Looking for simple recipe for Java Annotation - java

I've never written an annotation in Java.
I've got a simple Java class for performance measurement. I call it PerfLog. Here's an example of its use:
public class MyClassToTest {
public String MyMethod() {
PerfLog p = new PerfLog("MyClassToTest", "MyMethod");
try {
// All the code that I want to time.
return whatever;
} finally {
p.stop();
}
}
}
When p.stop() is called, a line will be written to the log file:
2010/10/29T14:30:00.00 MyClassToTest MyMethod elapsed time: 00:00:00.0105
Can PerfLog be rewritten as an Annotation so that I can write this instead?
public class MyClassToTest {
#PerfLog
public String MyMethod() {
// All the code I want to time.
return whatever;
}
}
It would seem to be a good candidate for annotating: It's easy to add or take away the annotation; a production build can leave out PerfLog entirely without having to remove the annotations from the source code; the annotation processor can get the class and method names.
Is this easy to do? Is there a recipe somethere that I can follow?
It has to be Java 5 so I know I have to use apt somewhere.

There is no trivial way to do this using standard Java tools. The path of least resistance would almost certainly be to use an AOP-style library like Google Guice or Spring or AspectJ. Any home-grown attempt to solve this problem will essentially end up doing what AOP libraries would already do for you.

Consider using AOP or Spring - supports Annotations to intercept method invocations and implement custom code
In case that sounds interesting, the Spring AOP docs are here : http://static.springsource.org/spring/docs/2.5.x/reference/aop.html
You can definitely write the annotation parser and its runtime implementation on your own, but reinventing will only be error prone and inefficient when compared to industry solutions.
If you insist on implementing this on your own (without AOP or AOP with Spring), here is what I can suggest (may not be the bestest method) :
Create your beans via a custom FactoryBean always.
In the custom FactoryBean implementation, query the class for methods and check if they are annotated.
If yes, instead of returning the instance of the class itself, return a proxy over the instance.
In the invoke of this proxy, wrap the call to the actual instance's method with new PerfLog() and p.stop()
Its effectively what AOP would (more powerfully) do for you. However, take note that final classes, static methods, classes with no interfaces etc.. will still be a problem in this case (a different ball game).

Related

Java dependency injection using ASM or CGLib

I have a fairly large Java code base (~15k files) that I do not have access to the source for, however, I would like to modify certain classes at runtime and inject code into certain methods to also call my code.
Due to technical issues, I can't decompile/recompile and go from there. The class files are loaded by native code and are extracted from a custom archive format and loaded using a custom class loader. I can however execute Java code in the context of their JVM instance fairly easily.
My goal is to do something like below:
For example, say in there code there is a class:
class Theirs {
public Theirs() {
//....
}
public String getName() {
return "Theirs";
}
}
And in my code I have:
class Mine
{
public static Theirs theirs_ = null;
public static void myMethod(Theirs theirs) {
theirs_ = theirs;
}
}
I would like to modify every instance of Theirs to behave as such:
class Theirs {
public Theirs() {
Mine.myMethod(this);
}
}
So that I can then do something like:
System.out.println(Mine.theirs_.getName());
I thought that CGLib Proxies would enable this, but with Proxies, the overhead is high due to string comparisons for methods that may be called hundreds thousands of times a second and anyways, I discovered that in order to have an instance of an enhanced object, you need to instantiate them yourself.. IE: not all instances of the class you enhanced are actually enhanced such as:
public static void main( String[] args )
{
Object proxy = Enhancer.create(Object.class, new HashCodeAlwaysZeroMethodInterceptor());
System.out.println(new Object().hashCode());
System.out.println(proxy.hashCode());
}
The first println prints a real objects hash, not 0 as intended.
So now I am thinking that what I need to do is write my own (or modify theirs) ClassLoader that looks for the classes I am interested in modifying, inject my modifications and go from there using something like ASM. (I've done something similar using JVMTI and C++, but the compile/debug process for that is extremely time consuming)
Before I do that however, I was hoping that there was something that worked similar to how CGLib proxies work, in that the library takes care of the required bytecode modifications, but that doesn't require me to actually instantiate an instance of said enhanced class.
I don't know if CGLIB is ideal for injecting Java code into Java classes - but there are a couple of framework like f.e. javassist available which provide a Java centric way to inject code into non-sealed Java classes: http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
For example, I had to create a Plugin mechanism for a university course once where I used javassist therefore. Hope the code example is helpful: https://github.com/RovoMe/PluginApplication/blob/master/PluginFramework/PluginCore/src/main/java/at/rovo/core/classloader/InjectionLoaderStrategyDecorator.java

Is it possible to Perform an action when the method exits using an annotation?

Is it possible to perform an action at the end of a method, in other words when the function control returns to the caller(either because of exception or normal return) using an annotation ?
Example:
#DoTaskAtMethodReturn
public void foo() {
.
.
.
Method foo Tasks
.
.
.
return; --------> Background task done by annotation hook here before returning to caller.
}
Your question is tagged with Spring-Annotations, so you are obviously using Spring. There are several steps to do what you want with Spring:
Enable AspectJ/AOP-Support in your configuration:
<aop:aspectj-autoproxy/>
Write an Aspect (c.f. Spring AOP vs AspectJ) that uses #After and the #annotation pointcut:
#Aspect
public class TaskDoer {
#After("#annotation(doTaskAnnotation)")
// or #AfterReturning or #AfterThrowing
public void doSomething(DoTaskAtMethodReturn doTaskAnnotation) throws Throwable {
// do what you want to do
// if you want access to the source, then add a
// parameter ProceedingJoinPoint as the first parameter
}
}
Please note the following restrictions:
Unless you enable AspectJ compile-time weaving or use a javaagent parameter, the object containing foo must be created via Spring, i.e. you must retrieve it from the application context.
Without additional dependencies, you can only apply aspects on methods that are declared through interfaces, i.e. foo() must be part of an interface. If you use cglib as an dependency, then you can also apply aspects on methods that are not exposed though an interface.
Yes, but not only with annotation.
You have to write your own annotation processor and use code injection.
How to write a Java annotation processor?
What is Java bytecode injection?
Java byte-code injection
The short answer is "Yes, it is possible". This is part of what's called Aspect Oriented Programming (AOP). A common use of annotation-based AOP is #Transactional for wrapping all database activities in a transaction.
How you go about this depends on what you're building, what (if any) frameworks you're using, etc. If you're using Spring for dependency injection, this SO answer has a good example or you can checkout the Spring docs. Another option is to use Guice (my preference), which allows easy AOP.

Write annotation to guard a method from being called when parameters are invalid

Can I have an annotation for a method that when its parameters are null, just do nothing, effectively as not being invoked?
Probably the easiest way to do this is using interfaces and dynamic proxies. Annotations do nothing other than add metadata. You're going to have to add code to act based on the annotation.
You'd have to do a few things --
Create an interface
public interface IService {
#ValidateNull // Your custom annotation
public void yourMethod(String s1);
}
When using the implementation, instantiate it as a JDK Proxy.
IService myService = (IService)java.lang.Proxy.newInstance(ServiceImpl.class.getClassLoader(),
ServiceImpl.class.getInterfaces(),
new YourProxy(new ServiceImpl());
Now, you can via reflection, capture all invocations of your method in YourProxy class.
public YourProxy implements InvocationHandler {
public Object invoke(Object arg0, Method method, Object[] args) throws Throwable {
if (method.isAnnotationPresent(ValidateNull.class)) {
//Check args if they are null and return.
}
}
}
If you dont want to do this, then you're looking at more heavyweight frameworks such as AspectJ / Spring AOP.
Annotations in and of themselves are nothing but data. They don't "do" anything. There are a number of different ways you can have a run time framework that interprets annotations and accomplishes the functionality you're looking for. The most common technique would be what's called Aspect Oriented Programming, where you alter the behaviour of program components based on metadata.
aspectJ is a full featured library that allows you to change the behaviour of just about anything! You wouldn't even technically need an annotation will full aspectJ, there are lots of different ways to 'match' methods that you want to alter the behaviour of.
SpringAOP is a more limited subset of the functionality provided by aspectJ, but it is also easier to use and add to your project as a consequence!

How can I run a function before current function using annotations?

Is there any way for using an annotation for running a function before currently called function, something like this:
public void doSomethingEarlier() {
}
#DoSomethingEarlier
public void doSomething() {
}
So I want to call doSomethin() function, and before executing this function I want to automatically run doSomethingEarlier() function.
You have a number of ways, which are a bit difficult to implement:
use Proxy where you can parse the annotation on the target method and invoke a method with the same name
use AOP
The first approach is more straightforward. It would probably be better to have the annotation look something like:
#BeforeMethod("methodName")
In general, this is how AOP works on the low level.
See Spring Aspect Oriented Programming.
Java won't do this for you. Someone else: you or some library: has to see the annotation and adjust the call process.
Yes, you can use annotations for that. You have to create your own #DoSomethingEarlier annotation (with run-time retention), and you have to code your own annotation processor processor. It is not an easy proposition, and you might want to look for other alternatives like AOP or dynamic proxies (which might not be easy either.)
This is easier...
public void doSomethingEarlier() {
}
public void doSomething() {
doSomethingEarlier();
}

How do I intercept a method invocation with standard java features (no AspectJ etc)?

I want to intercept all method invocations to some class MyClass to be able to react on some setter-invocations.
I tried to use dynamic proxies, but as far as I know, this only works for classes implementing some interface. But MyClass does not have such an interface.
Is there any other way, besides implementing a wrapper class, that delegates all invocations to a member, which is an instance of the MyClass or besided using AOP?
As you note, you cannot use JDK dynamic proxies (no interface), but using Spring and CGLIB (JAR included with Spring), you can do the following:
public class Foo
{
public void setBar()
{
throw new UnsupportedOperationException("should not go here");
}
public void redirected()
{
System.out.println("Yiha");
}
}
Foo foo = new Foo();
ProxyFactory pf = new ProxyFactory(foo);
pf.addAdvice(new MethodInterceptor()
{
public Object invoke(MethodInvocation mi) throws Throwable
{
if (mi.getMethod().getName().startsWith("set"))
{
Method redirect = mi.getThis().getClass().getMethod("redirected");
redirect.invoke(mi.getThis());
}
return null;
}
});
Foo proxy = (Foo) pf.getProxy();
proxy.setBar(); // prints "Yiha"
If you are prepared to do something really ugly, have a look at:
http://docs.oracle.com/javase/7/docs/technotes/guides/jpda/
Basically the debugger interface ought to allow you to attach like a debugger, and hence intercept calls. Bear in mind I think this is a really bad idea, but you asked if it was possible.
Java doesn't have any actual language features for method interception (not sure any static language does)
I kinda like Nick's idea of using the debugger interface, that's just mean.
I think the short answer you need is: No there isn't a way of intercepting a method call in Java without actually replacing the class using a proxy or wrapper.
Note: The AOP libraries just make this happen automatically.
Some of the Java gurus might frown upon this but I've had some good success with avoiding primitive types and setters altogether. My class looks like this:
class Employee extends SmartPojo {
public SmartString name;
public SmartInt age;
}
You'll notice two things: 1. everything is public. 2. No constructor.
The magic happens in SmartPojo which searches for any field which implements the "Smart" interface and initializes it. Since this is no primitive (and no final class), I can add set() and get() methods for all fields anywhere in my model in a single place. So no setter/getter wastes anymore, it's stunningly simple to add notification (also in a single place), etc.
True, this is no POJO anymore and it's not a Bean in most ways but I've found that these old ideas limit me more than they help. YMMV.
I just developed a small framework for this purpose.
You can check it out at: http://code.google.com/p/java-interceptor/ (use svn to check out).
There isn't a lot of magic in AspectJ. You can write your own agent. http://java.sun.com/javase/6/docs/api/java/lang/instrument/package-summary.html seems to be good starting point.
Why cannot your class implement an interface? You could just extract some interface from it containing all the methods that you want to intercept and use the dynamic proxies mechanism easily. It's also a good programming practice to code with interfaces and not classes.
You could use Spring framework with Spring AOP capabilities (which are using dynamic proxies inside) to do it. You will just have to define your class as a Spring bean in the configuration file and clients of your class will have to either get its instance from the Spring application context or as a dependency automatically (by defining the setMyClass(MyClass mc) method for instance). From there you can easily go to defining an aspect that intercepts all the method calls to this class.

Categories

Resources