Retro-actively add Java annotations to methods? - java

Is there a way to modify .class files in order to add Java annotations to certain methods? Basically I want to traverse methods of each class file in a jar file and annotate certain ones. Note that this is not at run-time while using the jar file. Rather, after I'm done I want to have modified class files with the annotations.
I do have access to the source code, so if there's an automatic source code modifier, that would work as well...
I'm assuming I'll need a tool such as Javassist or ASM. If so, which one should I use and how would I go about it?

Actually, this is a classic use case for AspectJ:
declare #method : public * BankAccount+.*(..) : #Secured(role="supervisor")
While I will grant you that direct byte code manipulation is more powerful, AspectJ is much more user-friendly, and it immediately gives you compiler warnings when you are doing something wrong.
Also, if you use Load Time Weaving, you can leave the original library jar unchanged, because the weaving happens at class-load time.
Reference:
Declare Annotation
AspectJ in Action (book)

Googling for an hour or so turned this article up which seems to completely answer my question: use ASM. To write class files using the changed bytecode, use ClassWriter.
Well, time to get to work then, I guess. :)

Related

Can I create custom Annotation to initialize static variables using other field names? [duplicate]

I may be just looking in the wrong direction but I find the JSE documentation on annotation processing very ... sparse. I want to write an annotation processor which processes annotated String fields and local variables to substitute them with a computed String expression. This should not be too complicated but I'm pretty lost in the Javadoc for javax.annotation.processing.
EDIT: I need to process annotations at compile time because I want to modify the generated code. It should replace annotated constant String expressions with a computed String expression.
This can not be done with a compile time annotation processor. Compile time time annotation processors can only generate new files (and classes) they can not modify existing classes. You can do reflection at runtime but strictly speaking you that is not called annotation processing. Also you won't have access to local variables.
If you're looking on how to write a compile time annotation processor check out https://github.com/pellaton/spring-configuration-validation-processor
Two tools that do this are Project Lombok and DuctileJ. Both of these tools existed at the time the question was originally asked; additional tools now surely exist.
The key idea is to write an annotation processor that traverses and modifies the program's AST (abstract syntax tree) during compilation, before code generation. The compiler won't change the source code on disk, but the generated .class file will reflect the changes that your annotation processor makes.
You may be able to adapt one of these tools to suit your needs, or you could implement your own tool inspired by their implementation techniques.
Compile-time processing has two advantages over class-file processing. One is that the compiler usually has more information than is available from compiled code. Another is that everything happens in one step, during compilation, rather than requiring the developer to run a separate tool to rewrite the .class files after compilation.
Check
Javassist http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
ASM http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
Byteman (for runtime) http://www.jboss.org/byteman/

How to write a Java annotation processor?

I may be just looking in the wrong direction but I find the JSE documentation on annotation processing very ... sparse. I want to write an annotation processor which processes annotated String fields and local variables to substitute them with a computed String expression. This should not be too complicated but I'm pretty lost in the Javadoc for javax.annotation.processing.
EDIT: I need to process annotations at compile time because I want to modify the generated code. It should replace annotated constant String expressions with a computed String expression.
This can not be done with a compile time annotation processor. Compile time time annotation processors can only generate new files (and classes) they can not modify existing classes. You can do reflection at runtime but strictly speaking you that is not called annotation processing. Also you won't have access to local variables.
If you're looking on how to write a compile time annotation processor check out https://github.com/pellaton/spring-configuration-validation-processor
Two tools that do this are Project Lombok and DuctileJ. Both of these tools existed at the time the question was originally asked; additional tools now surely exist.
The key idea is to write an annotation processor that traverses and modifies the program's AST (abstract syntax tree) during compilation, before code generation. The compiler won't change the source code on disk, but the generated .class file will reflect the changes that your annotation processor makes.
You may be able to adapt one of these tools to suit your needs, or you could implement your own tool inspired by their implementation techniques.
Compile-time processing has two advantages over class-file processing. One is that the compiler usually has more information than is available from compiled code. Another is that everything happens in one step, during compilation, rather than requiring the developer to run a separate tool to rewrite the .class files after compilation.
Check
Javassist http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
ASM http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
Byteman (for runtime) http://www.jboss.org/byteman/

changing java's .class file without recompiling

is there any way to do the following. so i have a project.jar file, inside it i need to modify the string passed to some method of let's say classA.class. for example, let's say this classA.class has a method named
change(String a, String b)
what i all want is to do the following as the first line of the code inside this method as follows:
a = a + "hi";
i want to modify the .class file directly, without needing to recompile everything again. then after that i would update the jar file with the new class file. is it possible? if yes can anyone show an example? thanks a lot in advance!
Yes it's possible with byte code editors. Commonly you can use aspectj together with compile time weaving to modify a class file. You can also use libraries such as BCEL, cglib etc.
However, for the use case you are describing you typically don't need to edit a class file. You can just wrap your object in a proxy or modify it's behaviour using AoP style of programming (as supported by e.g., aspectj)
There are tools to manipulate byte code dynamically, such as ASM: http://asm.ow2.org/
another way could be instrumentation. when you are loading the class you could manipulate the bytecode before using it. there are some good libraries for this, for example javassist from jboss. i think aspectJ works similar.
but why you want to change the bytecode, compile it and add it to a jar file again? are you needing the source code? perhaps you could use some de-compiler to get the source code, if you need it. a good tool is http://java.decompiler.free.fr/.

Java: Locate reflection code usage

We have huge codebase and some classes are often used via reflection all over the code. We can safely remove classes and compiler is happy, but some of them are used dynamically using reflection so I can't locate them otherwise than searching strings ...
Is there some reflection explorer for Java code?
No simple tool to do this. However you can use code coverage instead. What this does is give you a report of all the line of code executed. This can be even more useful in either improving test code or removing dead code.
Reflections is by definition very dynamic and you have to run the right code to see what it would do. i.e. you have to have reasonable tests. You can add logging to everything Reflection does if you can access this code, or perhaps you can use instrumentation of these libraries (or change them directly)
I suggest, using appropriately licensed source for your JRE, modifying the reflection classes to log when classes are used by reflection (use a map/WeakHashMap to ignore duplicates). Your modified system classes can replace those in rt.jar with -Xbootclasspath/p: on the command line (on Oracle "Sun" JRE, others will presumably have something similar). Run your program and tests and see what comes up.
(Possibly you might have to hack around issues with class loading order in the system classes.)
I doubt any such utility is readily available, but I could be wrong.
This is quite complex, considering that dynamically loaded classes (via reflection) can themselves load other classes dynamically and that the names of loaded classes may come from variables or some runtime input.
Your codebase probably does neither of these. If this a one time effort searching strings might be a good option. Or you look for calls to reflection methods.
As the other posters have mentioned, this cannot be done with static analysis due to the dynamic nature of Reflection. If you are using Eclipse, you might find this coverage tool to be useful, and it's very easy to work with. It's called EclEmma

Compile Java class with missing code parts

I'm looking for some ideas on how to compile Java code with some other pieces of code missing (method calls). I am fully aware that javac will not allow you to compile Java files if cannot find all dependencies. But maybe there is some way how to bypass it, something like force compile.
My bytecode knowledge is not so good but I think some method invoke is just full package definition of class and method name with parameters. So if compiler just puts this data to class file and assume in running process dependency will be available (if not simple NoSuchMethodExp).
Only workaround so far I found is to create empty missing class files with empty methods to "cheat" compiler. Works perfectly but there should be easier way :)
Any ideas?
Use Interfaces.
Create the interfaces that have the methods you need. At runtime, inject (Spring, Guice, etc.) or generate (cglib ...) classes that implement the interface.
If you're modifying a jar, you can extract the class files you are not modifying to another directory and include that in the classpath. That way they will be available to the compiler.
Bad luck! Probably all you can do is to create mock objects for missing parts of code just to compile your code (empty methods, so the compiler can find it).
Another question - if you miss some classes, how will you execute that code?
UPDATED according to information provided:
Well, there is another option to modify classes in jar, you can use AOP, and to make it done read about AspectJ - actually for me this is the easiest option (typically you need to spend time mocking objects, writing empty methods, so I would contribute that time to study new technology, which will help you many times ;)
And btw the easiest way to implement it, if you use Eclipse, is:
install AJDT
create aspect project
create aspect which modifies code (depending on what you need to change)
add jar file you want to modify
immediately get modified code in
another already packed jar file
Sounds magically :)
In this case you don't need any dependencies in classpath, except for libraries which are needed for new code you add!
Methods aren't dependencies. They are part of the class definition. The only places the java runtime looks for method definitions is in the class def that was compiled at compile time and in its parent classes. If you're problem is that a super class is incomplete, I don't think I can help you.
If not, you could define some of these methods as abstract and than have a child class implement them.
What kind of code is missing? Normally this happens if you refer to libraries your compiler can't find. Maybe you simply need to extend the classpath the compiler is searching for classes.
If you really refer to code that is not available yet you need to implement at least those methods you refer to. But that sounds strange... maybe you can clear things up.

Categories

Resources