4

Looked at using CGLib, ASM, BCEL (aspect) and Javassist to add a field to a class during runtime....

Just to get my head straight it looks like these bytecode manipulators don't update the actual class rather allow the user to only dump the modification (like with CGLib and the writeFile method). Was hoping I would find a solution that (a) loaded the class (rather than doing an InputStream with BCEL) and (b) updated the class.

Maybe this is normal? Do people usually create a proxy and pass the proxy around?

What I want to do is to add a field (note: not a property via get/set methods) before passing the object along to a framework that looks for fields (not properties) with a particular annotation. So "clients" are creating my target classes that I want to inject with an extra field. Intercepting with AOP calls to a service layer where I want to manipulate these objects.

Matthew Campbell
  • 1,864
  • 3
  • 24
  • 51

1 Answers1

2

You can redefine classes with Intrumentation. However a common limiation is that you cannot change the fields used. This is because you cannot change the contents of a object (or add to it) once it has been created.

In your case you can,

  • create a proxy as you suggest, however proxies need to be interfaces.
  • create a subclass which has the additional field(s)
  • add the field before the class has loaded.
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • point (3) assuming you mean to intercept the class loader? Example or link to an example? Point (2) won't work for me but point (1) looks like CGLib has some sort of Field interception. Finding examples on CGLib is a nightmare so I not with ya on my a proxy has to be an interface? – Matthew Campbell Aug 06 '12 at 12:38
  • If you know the class you want to load before it is used, you can load it yourself by calling `defineClass`. If you need it to be dynamic, you can create your own ClassLoader which overrides findClass. Or you can use `Instrumentation` which will intercept the class loading without changing the class loader. Most tools require a proxy to be an interface e.g. `Proxy.newProxyInstance(classLoader, interfaces, handler)` – Peter Lawrey Aug 06 '12 at 12:43
  • Found https://github.com/kreyssel/maven-examples/blob/master/javaagent/src/main/java/org/kreyssel/tools/loggingagent/LoggerAgent.java where via an agent you can transform a class. Can you lead me to how this is done when picking up a reference to a classloader? – Matthew Campbell Aug 06 '12 at 13:01
  • What do you mean `picking up a reference`? Do you mean changing it before it is loaded? In that case you get your class loader, use reflections to call `defineClass` with the byte code you created and as long as the class is not already loaded, that will be the byte code for that class. – Peter Lawrey Aug 06 '12 at 13:03
  • What I have seen is that people jack in an interceptor with a javaagent (ClassFileTransformer) and when the JVM starts up you can catch specific classes then transform them (javassist toBytecode() method). When I say pick up a reference I would like to transform after the JVM is started (i.e. when somebody calls my service and I AOP intercept the call, right there transform a class if necessary). – Matthew Campbell Aug 06 '12 at 13:10
  • You can do that to change the code, but not to add fields. If you want additional fields they have to be there from the start (you don't have to add the code until later) – Peter Lawrey Aug 06 '12 at 13:16