From a946f898d667269fe0644624acce236147c2ed72 Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Wed, 31 Aug 2016 20:17:17 +0200 Subject: [PATCH] handled fatal analysis failure due to JVM bug. When analysis failes an explanation is printed to console, with stacktrace and a link to the github issue #68 The Tests that triggered the failure are included on JDK versions with the problem. --- .../degraph/analysis/asm/Analyzer.scala | 21 +++++++++++++--- .../degraph/jdk8tests/AnalyzerTest.scala | 25 +++++++++++++++++-- releaseNotes.md | 7 ++++++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/de/schauderhaft/degraph/analysis/asm/Analyzer.scala b/core/src/main/scala/de/schauderhaft/degraph/analysis/asm/Analyzer.scala index e19d7d4..ad8460f 100644 --- a/core/src/main/scala/de/schauderhaft/degraph/analysis/asm/Analyzer.scala +++ b/core/src/main/scala/de/schauderhaft/degraph/analysis/asm/Analyzer.scala @@ -12,10 +12,25 @@ object Analyzer extends AnalyzerLike { def analyze(sourceFolder: String, categorizer: (Node) => Node, filter: (Node) => Boolean): Graph = { val g = new Graph(categorizer, filter, new NoSelfReference(categorizer)) - def analyze(f : File)={ + def readStream(reader: ClassReader, name: String): Unit = { + try { + reader.accept(new GraphBuildingClassVisitor(g), 0) + } catch { + case e: Exception => + println("Something went wrong when analyzing " + name) + println("For this class some or all dependencies will be missing.") + println("This is most likely due to a bug in the JDK (no, really) or ASM,") + println("see https://github.com/schauder/degraph/issues/68 for details.") + println("If the stacktrace below does not match what you see in the issue above,") + println("please create a new issue and include the stacktrace.") + e.printStackTrace() + } + } + + def analyze(f: File) = { if (f.getName.endsWith(".class")) { val reader = new ClassReader(new BufferedInputStream(new FileInputStream(f))) - reader.accept(new GraphBuildingClassVisitor(g), 0) + readStream(reader, f.getName) } else { val zipFile = new ZipFile(f) val entries = zipFile.entries() @@ -23,7 +38,7 @@ object Analyzer extends AnalyzerLike { val e = entries.nextElement() if (e.getName.endsWith(".class")) { val reader = new ClassReader(zipFile.getInputStream(e)) - reader.accept(new GraphBuildingClassVisitor(g), 0) + readStream(reader, e.getName) } } } diff --git a/jdk8tests/src/test/scala/de/schauderhaft/degraph/jdk8tests/AnalyzerTest.scala b/jdk8tests/src/test/scala/de/schauderhaft/degraph/jdk8tests/AnalyzerTest.scala index 0d2e885..835e843 100644 --- a/jdk8tests/src/test/scala/de/schauderhaft/degraph/jdk8tests/AnalyzerTest.scala +++ b/jdk8tests/src/test/scala/de/schauderhaft/degraph/jdk8tests/AnalyzerTest.scala @@ -13,9 +13,21 @@ import org.scalatest.Matchers._ @RunWith(classOf[JUnitRunner]) class AnalyzerTest extends FunSuite { + + private val testClassFolder = System.getProperty("java.class.path") - private val graphs = Map( - "asm" -> asm.Analyzer.analyze(testClassFolder, x => x, _ => true)) + + private def isJavaVersionWithBrokenTypeAnnotations: Boolean = { + val javaVersionString = System.getProperty("java.version") + javaVersionString > "1.8.0_31" + } + + private val graphs = + if (isJavaVersionWithBrokenTypeAnnotations) + Map() + else + Map( + "asm" -> asm.Analyzer.analyze(testClassFolder, x => x, _ => true)) for ((label, graph) <- graphs) { @@ -58,6 +70,7 @@ class AnalyzerTest extends FunSuite { graph should connect("de.schauderhaft.degraph.jdk8tests.ClassWithTypeAnnotations" -> "de.schauderhaft.degraph.jdk8tests.TypeAnno8") } + def connect(connection: (String, String)) = { val (from, to) = connection new Matcher[Graph] { @@ -84,4 +97,12 @@ class AnalyzerTest extends FunSuite { } } } + + // if annotations are broken, at least verify that broken stuff doesn't completely kill the analysis + if (isJavaVersionWithBrokenTypeAnnotations) { + test("Analysis does not explode") { + asm.Analyzer.analyze(testClassFolder, x => x, _ => true) + } + } + } \ No newline at end of file diff --git a/releaseNotes.md b/releaseNotes.md index a562bf6..b96fe7e 100644 --- a/releaseNotes.md +++ b/releaseNotes.md @@ -11,6 +11,9 @@ - `printTo` in the ConstraintBuilder now always prints the analysis results. If you want the old behaviour back, use `printOnFailure` +- `Check` and `JCheck` got a new method `customClasspath`. You can use it in order to provide a classpath explicitly + instead of using the classpath used by the current JVM. + - ConstraintBuilder got a new method `filterClasspath(pattern: String): ConstraintBuilder` for limiting the classpath to elements matching the pattern. This should be useful, if you want to analyze some, but not all jar-files. @@ -21,6 +24,10 @@ - minor performance improvements +### Known Issues + +- Due to a JDK or ASM bug analysis of class files which contain Type-Annotations might fail. Dependencies of such classes +will be incomplete. A message saying so will be displayed. See ## 0.1.3