Can JVM bytecode be manipulated at compile time? - java

Is it possible to use a bytecode manipulation library like ASM at compile time?
Specifically, I'd like to use Java's annotation processing API to implement boilerplate-heavy methods on annotated classes. Implementing an annotation processor is straightforward enough, but it seems like the .class files don't yet exist when the Processor is run. Is there another way?

You might be interested in Javassist ( http://www.jboss.org/javassist ) which can enhance and save classes as a post-compilation step.
This article describes how to save enhanced classes : https://dzone.com/articles/implementing-build-time
in particular, once you have altered a class, you can do something like this:
compiledClass.writeFile("/tmp/modifiedClassesFolder");

It should be possible since the following project is doing it: Project Lombok
Also:
Java 8 will bring a new mechanism that allows you to write plug-ins for the Java compiler (javac). A compiler plug-in lets you add new phases to javac without making changes to its code base. New behavior can be encapsulated in a plug-in and distributed for other people to use. For example, javac plug-ins could be used to do the following:
• Add extra compile-time checks
• Add code transformations
• Perform customized analysis of source code

You should use CGLib instead. With CGLib you can add proxies with method interceptors and have the interceptor implement your boilerplate code. Another option is to look at Javassist. With Javassist you literally create a new subclass using actual text (in strings) and have javassist compile it into byte-code.

Related

Accessing the generated code with bytecode manipulation

I'm currently working on a Java library and I want to add some public static final String fields using bytecode manipulation which just hold some info about an entity. e.g.Customer.TABLE_NAME. I want to be able to access these fields before compile time while writing code something like what lombok allows you to do. Obviously those lombok generated methods don't actually exist before the code has been compiled but we can still see and use them without any problem. How can I achieve something like this?
Have you looked into AspectJ inter-type declarations (ITD)? They do exactly what you need. Of course, you can also use more low-level tools like Byte Buddy and Javassist or really low level ones like ASM in order to achieve the same.
Most of those tools can be used during the build process, transforming your class files, or alternatively as Java agents, i.e. they perform the byte code transformation during class-loading. It depends on your use case. If I understand correctly, your use case is that other developers using your classes can see the additional fields or methods you create dynamically. In that case, you would add them during build time and they would be part of the byte code in your library or module.

How can I access a java compile time parameter at runtime?

We are migrating a system written in C to Java and must retain existing processes (no debate). We currently "embed" compile-time information into the C application using the C preprocessor, for example:
cc -o xxx.o -DCOMP_ARG='"compile time arg"' xxx.c
The xxx.c file can then use "COMP_ARG" and its value will be embedded in the code and we have little worry about it being changed inadvertently.
We realize Java likes to use properties files, however, our requirements are such that some information ** ** be embedded in the code, so properties files are not an option - these certain values cannot be specified at runtime. To illustrate the point, such data could be a date-stamp of when the file was compiled, but the exact data is irrelevant to the question.
We are looking for a way to specify at compile time various values that are available to the Java code. We are quite aware that Java does not have a pre-processor as does C, so the mechanism would be different.
Our current solution is using a code generation step (Maven), which does work, however, Eclipse is wreaking havoc trying to deal with the source files so that we had turn off "Build Automatically". We really want to find a more robust solution.
We appreciate any help, thanks.
The xxx.c file can then use "COMP_ARG" and its value will be embedded
in the code and we have little worry about it being changed
inadvertently.
...our requirements are such that some information be embedded in the
code....
We are looking for a way to specify at compile time various values
that are available to the Java code. We are quite aware that Java does
not have a pre-processor as does C, so the mechanism would be
different.
It seems that the best way to solve this problem would be to make use of annotations in your code.
In Java, annotations are a kind of interface declaration, but they do not enforce a behavioral contract with an implementing class. Rather, they are meant to define a contract with some external framework, preprocessor, or with the compiler itself. Annotations are used extensively in Java EE 5.0 (and later) to specify configuration and behavior to the framework within which the developer's code runs. Annotations are also used extensively by the JavaDoc documentation processor. Here, the annotations in the doc comments allow you to specify and format the information which you intend to appear in the documentation when the JavaDoc processor runs.
Annotations can be defined to be accessible at runtime. In such a case, the primary mechanism for accessing annotations is the Java Reflection facility. For example, annotations with a retention policy of RUNTIME and defined on a class, can be accessed through that class's corresponding Class object:
Class myCls = MyClass.class; // the "class literal" for MyClass
Annotation[] annotations = myCls.getDeclaredAnnotations();
Annotations can include arguments for parameters to allow for more flexibility in configuration. The use of annotations is most convenient when the code itself can be so annotated.
A quick tutorial on how annotations are defined and used in Java is available here: https://docs.oracle.com/javase/tutorial/java/annotations/
I'm going to post my own answer which seems to be "Can't be done" - what can't be done, apparently, is provide at compile time to Java, a set of parameters that gets passed to the program at execution time. The solution appears to be to continue with what I am doing which is to update a Java source file with the compile-time data and figure out how to coax Eclipse to stop over-writing the files.
Thanks to everyone who commented.

What is the easiest way to generate an efficient implementation of a Java interface at runtime?

Starting with one Java base-interface, I want others to be able to extend this interface, directly or indirectly, and add bean properties and behavior to it, as a plugin system.
Then, at runtime, on the user computer, I would find all those interfaces and generate a single big class that implements them all. The fields required for the bean properties would be generated automatically, while the behavior defined in the interfaces would be implemented as static methods of an helper class (created by the plugin developers) that take the appropriate interface as first parameter, so the implementation of the interface method would delegate to a static method, passing "this" as first parameter.
This is similar to how Scala implements it's traits.
I see 3 ways of doing this:
Use Java's dynamic proxies, which are based on reflection.
Generate the source-code as a string, and compile it at runtime.
Use some bytecode manipulation library to generate the class at runtime.
Option 1 is the easiest, but least efficient, and therefore I want a better solution. Option 2 would give me an efficient implementation, but is rather ugly.
While I have seen several libraries that can do option 3, they all seem to require that I learn Java's assembler language first, which I take as a very time-consuming activity, with little benefits in the end..
Since I don't want to learn any assembler, JVM or otherwise, is option 2 my best bet, or are there libraries that can generate dynamic proxies without me using JVM assembler?
Have a look at Javassist. With it, you can make runtime changes to classes using a straight-forward API. You don't need to know about java "black magic" to use it.
When using BCEL you don't have to know java assembler. Lok at this proxy.

Is it possible to use Java annotations, to achieve a similar functionality as a preprocessor

Is it possible to create a preprocessor like functionality that is available in C and provided by Antenna. Can we use the APT tool to achieve this functionality? Are there any articles or links on similar topics?
Annotations are not meant as a tool to transform code; they just add metadata to code. You can't use annotations for conditional compilation, for example.
As Sun's tutorial on annotations says:
Annotations provide data about a program that is not part of the program itself. They have no direct effect on the operation of the code they annotate.
Wikipedia says:
When Java source code is compiled, annotations can be processed by compiler plug-ins called annotation processors. Processors can produce informational messages or create additional Java source files or resources, which in turn may be compiled and processed, but processors cannot modify the annotated code itself.
So an annotation processor plug-in is not going to be able to give you all of the functionality that the C preprocessor has.
You can perform compile-time tasks using the annotation processing framework. It's not as powerful as a preprocessor, since you can't do things like:
#RunOnlyOn(OS.Mac) public void someMethod() { ... }
Some good use cases for annotation processors are:
creating mapping files from annotated classes, e.g. create a hibernate mapping file;
creating indexes of classes which have certain annotation, e.g. create testng xml files from a source folder of test classes;
enforce compile-time constraints not usually available, e.g. having a no-arg constructor.
Please note that as of Java 6 APT is no longer needed, since all properly declared annotation processors take part in the compilation.

Plugging in to Java compilers

I have a post-compilation step that manipulates the Java bytecode of generated classes. I'd like to make life as painless as possible for library consumers, so I'm looking at ways I can make this process automatic and (if possible) compiler agnostic.
The Annotation Processing API provides many of the desired features (automatic service discovery; supported by Eclipse). Unfortunately, this is aimed at code generators and doesn't support manipulation of existing artefacts:
The initial inputs to the tool are
considered to be created by the zeroth
round; therefore, attempting to create
a source or class file corresponding
to one of those inputs will result in
a FilerException.
The Decorator pattern recommended by the API is not an option.
I can see how to perform the step with a runtime agent/instrumentation, but this is a worse option than a manual build step as it would require anyone even peripherally touched by the API to configure their JVMs in a non-obvious manner.
Is there a way to plug into or wrap the compiler tool as invoked by javac? Has anyone successfully subverted the annotation processors to manipulate bytecode, no matter what the doc says?
The Groovy compiler is the only bytecode compiler which allows to hook into the compilation process (example: Generate bytecode to support the Singleton pattern)
The Annotation Processing API is not meant to change the code. As you have already found out, all you can do is install a classloader, examine the bytecode at runtime and manipulate it. It's braindead but it works. This follows the general "we're afraid that a developer could try something stupid" theme which you will find throughout Java. There is no way to extend javac. The relevant classes are either private, final or will change with the next version of Java.
Another option is to write annotated Java, for example you write a class "ExampleTpl.java". Then, you use a precompiler which expands the annotations in that file to get "Example.java". In the rest of the code, you use Example and ignore ExampleTpl.
For Eclipse, there is a bug report to automate this step. I'm not aware of any other work in this area.
It can be done.
Take a look at my blog post Roman Numerals, in our Java where an annotation processor is used to rewrite code. Limitation being that it works with Sun's javac only.

Categories