javassist
Java bytecode engineering toolkit
Javassist by jboss-javassist
I'm using Javassist to generate a class foo
, with method bar
, but I can't seem to find a way to add an annotation (the annotation itself isn't runtime generated) to the method. The code I tried looks like this:
ClassPool pool = ClassPool.getDefault();
// create the class
CtClass cc = pool.makeClass("foo");
// create the method
CtMethod mthd = CtNewMethod.make("public Integer getInteger() { return null; }", cc);
cc.addMethod(mthd);
ClassFile ccFile = cc.getClassFile();
ConstPool constpool = ccFile.getConstPool();
// create the annotation
AnnotationsAttribute attr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag);
Annotation annot = new Annotation("MyAnnotation", constpool);
annot.addMemberValue("value", new IntegerMemberValue(ccFile.getConstPool(), 0));
attr.addAnnotation(annot);
ccFile.addAttribute(attr);
// generate the class
clazz = cc.toClass();
// length is zero
java.lang.annotation.Annotation[] annots = clazz.getAnnotations();
And obviously I'm doing something wrong since annots
is an empty array.
This is how the annotation looks like:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
int value();
}
Source: (StackOverflow)
I have a java class which creates a custom classloader based on javassist class loader on start up and then run the real program class.
I'm getting the following error:
log4j:ERROR A "org.apache.log4j.ConsoleAppender" object is not assignable to a
"org.apache.log4j.Appender" variable.
log4j:ERROR The class "org.apache.log4j.Appender" was loaded by
log4j:ERROR [javassist.Loader@6f97b10a] whereas object of type
log4j:ERROR "org.apache.log4j.ConsoleAppender" was loaded by
[java.net.URLClassLoader@5b414a8d].
log4j:ERROR Could not instantiate appender named "stdout".
The problem is related to the fact that one object is created by the original classloader while the other is created by the custom one.
Is there a way to resolve this error?
Thanks in advance,
Avner
Source: (StackOverflow)
I have been using Javassist to dynamically manipulate classes as they are loaded. While adding code to a method is relatively easy using Javassist, I have not been able to find a way to remove code.
At this time I am simulating the removal of the code by using nop instructions to replace the targeted opcodes and any parameters. However, I consider this to be mostly a hack:
Each opcode has to be treated separately, since the byte length of the parameters differs. In some cases I also need to choose between nop and pop, depending on whether the removed opcode affects the stack or not. This kind of manipulation is starting to get tedious - and the code that does it is becoming accordingly convoluted. So, naturally, I am hoping for an existing solution.
The final result is filled with nop instructions. While the JVM should optimize those out with no performance impact, the resulting bytecode is still quite inelegant and bigger than it should be. This is more of an issue of aesthetics, but it is still something to consider.
Unfortunately, merely shifting parts of the bytecode array to close the gap is not enough - any references to the moved code (e.g. branch instruction indexes) should be updated as well.
Is it possible to remove instructions using Javassist? Alternatively, is there a bytecode manipulation library that would allow me to do that easily, without having to essentially parse the bytecode myself?
Source: (StackOverflow)
My Goal
To be able to detect when, at runtime, a comparison is made (or any other operation like, *, - , /, >, < ,...
This should be achieved to edit the bytecode of a class using Javassist or ow2 ASM
What must be achieved
This code
public class Test{
public void m(){
if(a>2){
//blablabla
}
}
}
Has to become
public class Test{
public void m(){
if(someExternalClass.greaterThan(a,2)){
//blalbla
}
}
}
The greaterThan will return exactly the same result as '>' but will also be used the save the amount of comparisons
The external class will then be notified everytime a comparison has been made
Extra note
It has to be done everywhere there is an operation. So not only in if statements.
This means
int a = c+d;
must also become
int a = someExternalClass.add(c,d);
Do you have any suggestions on how I can achieve this with Javassist or other libraries.
I guess it'll have something to do with OpCodes like IFLT, IFGT
Source: (StackOverflow)
I am trying to delete a method from a class file using Javassist.
Target class:"RemoveMethod"
.
Target method:"DoubleCheck"
.
My codes:
package javassist;
import java.io.IOException;
import java.lang.reflect.Method;
import javassist.*;
public class cRepair {
public static void main(String[] args) throws NotFoundException, IOException, CannotCompileException{
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get("javassist.RemoveMethod");
CtMethod ctm = ctClass.getDeclaredMethod("DoubleCheck");
ctClass.removeMethod(ctm);
ctClass.writeFile("C:/Users/workspace/Javaproject1/src/javassis");
}
}
Then,run the code using the file "javassist.jar":
javac -cp javassist.jar cRepair.java
Then check the target class:
javap -verbose RemoveMethod.class
The method "DoubleCheck" is still there!
This looks really odd. Why could this happen and how to fix it?
Source: (StackOverflow)
Given a Java application which was written with performance in mind (i.e. methods are deliberately not declared 'strictfp' in the source code), is it possible to allow users to run the entire application in strictfp mode?
It looks like a crude approach would be to simply add the "strictfp" attribute to all methods of all classes using a custom class loader written using javassist. This would be similar to:
http://www.verious.com/qa/no-strictfp-in-scala-workarounds/
However, the class loader would need to add the strictpf attribute to all class methods in the application, including private ones. (The application is simply too large and complex to explicitly list all possible methods which might requre the strictfp attribute.)
The reflection API in javassist does not seem to support listing private methods:
http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/html/javassist/CtClass.html#getMethods()
Is what I want to do possible in javassist (or at all via the custom class loader approach)?
Source: (StackOverflow)
I want to rename a field inside a java class at runtime. In addition, Any method that access that field ;wether it's read or write; I need it to be modified to use the new name instead of the old name....
All this will be done inside the pre-main method...
As an Exmaple, given the following code:
public class Class1
{
String strCompany;
public String Test()
{
strCompany = "TestCompany";
return strCompany;
}
}
In the above class, I need to change the field "strCompany" to be "strCompany2", in addition I need the method Test to use the new name instead of the old name....
changing the field name can be done using the setName method from the ctField class, but how can I modify the method body to use the new name.
Source: (StackOverflow)
How to add the @Override
annotation to a method while creating the class using javaassist?
ClassPool pool = ClassPool.getDefault();
CtClass ctClasz = pool.makeClass("test.ExampleImpl");
ctClasz.addInterface(pool.get(MyInterface.class.getName()));
CtMethod method = CtNewMethod.make ("@Override public void print() { System.out.println(\"Hello! \"); }", ctClasz);
ctClasz.addMethod(method);
System.out.println("Implementd: Interfaces:" + ctClasz.getInterfaces());
System.out.println("Methods: " + ctClasz.getMethods());
ctClasz.writeFile("D:");
This code is throwing exception as follows:
Exception in thread "main" javassist.CannotCompileException: [source error] syntax error
near "@Override p"
at javassist.CtNewMethod.make(CtNewMethod.java:78)
at javassist.CtNewMethod.make(CtNewMethod.java:44)
at javaassist.Demo.main(Demo.java:17)
Caused by: compile error: syntax error near "@Override p"
at javassist.compiler.Parser.parseClassType(Parser.java:983)
at javassist.compiler.Parser.parseFormalType(Parser.java:191)
at javassist.compiler.Parser.parseMember1(Parser.java:51)
at javassist.compiler.Javac.compile(Javac.java:89)
at javassist.CtNewMethod.make(CtNewMethod.java:73)
... 2 more
Source: (StackOverflow)
In my program, I deal with classes and primitive types.
If the program finds a class, it simply does one of the following calls :
Class.forName(classname)
cc.toClass()
where cc
is an instance of CtClass
However, if it finds a primitive type, things get worse :
Class.forName
is not usable, it cannot be used with primitive types.
cc.toClass()
returns null
It's possible to call the TYPE
field from primitive types wrapper class but how can I do it with reflection ?
Here is my code :
CtClass cc;//Obtained from caller code
Class<?> classParam;
if (cc.isprimitive()) {
classParam= ?? // How can I get TYPE field value with reflection ?
} else {
String nomClasseParam = cc.getName();
if (nomClasseParam.startsWith("java")) {
classeParam = Class.forName(nomClasseParam);
} else {
classeParam = cc.toClass();
}
}
Javassis 3.12.0.GA
EDIT:
I have posted the solution I chose in the anwsers below.
Anyway, I ticked Tom's answer.
Source: (StackOverflow)
I want to add an "insertBefore" on a method of a core JDK 5 class. For some reason it´s not working. Here's an example of the code:
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get("com.sun.org.apache.xerces.internal.impl.xs.XSMessageFormatter");
CtMethod ctMethod = ctClass.getDeclaredMethods()[0];
ctMethod.insertBefore("System.out.println(\"WORKED\");");
ctClass.toClass();
The com.sun.org.apache.xerces.internal.impl.xs.XSMessageFormatter comes bundled with the JDK, it's inside rt.jar. After the snippet above, I run some code that forces the XSMessageFormatter class to run, but my inserted code never runs. I can only get this to work on my own classes. This code is running as a simple standalone app.
Any ideas?
Source: (StackOverflow)
I am facing a problem where I have to modify a package-info.
package-info.java
@javax.xml.bind.annotation.XmlSchema(namespace = "http://some.url/soap/style/document_literal")
package org.example.wsdl.wsdl;
The following code works fine with 1.7.0_45.
// do not load any classes before, this could break the following code.
Class<?> pkgInfo = Class.forName("org.example.wsdl.package-info", true, NameSpaceModifier.class.getClassLoader());
Field field = Class.class.getDeclaredField("annotations");
field.setAccessible(true);
final XmlSchema oldAnnotation = (XmlSchema) pkgInfo.getAnnotations()[0];
logger.debug("Old Annotation namespace value was: " + oldAnnotation.namespace());
XmlSchema newAnnotation = new XmlSchema() {
@Override
public XmlNs[] xmlns() {
return oldAnnotation.xmlns();
}
@Override
public String namespace() {
return "newNs";
}
@Override
public XmlNsForm elementFormDefault() {
return oldAnnotation.elementFormDefault();
}
@Override
public XmlNsForm attributeFormDefault() {
return oldAnnotation.attributeFormDefault();
}
@Override
public String location() {
return oldAnnotation.location();
}
@Override
public Class<? extends Annotation> annotationType() {
return oldAnnotation.annotationType();
}
};
@SuppressWarnings("unchecked")
Map<Class<? extends Annotation>, Annotation> annotations = (Map<Class<? extends Annotation>, Annotation>) field.get(pkgInfo);
annotations.put(XmlSchema.class, newAnnotation);
XmlSchema modifiedAnnotation = (XmlSchema) pkgInfo.getAnnotations()[0];
When compiling and executing the same Code with 1.8.0_05 I get this error message:
java.lang.NoSuchFieldException: annotations
at java.lang.Class.getDeclaredField(Class.java:2057)
I know its a Hack, at least it looks like one. But does Java 8 work here as expected?
How do I have to change that code that it does work with Java 8 then?
Javassist answers are welcome too ;)
Source: (StackOverflow)
I'm trying to generate my Entity class using javassist. Everything went well until I added the GeneratedValue annotation to the Id field. The @Id annotation works fine but when I add @GeneeratedValue I get an exception. This is my code:
ClassPool cp = ClassPool.getDefault();
CtClass ctClass = cp.makeClass("test.Snake");
ClassFile classFile = ctClass.getClassFile();
classFile.setVersionToJava5();
AnnotationsAttribute attribute = new AnnotationsAttribute(classFile.getConstPool(), AnnotationsAttribute.visibleTag);
Annotation idAnnotation = new Annotation(classFile.getConstPool(), ClassPool.getDefault().get("javax.persistence.Id"));
attribute.addAnnotation(idAnnotation);
Annotation gvAnnotation = new Annotation(classFile.getConstPool(), ClassPool.getDefault().get("javax.persistence.GeneratedValue"));
attribute.addAnnotation(gvAnnotation);
CtField idField = new CtField(ClassPool.getDefault().get("java.lang.Long"), "id", ctClass);
idField.getFieldInfo().addAttribute(attribute);
ctClass.addField(idField);
CtField nameField = new CtField(ClassPool.getDefault().get("java.lang.String"), "name", ctClass);
ctClass.addField(nameField);
AnnotationsAttribute attr = new AnnotationsAttribute(classFile.getConstPool(), AnnotationsAttribute.visibleTag);
Annotation annotation = new Annotation(classFile.getConstPool(), ClassPool.getDefault().get("javax.persistence.Entity"));
attr.addAnnotation(annotation);
classFile.addAttribute(attr);
snakeClass = ctClass.toClass();
newInstance = snakeClass.newInstance();
And this is the exception I get:
java.lang.NullPointerException
at javassist.bytecode.ConstPool.getUtf8Info(ConstPool.java:565)
at javassist.bytecode.annotation.EnumMemberValue.getValue(EnumMemberValue.java:98)
at javassist.bytecode.annotation.EnumMemberValue.write(EnumMemberValue.java:116)
at javassist.bytecode.annotation.Annotation.write(Annotation.java:316)
at javassist.bytecode.AnnotationsAttribute.setAnnotations(AnnotationsAttribute.java:246)
at javassist.bytecode.AnnotationsAttribute.addAnnotation(AnnotationsAttribute.java:211)
at ClassLoadingTest.javassitTest(ClassLoadingTest.java:56)
It seems to be a problem with @GeneratedValue. When I use it alone whithout id I get this exception either. When I use eclipse debugger to watch variable values, I get get this
com.sun.jdi.InvocationException occurred invoking method.
instead of the annotation value. but for Id annotation it shows a javassist annotation object.
I'm new to javassist. Can anyone help me?
Source: (StackOverflow)
In a project I'm currently working on, I need to generate Java classes at runtime.
I also need to avoid using reflection when using these classes later on.
I've been search for current solutions to do this, and found Javassist and Java 6 Java Compiler API.
I'm confused though:
What does Javassist uses to generate
classes? Does it uses reflection or
something?
I've coded some tests and found it
pretty easy to generate bytecode
from source code, and then load
classes from the generated bytecode.
What are the advantages of using
Javassist over this solution?
Source: (StackOverflow)
I have a maven project which compiles with javac / aspectj compiler.
I want to run on classes which were compiled a javassist program which manipulate the compiled classes and add stuff to them.
I thought using the "process-classes" phase to run my tool.
My question is what is the best way to iterate with javassist over the classes files created in the "target/classes" so I can load, fix and save afterwards.
Another requirement is to run the tool on test classes as well.
If there is an open source project which does similar stuff it will be great to see a live example.
Thanks,
Avner
Source: (StackOverflow)
What I'm trying to is to get 'hashCode()' value of the object that calls a specific method in Java. For example,
public class Caller {
public void aMethod() {
Callee calleeObj = new Callee();
calleeObj.aSpecificMethod();
//do something
}
}
What I want to know is Caller's hashCode() value which calls calleeObj.aSpecificMethod()
during the runtime. It is for drawing an Object diagram like below.

As a constraint, I only can modify '.class' files using bytecode instrumentation techniques.
To do that, I've tried Javassist
library to instrument inside Callee.aSpecificMethod()
but this way cannot get the caller's object. The reason seems obvious because instrumented code on 'Callee.aSpecificMethod()
' only can access codes on Callee
class, not Caller
class.
Is there any way to capture the hashCode() value of caller's object using Javassist? I'm considering ASM 5.0 also, but using ASM 5.0 is the last option because I've built many code based on Javassist until now.
Source: (StackOverflow)