I\'m aware that the runtime features of Java 7 are not available with Java 6 but since no new byte code has been added the new byte code invokedynamic
is
It's probably some work but try this:
Add Eclipse's Java Compiler to your classpath. It's in the plugin org.eclipse.jdt.core
(search for org.eclipse.jdt.core_*.jar
in the folder plugins
).
This JAR contains the compiler and the parser. You can invoke the parser yourself and then use the ASTVisitor to traverse the parse tree.
You can then modify the tree and create the new source code from this that you can compile as usual.
It might even be possible to "preprocess" the AST tree before the compiler generates byte code; this would save you the "write sources back to disk and compile them from there" step.
You are right that invokedynamic instruction is not used by Java, however there are some other related changes which can be used in Java. Invokedynamic relies on a new 'Dynamic Linkage Mechanism - Method Handles' for which there are some changes to the invokevirtual instruction as well. You can find more details in this article in the section 'A New Dynamic Linkage Mechanism: Method Handles'.
Method handles also provide a faster alternative to reflection, and hence are useful in Java. Converting code using method handles to Java 6 would not be possible as the feature relies Java 7 VM.
As far as I know, there is no solution for this problem at the moment. The best bet would be to extend retrotranslator to deal with Java 1.7 constructs. The diamond operator should be very easy, since it requires no bytecode modification at all.
Your statement "no new byte code has been added" is not correct: There is a new invokedynamic byte code and more importantly there are several cases where the generated bytecode will not be valid for 1.6 JREs, so retrotranslator would have to fix that.
Mark a .class file output by Java 7 javac with version 1.6.0 (i.e. 0x32)
printf "\x00\x00\x00\x32" |dd of=Example.class seek=4 bs=1 count=4 conv=notrunc
(according to http://en.wikipedia.org/wiki/Java_class_file#General_layout)
If you put that (using $1 for the filename) into j6patch
you can do all class files with:
find . -name \*.class |xargs -I {} ./j6patch {}
I used this on a large (~4.8 MB jar) code base and even used RetroTranslator
on the java 6 jar so Java 7 language features can be used on an app that runs in Java 5. Also the Java 7 compiler (javac
) does lots of extra optimizations (e.g. escape analysis) that very noticeably improves performance.
Using RetroTranslator
with -verify -target 1.5
and JRE 1.6 runtime jars allows to verify that no Java 7 runtime features are used.