From e400e2da635dfa8d3c1f193b1a8e8925b8c73aee Mon Sep 17 00:00:00 2001 From: Andy Clement Date: Thu, 20 Feb 2014 09:13:14 -0800 Subject: [PATCH] Working Java8 build! - Split the AspectJ testcode out of the general testdata project. - Adjusted tests to handle that JDT produces different code to AspectJ. - Modified some tests to work better with javac compiled testdata (which is what happens when building on the command line or build machine) --- settings.gradle | 1 + springloaded/.classpath | 1 - springloaded/build.gradle | 2 + .../org/springsource/loaded/ClassRenamer.java | 5 ++- .../springsource/loaded/ExecutorBuilder.java | 9 +++++ .../springsource/loaded/TypeDiffComputer.java | 5 ++- .../springsource/loaded/support/Java8.java | 4 +- .../loaded/test/ExecutorBuilderTests.java | 22 +++++++++- .../loaded/test/FieldReloadingTests.java | 12 +++++- .../loaded/test/InnerClassesTests.java | 13 ++++-- .../loaded/test/SpringLoadedTests.java | 9 +---- .../loaded/test/TestInfrastructureTests.java | 2 +- testdata-aspectj/.classpath | 9 +++++ testdata-aspectj/.project | 18 +++++++++ testdata-aspectj/build.gradle | 40 +++++++++++++++++++ .../src/main/java/data/AnAspect.java | 0 .../src/main/java/data/AspectReceiver.java | 0 testdata/.classpath | 1 - testdata/.project | 3 +- testdata/build.gradle | 39 ++++-------------- 20 files changed, 140 insertions(+), 55 deletions(-) create mode 100644 testdata-aspectj/.classpath create mode 100644 testdata-aspectj/.project create mode 100644 testdata-aspectj/build.gradle rename {testdata => testdata-aspectj}/src/main/java/data/AnAspect.java (100%) rename {testdata => testdata-aspectj}/src/main/java/data/AspectReceiver.java (100%) diff --git a/settings.gradle b/settings.gradle index 5bafddb..047c69d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,7 @@ include "springloaded" include "testdata" include "testdata-java8" +include "testdata-aspectj" include "testdata-groovy" include "testdata-plugin" include "testdata-subloader" diff --git a/springloaded/.classpath b/springloaded/.classpath index c302a4b..720d087 100644 --- a/springloaded/.classpath +++ b/springloaded/.classpath @@ -6,6 +6,5 @@ - diff --git a/springloaded/build.gradle b/springloaded/build.gradle index d0f9fec..f733708 100644 --- a/springloaded/build.gradle +++ b/springloaded/build.gradle @@ -46,7 +46,9 @@ dependencies { testCompileOnly files("../testdata-groovy/groovy-all-1.8.6.jar") testCompileOnly project(':testdata') + testCompileOnly project(':testdata-aspectj') testCompileOnly project(':testdata-groovy') + testCompileOnly project(':testdata-java8') testCompileOnly project(':testdata-plugin') testCompileOnly project(':testdata-subloader') testCompileOnly project(':testdata-superloader') diff --git a/springloaded/src/main/java/org/springsource/loaded/ClassRenamer.java b/springloaded/src/main/java/org/springsource/loaded/ClassRenamer.java index bbf88a0..921524e 100644 --- a/springloaded/src/main/java/org/springsource/loaded/ClassRenamer.java +++ b/springloaded/src/main/java/org/springsource/loaded/ClassRenamer.java @@ -111,12 +111,15 @@ public class ClassRenamer { } return string; } - + @Override public MethodVisitor visitMethod(int flags, String name, String descriptor, String signature, String[] exceptions) { if (descriptor.indexOf(oldname) != -1) { descriptor = descriptor.replace(oldname, newname); } else { + if (descriptor.indexOf(oldname) != -1) { + descriptor = descriptor.replace(oldname, newname); + } for (String s : retargets.keySet()) { if (descriptor.indexOf(s) != -1) { descriptor = descriptor.replace(s, retargets.get(s)); diff --git a/springloaded/src/main/java/org/springsource/loaded/ExecutorBuilder.java b/springloaded/src/main/java/org/springsource/loaded/ExecutorBuilder.java index a7efa70..8f1de84 100644 --- a/springloaded/src/main/java/org/springsource/loaded/ExecutorBuilder.java +++ b/springloaded/src/main/java/org/springsource/loaded/ExecutorBuilder.java @@ -129,7 +129,16 @@ public class ExecutorBuilder { if (name.charAt(1) != 'c') { // regular constructor // want to create the ___init___ handler for this constructor + + // With the JDT compiler the inner class constructor gets an extra first parameter that is the type of + // containing class. But with javac the inner class constructor gets an extra first parameter that is of + // a special anonymous type (inner class of the containing class) + // For example: class Foo { class Bar {}} + // JDT: ctor in Bar is (Foo) {} + // JAVAC: ctor in Bar is (Foo$1) {} + descriptor = Utils.insertExtraParameter(classname, descriptor); + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC_STATIC, mInitializerName, descriptor, signature, exceptions); ConstructorCopier cc = new ConstructorCopier(mv, typeDescriptor, suffix, classname); diff --git a/springloaded/src/main/java/org/springsource/loaded/TypeDiffComputer.java b/springloaded/src/main/java/org/springsource/loaded/TypeDiffComputer.java index 0839438..345d5e3 100644 --- a/springloaded/src/main/java/org/springsource/loaded/TypeDiffComputer.java +++ b/springloaded/src/main/java/org/springsource/loaded/TypeDiffComputer.java @@ -625,7 +625,10 @@ public class TypeDiffComputer implements Opcodes { // td.setTypeVersionChange(oldClassNode.version, newClassNode.version); // } if (oldClassNode.access != newClassNode.access) { - td.setTypeAccessChange(oldClassNode.access, newClassNode.access); + // Is it only because of 0x20000 - that appears to represent Deprecated! + if ((oldClassNode.access & 0xffff) != (newClassNode.access&0xffff)) { + td.setTypeAccessChange(oldClassNode.access, newClassNode.access); + } } if (!oldClassNode.name.equals(newClassNode.name)) { td.setTypeNameChange(oldClassNode.name, newClassNode.name); diff --git a/springloaded/src/main/java/org/springsource/loaded/support/Java8.java b/springloaded/src/main/java/org/springsource/loaded/support/Java8.java index 57ab1f2..35e78f9 100644 --- a/springloaded/src/main/java/org/springsource/loaded/support/Java8.java +++ b/springloaded/src/main/java/org/springsource/loaded/support/Java8.java @@ -87,7 +87,7 @@ public class Java8 { * @param lookup * @return */ - public static Object emulateInvokeDynamic(Class executorClass, Handle handle, Object[] bsmArgs, Object lookup, String indyNameAndDescriptor, Object[] indyParams) { + public static Object emulateInvokeDynamic(Class executorClass, Handle handle, Object[] bsmArgs, Object lookup, String indyNameAndDescriptor, Object[] indyParams) { try { CallSite callsite = callLambdaMetaFactory(bsmArgs,lookup,indyNameAndDescriptor,executorClass); return callsite.dynamicInvoker().invokeWithArguments(indyParams); @@ -98,7 +98,7 @@ public class Java8 { // TODO [perf] How about a table of CallSites indexed by invokedynamic number through the class file. Computed on first reference but cleared on reload. Possibly extend this to all invoke types! // TODO [lambda] Need to handle altMetaFactory which is used when the lambdas are more 'complex' (e.g. Serializable) - public static CallSite callLambdaMetaFactory(Object[] bsmArgs, Object lookup, String indyNameAndDescriptor,Class executorClass) throws Exception { + public static CallSite callLambdaMetaFactory(Object[] bsmArgs, Object lookup, String indyNameAndDescriptor,Class executorClass) throws Exception { MethodHandles.Lookup caller = (MethodHandles.Lookup)lookup; ClassLoader callerLoader = caller.lookupClass().getClassLoader(); diff --git a/springloaded/src/test/java/org/springsource/loaded/test/ExecutorBuilderTests.java b/springloaded/src/test/java/org/springsource/loaded/test/ExecutorBuilderTests.java index def4722..497864e 100644 --- a/springloaded/src/test/java/org/springsource/loaded/test/ExecutorBuilderTests.java +++ b/springloaded/src/test/java/org/springsource/loaded/test/ExecutorBuilderTests.java @@ -17,6 +17,7 @@ package org.springsource.loaded.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import java.lang.annotation.Annotation; import java.lang.reflect.Method; @@ -262,7 +263,10 @@ public class ExecutorBuilderTests extends SpringLoadedTests { s.add(anno.toString()); } Assert.assertTrue(s.remove("@common.Marker()")); - Assert.assertTrue(s.remove("@common.Anno(someValue=37, longValue=2, id=abc)")); + // Allow for alternate toString() variant + if (!s.remove("@common.Anno(someValue=37, longValue=2, id=abc)")) { + Assert.assertTrue(s.remove("@common.Anno(longValue=2, someValue=37, id=abc)")); + } Assert.assertEquals(0, s.size()); } @@ -296,7 +300,21 @@ public class ExecutorBuilderTests extends SpringLoadedTests { checkAnnotations(rtype.getLatestExecutorBytes(), "m2(Lexecutor/I;)V", "@common.Marker()", "@common.Anno(id=abc)"); Method m = rtype.getLatestExecutorClass().getDeclaredMethod("m2", rtype.getClazz()); assertEquals("@common.Marker()", m.getAnnotations()[0].toString()); - assertEquals("@common.Anno(someValue=37, longValue=2, id=abc)", printAnnotation(m.getAnnotations()[1])); + assertIsOneOfThese(printAnnotation(m.getAnnotations()[1]),"@common.Anno(someValue=37, longValue=2, id=abc)", "@common.Anno(longValue=2, someValue=37, id=abc)"); + } + + /** + * Check the actual value is one of the possible options. + */ + private void assertIsOneOfThese(String actual, String... possibleValues) { + StringBuilder buf = new StringBuilder(); + for (int i=0;i + + + + + + + + diff --git a/testdata-aspectj/.project b/testdata-aspectj/.project new file mode 100644 index 0000000..9941b1e --- /dev/null +++ b/testdata-aspectj/.project @@ -0,0 +1,18 @@ + + + testdata-aspectj + + + + + + org.eclipse.ajdt.core.ajbuilder + + + + + + org.eclipse.ajdt.ui.ajnature + org.eclipse.jdt.core.javanature + + diff --git a/testdata-aspectj/build.gradle b/testdata-aspectj/build.gradle new file mode 100644 index 0000000..fa94bf2 --- /dev/null +++ b/testdata-aspectj/build.gradle @@ -0,0 +1,40 @@ +def aspectjVersion = "1.8.0.M1" + +configurations { + aspects + ajInpath +} + +dependencies { + tools "org.aspectj:aspectjtools:$aspectjVersion" + compile "org.aspectj:aspectjrt:$aspectjVersion" + compile("cglib:cglib:2.2.2") { exclude group: 'asm' } // cglib 2.2.2 depends on asm 3.3 + compile 'org.ow2.asm:asm:5.0_BETA' + compile 'org.ow2.asm:asm-tree:5.0_BETA' + compile files("code.jar") +} + +compileJava.deleteAllActions() + +task aspectJ(dependsOn: JavaPlugin.PROCESS_RESOURCES_TASK_NAME) { + dependsOn configurations.tools.getTaskDependencyFromProjectDependency(true, "compileJava") + def srcDirs = sourceSets.main.java.srcDirs + srcDirs.each { inputs.dir it } + def destDir = sourceSets.main.output.classesDir + outputs.dir destDir + doLast { + ant.taskdef(resource: "org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: configurations.tools.asPath) + + ant.iajc(source:sourceCompatibility, target:targetCompatibility, destDir: destDir.absolutePath, maxmem:"512m", fork:"true", + aspectPath: configurations.aspects.asPath, inpath:configurations.ajInpath.asPath, sourceRootCopyFilter:"**/.svn/*,**/*.java",classpath:configurations.compile.asPath ){ + sourceroots { + srcDirs.each { + if (it.exists()) pathelement location: it.absolutePath + } + } + } + } +} + +compileJava.dependsOn aspectJ + diff --git a/testdata/src/main/java/data/AnAspect.java b/testdata-aspectj/src/main/java/data/AnAspect.java similarity index 100% rename from testdata/src/main/java/data/AnAspect.java rename to testdata-aspectj/src/main/java/data/AnAspect.java diff --git a/testdata/src/main/java/data/AspectReceiver.java b/testdata-aspectj/src/main/java/data/AspectReceiver.java similarity index 100% rename from testdata/src/main/java/data/AspectReceiver.java rename to testdata-aspectj/src/main/java/data/AspectReceiver.java diff --git a/testdata/.classpath b/testdata/.classpath index 92b173c..0fb1905 100644 --- a/testdata/.classpath +++ b/testdata/.classpath @@ -1,7 +1,6 @@ - diff --git a/testdata/.project b/testdata/.project index e9d6a17..def9b8b 100644 --- a/testdata/.project +++ b/testdata/.project @@ -6,13 +6,12 @@ - org.eclipse.ajdt.core.ajbuilder + org.eclipse.jdt.core.javabuilder - org.eclipse.ajdt.ui.ajnature org.eclipse.jdt.core.javanature diff --git a/testdata/build.gradle b/testdata/build.gradle index fa94bf2..1c4ec5b 100644 --- a/testdata/build.gradle +++ b/testdata/build.gradle @@ -1,40 +1,17 @@ -def aspectjVersion = "1.8.0.M1" - -configurations { - aspects - ajInpath -} - dependencies { +/* tools "org.aspectj:aspectjtools:$aspectjVersion" compile "org.aspectj:aspectjrt:$aspectjVersion" +*/ compile("cglib:cglib:2.2.2") { exclude group: 'asm' } // cglib 2.2.2 depends on asm 3.3 compile 'org.ow2.asm:asm:5.0_BETA' compile 'org.ow2.asm:asm-tree:5.0_BETA' compile files("code.jar") } - -compileJava.deleteAllActions() - -task aspectJ(dependsOn: JavaPlugin.PROCESS_RESOURCES_TASK_NAME) { - dependsOn configurations.tools.getTaskDependencyFromProjectDependency(true, "compileJava") - def srcDirs = sourceSets.main.java.srcDirs - srcDirs.each { inputs.dir it } - def destDir = sourceSets.main.output.classesDir - outputs.dir destDir - doLast { - ant.taskdef(resource: "org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: configurations.tools.asPath) - - ant.iajc(source:sourceCompatibility, target:targetCompatibility, destDir: destDir.absolutePath, maxmem:"512m", fork:"true", - aspectPath: configurations.aspects.asPath, inpath:configurations.ajInpath.asPath, sourceRootCopyFilter:"**/.svn/*,**/*.java",classpath:configurations.compile.asPath ){ - sourceroots { - srcDirs.each { - if (it.exists()) pathelement location: it.absolutePath - } - } - } - } +sourceSets { + main { + java { + srcDir 'src' + } + } } - -compileJava.dependsOn aspectJ -