Sending events via code generation with annotations - java

I have a bunch of methods that must send events when called, i.e. something like this
public void someMethod(){
sendEvent("someMethod was called");
// the method does something
}
public void someOtherMethod(){
sendEvent("someOtherMethod was called");
// the method does something
}
I would like to avoid the sendEvent method call by doing something like
#SendsEvent("someMethod was called")
public void someMethod(){
// do something
}
I have heard of annotation processing as a way of generating code at build time. Would this be possible to do? if so could you point me in the right direction (tutorial or docs).
PS: I have searched on the net for tutorials on annotation processing by they all seem to focus on using the reflections API for runtime annotation processing. This is NOT what I want.

I think for this feature, annotation processing is not worth the additional effort and complexity. Annotation processors are often used for code generation but it doesn't seems you need to generate any dynamic code for this use case. You would have to:
Learn the annotation processor and mirror apis (similar to the reflection api but more complex)
Integrate the processor in your build system
Let the processor generate classes that monitor the annotated methods.
How to do this? There are many ways. You could generate a class that extends your class, adds the event call and then executes the original implementation. Other solution probably involve run-time handling of everything and could be done using reflections
Find a way to load the generated classes instead of you own implementations (DI or something)
Unless you actually really need to generate code for this and do everything at compile time, you should probably just do everything at runtime when the application starts. Checking for annotations once in the beginning using reflections should not impact performance in any way. Use a Proxy to intercept method invocations and add your event calls.

Related

How to implement build specific annotation retention in Java

I have an annotation that I currently use only for internal build and documentation purposes. It does not offer any value at runtime, which is why I chose #Retention(SOURCE):
#Retention(SOURCE)
public #interface X
However, in order to validate its proper usage, I would like to implement a unit test that navigates the entire API to check whether the annotation is applied everywhere it should be applied to. That unit test would be quite easy to implement by using ordinary Java reflection APIs, but I cannot do that as the tests can't reflect over the annotation, given its #Retention(SOURCE).
In order to use reflection in tests, I would have to change it to #Retention(RUNTIME), which I would like to avoid due to the overhead in byte code at run time.
Workarounds I'm aware of:
There are workarounds as always. I'm aware of these:
We could use an annotation processor that fails the build instead of running unit tests. This is feasible but less optimal, as the tests are quite sophisticated and much more difficult to implement using annotation processors rather than unit tests using both junit APIs and the much more convenient reflection API. I would like to use this workaround as a last resort only.
We could change the #Retention to RUNTIME in our sources, build the sources with these additional tests, then pre-process the API to remove the retention again, and then build the API a second time for production usage. This is an annoying workaround as it would complicate and slow down the build.
Question:
Is there a more convenient way to retain the annotation at runtime only for tests, but not in the actually built jar file, using Maven?
Here's a hybrid approach that might work.
Write an annotation processor that doesn't implement the full testing that you want to do, but instead merely records in a sidecar file where the annotations occurred. If you're annotating classes, methods, and fields, the location can be recorded fairly straightforwardly using the package-qualified class name plus a method or field descriptor. (This may be more difficult, though, if your annotation can appear in more obscure places such as on method parameters or at type use sites.) Then, you can keep the retention policy as SOURCE.
Next, write your junit tests to do whatever reflective analysis you're intending to do. Instead of trying to find the annotations reflectively, though (since they won't be there) read in the sidecar file and look there.
I think you covered the solution space pretty well.
Two more you didn't cover:
Strip the annotation later in a post processing step using a tool like proguard.
Hack your compiler to switch the annotation retention depending on a flag. Pretty sure you can switch some flag in the internal meta data. Maybe injected by another annotation processor triggered by the annotation #DynamicRetention("flag")?
One of other workarounds may include:
Leaving default retention = CLASS.
Using a library which will read bytecode directly.
#interface X {
}
#X
public class Main {
public static void main(String[] args) throws IOException {
ClassPathResource classResource = new ClassPathResource("com/caco3/annotations/Main.class");
try (InputStream is = classResource.getInputStream()) {
ClassReader classReader = new ClassReader(is);
AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(Main.class.getClassLoader());
classReader.accept(visitor, 0);
System.out.println(visitor.getAnnotationTypes());
}
}
}
yields:
[com.caco3.annotations.X]
The library used is ASM:
ASM is an all purpose Java bytecode manipulation and analysis framework
This code uses some classes from Spring Framework:
ClassPathResource - something similar to java.io.File
AnnotationMetadataReadingVisitor (source code) - is a ClassVisitor collecting annotation metadata
However this approach suffers from the same drawback as you described:
overhead in byte code at run time
because (from javadoc):
Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time.
public static void main(String[] args) throws IOException {
X x = AnnotationUtils.findAnnotation(Main.class, X.class);
System.out.println(x);
}
outputs: null
If #Retention(CLASS) is acceptable, then I would recommend to use ArchUnit. The task you describe sounds like it is a good fit. ArchUnit can be used to define and validate rules for your architecture. For example it can be used to restrict access between certain classes/packages, or e.g. to validate class hierarchies, type names - or annotations.
It is usually executed as a unit test by JUnit or any other test framework. It works by analyzing byte code, so there is no need to switch to runtime retention.
The fluent API is nice and in my opinion way more readable than using reflection or annotation processing for this use case. For example to ensure that certain classes should always have a particular Annotation you would write this rule in a unit test:
classes().that().areAssignableTo(MyService.class).should().beAnnotatedWith(MyAnnotation.class)
It's also possible to create custom rules to assert more complex constraints.

How to understand annotation in java And How to implement my annotation in java?

What I have known are:
annotation was added in java 5
annotation can be using in method, class, and property
annotation can work in RUNTIME, CLASS, SOURCE( I don't know how to work with CLASS and SOURCE, and their's features)
annotation with retention which is RUNTIME can be implement when java program is running.
And I want to implement a annotation to have follows features:
ensure class only being allowed to create a instance
ensure methods only being allowed to access method in the class
it is like as friend in c++
it is same as public and private , but more dynamicall, like
#MyAnnotation(allowMethods={xxx.doSomething})
public void getValue(){}
the getValues method only can be accessed in the instance self and xxx.doSomething() method
What should I do and learn in next?
And Where can I learn about these?
I think you might be misunderstanding something there. Annotations are descriptive elements, not parts of your program. You can write as many annotations as you want, and people who use your code will still be able to ignore them.
That said, an annotation that enforces a policy (as yours does) can actually be implemented, either at compile or at runtime, but you need an external mechanism to help you. I can think of 3:
Annotation processing lets you interact with the compiler and process annotations by generating code or by omitting compiler errors. Unfortunately, I don't think it will work for your case, as you want to protect your annotated type from instantiation, and that means the call site doesn't actually have an annotation. Annotation processing only gives you access to the actual code pieces that have annotations, not to those that refer to them.
AspectJ allows you to write policy enforcement aspects and omit compiler errors, based on static pointcuts. The problem here is that static pointcuts have very limited semantics, so while you could forbid the instantiation of your class altogether, or from certain packages, you could not limit the your class instantiations to 1.
The third way, and probably the only sane way is that you use a container like Spring or Guice and configure your class as singleton. As long as you only retrieve your class from the container, it will never create a second instance.
Finally: If you want to limit the number of instantiations of your class, you can always use a classic Singleton pattern approach.

Adding code to a Java class w/ Instrumentation: ASM or BCEL?

I am writing a game engine/library in which I have an event dispatcher class which dispatches events by calling listener methods of "registered" event handler classes. One can register an event handler/listener with the event dispatcher by calling the appropriate dispatcher method.
This obviously leads to some boilerplate code for registering every event handler(and also other aspects of my engine have similar bolierplate code), so I was wondering - how about just using Instrumentation to add in all of the necessary code during loading of the event handler class, so that no explicit registration with the event dispatcher is necessary while coding - the call to the dispatcher's register method is added in automatically when the program is run.
It is my understanding that in order to use Instrumentation one should use some bytecode modifier API. I know of two - ASM and BCEL. Which one should I use? Obviously, this is a somewhat simple task I am trying to do, so I want the one which is easier to learn and better documented.
EDIT: Here is a specific example.
Original event handler class:
#Handler //indicates this this class should be transformed
public class MouseEventHandler implements EventHandler<MouseEvent>
{
//hidden default constructor
public void handleEvent(MouseEvent event)
{ ... }
}
After transformation:
#Handler
public class MouseEventHandler implements EventHandler<MouseEvent>
{
public MouseEventHandler()
{
//add this line of code to default constructor
Game.getEventDispatcher().addEventHandler(this);
}
public void handleEvent(MouseEvent event)
{ ... }
}
Java bytecode libraries:
ASM is fast and actively developed.
BCEL is comparatively slow.
Javassist is probably easiest to get started with if you're not familiar with Java bytecode.
cglib builds on top of ASM, providing some higher level abstractions.
Byte Buddy generates classes via a DSL. Actively maintained and seeing increasing usage.
I would however consider other options before jumping into bytecode manipulation.
Adding the logic to a few classes might be boring, but unless you've thoushands of handlers, that's the way I would go. Keep it simple.
That said,
Game.registerHandler( this );
would be more object-oriented.
An alternative to adding the logic in each class is to introduce a factory that is responsible to instantiate the handlers.
HandlerFactory.createMouseHandler();
And method createMouseHandler contains something like
Handler mh = new MousheHandler();
registerHandler(mh);
return mh;
If you don't want either of these options, I would consider either an aspect framework (maybe AspectJ) or a container for Invertion of Control (maybe Spring IoC). Aspects allow you to annotate your source, and "weave" code at the selected places. An IoC container allows you to control the lifecycle of object (e.g. instantiation). Both use bytecode instrumentation behind the scene.
But if you want to do the instrumentation yourself, I can only compare Javassist and ASM that I used personally.
ASM is low-level, and operates really at the level of java bytecode. You must be familiar with it. The framework is very well designed, the manual is excellent, and it is a great library. One one side it can be complicate to replace patterns of bytecode, because it requires a so-called "stateful" transformation. One the other side, you have full control over the bytecode.
Javassist is more high-level. You do not operate at the raw level of bytecode, a slight higher level, e.g. fields read/write, message send, constructors. Also, it allows you to specify changes using regular java syntax, that is then compiled by the framework. The API is a bit confused, because the project grew over the years. There is documentation about the framework, but not so well centralized as with ASM.

How can I run my code upon class load?

Is there a feasible way to get my own code run whenever any class is loaded in Java, without forcing the user explicitly and manually loading all classes with a custom classloader?
Without going too much into the details, whenever a class implementing a certain interface read its annotation that links it with another class, and give the pair to a third class.
Edit: Heck, I'll go to details: I'm doing an event handling library. What I'm doing is having the client code do their own Listener / Event pairs, which need to be registered with my library as a pair. (hm, that wasn't that long after all).
Further Edit: Currently the client code needs to register the pair of classes/interfaces manually, which works pretty well. My intent is to automate this away, and I thought that linking the two classes with annotations would help. Next, I want to get rid of the client code needing to keeping the list of registrations up to date always.
PS: The static block won't do, since my interface is bundled into a library, and the client code will create further interfaces. Thus, abstract classes won't do either, since it must be an interface.
If you want to base the behavior on an interface, you could use a static initializer in that interface.
public interface Foo{
static{
// do initializing here
}
}
I'm not saying it's good practice, but it will definitely initialize the first time one of the implementing classes is loaded.
Update: static blocks in interfaces are illegal. Use abstract classes instead!
Reference:
Initializers (Sun Java Tutorial)
But if I understand you right, you want the initialization to happen once per implementing class. That will be tricky. You definitely can't do that with an interface based solution. You could do it with an abstract base class that has a dynamic initializer (or constructor), that checks whether the requested mapping already exists and adds it if it doesn't, but doing such things in constructors is quite a hack.
I'd say you cleanest options are either to generate Code at build time (through annotation processing with apt or through bytecode analysis with a tool like asm) or to use an agent at class load time to dynamically create the mapping.
Ah, more input. Very good. So clients use your library and provide mappings based on annotations. Then I'd say your library should provide an initializer method, where client code can register classes. Something like this:
YourLibrary.getInstance().registerMappedClasses(
CustomClass1.class,
CustomClass2.class,
CustomClass3.class,
CustomClass4.class
)
Or, even better, a package scanning mechanism (example code to implement this can be found at this question):
YourLibrary.getInstance().registerMappedClassesFromPackages(
"com.mycompany.myclientcode.abc",
"com.mycompany.myclientcode.def"
)
Anyway, there is basically no way to avoid having your clients do that kind of work, because you can't control their build process nor their classloader for them (but you could of course provide guides for classloader or build configuration).
If you want some piece of code to be run on any class loading, you should:
overwrite the ClassLoader, adding your own custom code at the loadClass methods (don't forget forwarding to the parent ClassLoader after or before your custom code).
Define this custom ClassLoader as the default for your system (here you got how to do it: How to set my custom class loader to be the default?).
Run and check it.
Depending on what kind of environment you are, there are chances that not all the classes be loaded trouugh your custom ClassLoader (some utility packages use their own CL, some Java EE containers handle some spacific areas with specific classLoaders, etc.), but it's a kind of aproximation to what you are asking.

Reflecting method's actions in Java

I'd like to know how to - if even possible - reflect what method calls are executed inside the method during execution. I'm especially interested in either external method calls (that is, methods in other classes) or calling some specific method like getDatabaseConnection().
My intention would be to monitor predefined objects' actions inside methods and execute additional code if some specific conditions are met like some method is called with specific values. The monitor would be completely external class or a set of classes with no direct access to the object to be monitored by no other way than reflection.
Aspect J will solve your problem.
Try to define a pointcut like this:
pointcut profilling(): execution(public * *(..)) && (
within(com.myPackage..*) ||
In this way you will catch all the call to any public method within the package com.myPackage. Add as many within clauses you need.
Then add the following code:
Object around(): profilling() {
//Do wherever you need before method call
proceed();
//Do wherever you need after method call
}
IF you want to learn something more about aspectJ follow this guide.
I'd expect BCEL to be able to do this. From the web site:
The Byte Code Engineering Library is
intended to give users a convenient
possibility to analyze, create, and
manipulate (binary) Java class files
(those ending with .class).
The "analyze" part being the important bit here. The JavaDoc isn't visible on the web site (as far as I can see) so I can't easily be sure whether or not it'll help you, but it's a reasonable starting point.
BCEL should offer this capability, but ...
... your requirements sound a lot like Aspect-Oriented Programming (AOP), so you should probably also look at AspectJ (with Eclipse tooling).
The main advantage of AspectJ is that it offers a well-designed way to express your specific conditions.

Categories

Resources