helloworld-classfiletransformer: Applying ClassTransformers to your Java EE archive
This is a WAR based application showing you how Wildfly let you apply a ClassTransformer to the classes in your enterprise archive.
It consists of a server component and a client component: * The server component is a simple @Stateless session EJB called HelloBean, which exposes a SOAP based view * The client component is a simple Java application that makes a call to the EJB through it’s Web service interface
All code is co-bundled in this projects' WAR src directory.
About the code
This project is a Web ARchive (WAR) project. It’s src folder contains three packages: * hello.client : this is where you find the SOAP based Java application client * hello.server.ejb : this is where you find the EJB that exposes a SOAP based view * hello.server.transformation : this is where you find the bytecode manipulation code
Note the file: src/main/webapp/META-INF/jboss-deployment-structure.xml. This is where we register a Java ClassFileTransformer. A ClassFileTransformer is a class that has a transform method that receives a class’s bytecode as a byte array input and then produces the class’s new bytecode. If the transformer doesn’t want to modify the class received, then it simply returns the input array directly. If, however, it want’s to transform it, it does so by means of cglib, javaassist, etc. This example demonstrates bytecode manipulation using Javassist.
It is the EJB’s implementation class, HelloBean, that is modified in this example. The modification is really simple: it simply injects logging statements before and after the sayHello() method. But Javaassist can do much more - check out the relevant documentation for Javassist. Or choose another bytecode generation library. The choice is yours - Wildfly doesn’t care what you choose.
You could achieve the same effect using EJB interceptors or CDI interceptors. They are standard and would normally be the recommended way to go about "around" behavior. But Java EE interceptors are not as powerful as bytecode manipulation can be: with bytecode manipulation you can easily advice unmanaged classes (including static member methods etc), "add/remove" interfaces, fields, methods and so on. And you can even advice code that is a third party dependency to your application (say Apache Commons library code).
Deploy the WAR
Start WildFly 10.1.0.Final (or newer)
mvn clean install wildfly:deploy
Run the SOAP client
mvn compile exec:java
Inspect the server log
Note that a single EJB was installed: HelloBean. It exposes a SOAP based interface, which is used by the client application.
Upon deployment you should see something like: "Instrumenting hello.server.ejb.HelloBean" and "Successfully instrumented hello.server.ejb.HelloBean". That is the example class transformer that tells you it has instrumented the HelloBean EJB.
Upon calling the EJB’s web service endpoint you should see something like: "INTERCEPTED MethodInvocation". One line before the method invocation. And one line after the method invocation.
Do make sure to verify that these lines hasn’t just been printed by the EJB’s sayHello() method.
And then check out the class "HelloByteCodeManipulator" which do the manipulation on behalf of the class transformer.
Finally: note that the transformer is registered in the WAR' archives META-INF/jboss-deployment-structure.xml file.
/Enjoy what is otherwise normally only performed by advanced Java Agents.