EzDevInfo.com

javassist

Java bytecode engineering toolkit Javassist by jboss-javassist

Adding an annotation to a runtime generated method/class using 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)

Configure org.apache.log4j.ConsoleAppender with custom classloader

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)

Advertisements

Removing instructions from Java bytecode

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)

Replace java operators by methods in bytecode using javassist

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)

How to remove a method using Javassist?

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)

Force all Java arithmetic to strictfp at runtime, using javassist?

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)

renaming a field using javassist at runtime in the pre-main method (java instrumentation)

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 @Override annotation to a method while creating the .class file using javaassist?

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)

How to get class of primitive types with Javassist?

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)

Is is possible to instrument with javassist java core classes? Classes loaded by the bootstrap classloader

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)

Unable to modify annotation of package-info.java using Java 8

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)

Javassist annoations problem

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)

Javassist Vs. Java Compiler API

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:

  1. What does Javassist uses to generate classes? Does it uses reflection or something?

  2. 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)

Integrating javassist byte code manipulation with maven compilation

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)

To get the hashCode() of the object that calls a specific method in Java

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.

enter image description here

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)