This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
Plugging in to Java compilers
Edit - this appears to be a dupe of Plugging in to Java compilers
I would like to implement an AnnotationProcessor for use with the apt tool that will be invoked after compiling a class to bytecode, that can read and modify the bytecode.
The reason for doing this is that I want to translate annotated methods to another language and replace the java methods with stubs that invoke the translated versions.
However the AnnotationProcessorEnvironment interface only provides methods to generate new classes, not to read back a class file that was generated in a previous round.
The instrumentation API does something similar to what I want, but only at run-time. I am looking for a way to do this at compile time.
Related: Plugging in to Java compilers
I had a look when I wanted to do some manipulation in the compiler, but ended up using a post-processor.
You can manipulate the abstract syntax tree (AST) using the APT, but only with compiler-specific hacks. If you want a sample of how that's done, Project Lombok does it with the Sun javac and Eclipse compilers. At present, there doesn't seem to be a better method.
Related
This question already has answers here:
How does lombok work?
(4 answers)
Closed 4 years ago.
I can generate classes from scratch using annotationprocessor but I could not modify a class like lombok does. I've searched for the generated classes by lombok in android studio however I found nothing. then I checked the lombok overview via their website and also investigated it in forums but I've reached at end without anything. My question is so simple actually. How lombok unifies the generated code with mines while I use #Setter for instance. How can I develop a processor such as?
Seems like a duplicate of How does lombok work?, and I would flag to close as dupe but your bounty's preventing it.
In short, Lombok doesn't actually generate code at all. Instead, it uses unspecified and undocumented internal compiler implementation api calls to directly modify the program's abstract syntax tree between reading the source code and outputting compiled bytecode. It could break without warning or notice on updating to a new compiler version, but there's currently no other way.
Lombok is generating code during the compilation phase. Here is a tutorial for that http://hannesdorfmann.com/annotation-processing/annotationprocessing101 .
If you are all new to declaring your own annotations i strongly recommend getting started with runtime annotations. They are easier to understand and debug and your code "acts" during the runtime phase you are already familiar with. A short tutorial for that: http://docs.oracle.com/javase/1.5.0/docs/guide/language/annotations.html
`Platform`: Windows 7, MinGW, MSYS, Java 1.5
I have thrift 0.9.1 compiler (prebuilt for windows) and source. I use Ant to build java library.
I create one thrift idl and compile it with the compiler. No problem in generating code files.
I add these files in my project, and that add slf4j (downloaded from their site) and libthrift.
Most of the errors that I have previously (imports etc) are gone except for errors related to overriding methods.
So basically it complains like:
The method clear() of type Server must override a superclass method
and similarly for compareTo, write, read etc. In short it complains about all methods that are overridden. This is all thrift compiler generated code and I haven't changed anything.
Is there any incompatibility? I cannot really find any mention of that. I have tried removing and then adding the libraries, I have also tried cleaning, refreshing, validating the project but the errors are still there.
I have also tried to compile the code (thrift code) but MinGW is also a huge headache. It cannot find configure even though I have installed it. And if I run the msys console, it is able to configure but cannot make complaining about inttypes.h not present (which is not in msys include directory but is present in MinGW include directory.).
Any suggestion would be appreciated.
Are you using Java 5? With Java 5 #Override doesn't search for methods on interfaces, only on superclasses.
If you are using a Java 5 compiler trying using a more recent javac (preferably 7 or 8) and see of that works.
EDIT:
Not sure if this is in your version of Thrift, but in mine it looks like there is a flag called java5 that you an specify when generating code to specify that you want the generated code to be Java 5 compliant
java (Java):
beans: Members will be private, and setter methods will return void.
private-members: Members will be private, but setter methods will return 'this' like usual.
nocamel: Do not use CamelCase field accessors with beans.
fullcamel: Convert underscored_accessor_or_service_names to camelCase.
android: Generated structures are Parcelable.
android_legacy: Do not use java.io.IOException(throwable) (available for Android 2.3 and above).
java5: Generate Java 1.5 compliant code (includes android_legacy flag).
reuse-objects: Data objects will not be allocated, but existing instances will be used (read and write).
sorted_containers:
Use TreeSet/TreeMap instead of HashSet/HashMap as a implementation of set/map.
The question is already in the title and it's the less specific version of a question I asked earlier:
How do you write an annotation in java that adds a default constructor to a class?
There is a project which already does that: http://projectlombok.org/
Technically, you need to hook into the Java compiler. Compiling Java code is done in phases: First, all the sources are collected. Then the parser creates an AST. The code generation phase then turns the AST into byte code.
Annotation processors are run after the AST has been built but before the byte code is generated. By modifying the AST, you can modify the resulting class file.
This blog post contains the details: http://notatube.blogspot.com/2010/11/project-lombok-trick-explained.html
As I understand Lombok, it contains all the tools to write additional AST transformers which get triggered by custom annotations.
This is generally not supported, AFAIK.
Project Lombok does something like this, but it uses some hacks AFAIK.
https://blogs.oracle.com/darcy/entry/properties_via_annotation_processing
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I'm trying to evaluate different approaches to have some code in our Java project generated automatically from definitions in a domain-specific language while building the project. I have manually written a code generator or two in the past but I have no experience with existing code generation frameworks. We have not yet decided whether to use such a framework or build the generator by hand.
I need help with a conceptual problem; I would like to understand how a code generator can be built which allows the DSL to refer to existing (hand-written) Java classes, methods and fields. It should be possible to refer to classes that are in the same compilation unit (e.g. Maven project) as the generated Java classes. This means that those hand-written classes cannot be compiled before the code generator is run and the code generator would have to look at Java source files in addition to everything required to be on the classpath for compiling those classes.
How do existing frameworks handle such cases, if at all? Do they parse the Java source files themselves or do they re-use some machinery of the Java compiler?
I think this is the same problem that any (non-dynamic) non-Java language targeting the JVM faces, if it allows its own code to reference Java classes and vice-versa in the same compilation units. Maybe it is helpful to look at how those compilers work, unless they circumvent javac by also include a Java compiler themselves.
There are multiple reasons why the code generator needs access to the classes in the Java files of the same compilation unit:
I would like to provide semantics similar to those in Java where I can import <package>.* and then use the names of those classes without fully qualifying the name of each of them.
I would like to reject code in the DSL if it refers to symbols that don't exists or don't meet some required criteria.
There will be cases where I want to generate code that depends on the members of a class or the signatures of methods. An example would be to automatically generate a decorator or builder or implement an interface but where the base class or interface is not generated by the code generator.
I may want to use the type information of referenced symbols in the generate code. e.g. generating different code depending on the signature of a method.
Our project uses Maven. I'm interested in general approaches to solving these problems but information or examples that apply to Maven are greatly appreciated.
How can I extend Java with a DSL that allows the DSL compiler to refer to external Java elements (classes, methods, fields)?
Actually unclear what you're asking, furthermore this question is more theoretical, than programmic.
In any case, from my experience of own DSL implementation, there isn't any problem use java classloaders for dynamically access to new generated and compiled java classes. Also, if you are using maven, so all dependencies with production scope must be loaded in main classloader and be available to load them using reflection.
Here are some useful links:
http://www.javaworld.com/article/2077260/learn-java/the-basics-of-java-class-loaders.html
http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html
http://docs.oracle.com/javase/tutorial/reflect/
Do not parse java programs, use compiled classes instead. The referenced classes can be written in different languages, including other DSL - the only common denominator is class file format.
This cause a problem of circular dependency, when a java program refers to a DSL program and at the same time that DSL program refers back to java program. Possible solutions are:
do not analyse any other programs while converting DSL to Java. All possible errors would be reporting while compiling generated java code
redirect references to common interfaces, thus breaking dependency loop
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.