GithubHelp home page GithubHelp logo

jboss-javassist / javassist Goto Github PK

View Code? Open in Web Editor NEW
4.0K 4.0K 691.0 29.85 MB

Java bytecode engineering toolkit

Home Page: www.javassist.org

License: Other

HTML 3.46% Java 96.54% CSS 0.01%
java java-bytecode

javassist's People

Contributors

andresluuk avatar backpaper0 avatar beikov avatar catsalty avatar chibash avatar cmelchior avatar dakusui avatar derklaro avatar eshizhan avatar fanofxiaofeng avatar junwen12221 avatar kyongsik-yoon avatar likey3 avatar m8rten avatar mkordas avatar nickl- avatar ningzhang-e avatar nschaefe avatar oldratlee avatar oreissig avatar pietrobraione avatar sam-ma avatar scottmarlow avatar sgjesse avatar shifujun avatar skybber avatar tim-hoffman avatar vimfun avatar wuwen5 avatar ximsfei avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

javassist's Issues

$class is not available when inside static method

Hi Chiba,

I am currently using latest build 3.18.2-GA and I am trying to get the class in which the static method is declared by passing $class but was not able to make it work. Is this supported and if so how I can make it work. Thanks.

Tomcat error "Unable to process Jar entry" for all javassist classes

Hello, I recently upgraded javassist in a project that was moving to Java 8. When tomcat starts we get errors for what looks like every class in javassist. I'm pretty sure it's just because tomcat is looking for servlets and such (which it's not going to find anyway) but it's concerning anyway. Here is the error:

13:03:26 starting axplatq
13:03:26 Using CATALINA_BASE: /www/axplatq
13:03:26 Using CATALINA_HOME: /www/tomcat/apache-tomcat-7.0.54
13:03:26 Using CATALINA_TMPDIR: /www/axplatq/temp
13:03:26 Using JRE_HOME: /www/java/jdk1.8.0_05
13:03:26 Using CLASSPATH: /www/java/jdk1.8.0_05/lib/tools.jar:/www/tomcat/apache-tomcat-7.0.54/bin/bootstrap.jar:/www/tomcat/apache-tomcat-7.0.54/bin/tomcat-juli.jar
13:03:26 Using CATALINA_PID: /www/axplatq/logs/tomcat.pid
13:03:26 Tomcat started.
13:03:26 INIT: 2015-02-02 12:58:26-06:00
13:03:26 INIT: start() by a909179
13:03:26 INFO: Loaded APR based Apache Tomcat Native library 1.1.30 using APR version 1.3.9.
13:03:26 INFO: APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
13:03:26 INFO: Initializing ProtocolHandler ["http-apr-8070"]
13:03:26 INFO: Initialization processed in 1241 ms
13:03:26 INFO: Starting service Catalina
13:03:26 INFO: Starting Servlet Engine: Apache Tomcat/7.0.54
13:03:26 INFO: Deploying web application archive /www/axplatq/webapps/platform.war
13:03:26 SEVERE: Unable to process Jar entry [javassist/ByteArrayClassPath.class] from Jar [jar:file:/www/axplatq/webapps/platform/WEB-INF/lib/javassist-3.19.0-GA.jar!/] for annotations
.... on and on

java.lang.VerifyError: StackMapTable error: bad offset

Hi Shigeru,

Please excuse me if this is not the right place to ask the question. I tried your github page to see if I can send email.

I used CtMethod.insertBefore to the following API during JVM startup and I end having following error. Can you please give me some help/hint/clue, what could be the issue?
BTW: I'm trying to instrument ojdbc7.jar
I'm suspecting, it could be an issue in javassist library.

Caused by: java.lang.VerifyError: StackMapTable error: bad offset
Exception Details:
Location:
oracle/jdbc/driver/OracleStatement.getMoreResults(I)Z @0: aload_0
Reason:
Invalid stackmap specification.
Current Frame:
bci: @166
flags: { }
locals: { 'oracle/jdbc/driver/OracleStatement', integer, 'java/lang/Object' }
stack: { }
Bytecode:
0000000: 2a13 073a 1307 3c13 0762 1307 7e04 bd03
0000010: 4459 03bb 05b8 591b b707 6a53 b807 614d
0000020: 2cb2 0757 a500 0b2c c007 47b6 075a ac00
0000030: 2a13 073a 1307 3c13 0762 1307 7e04 bd03
0000040: 4459 03bb 05b8 591b b707 6a53 01b8 0752
0000050: 4d2c b207 57a5 000f 2cc0 0747 b607 5aa7
..........

Exception Handler Table:
bci [100, 359] => handler: 359
bci [48, 466] => handler: 466
Stackmap Table:
full_frame(@47,{Object[#807],Integer,Object[#836]},{})
same_frame(@98)

May be a bug for CtNewMethod.make...

Not sure if this is a bug...When I wanna use CtNewMethod.make to generate a method which calls default method in interface (JDK 8 feature), it will throw a 'Class not found' exception.
Here is the test code for reproducing this error.

public class TestJavassist {

    public interface IA {
        default int get() {
            return 0;
        }
    }

    public static class A implements IA {
        public int anotherGet() {
            return 1;
        }
    }

    public static void main(String[] args) {
        ClassPool classPool = ClassPool.getDefault();
        try {
            CtClass ctClass = classPool.get(A.class.getName());
            String src = "public void id() { get(); }";
            CtMethod make = CtNewMethod.make(src, ctClass);
        } catch (NotFoundException e) {
            e.printStackTrace();
        } catch (CannotCompileException e) {
            e.printStackTrace();
        }
    }
}

And this is the exception:

javassist.CannotCompileException: [source error] get() not found in com.a17zuoye.commons.cache.couchbase.TestJavassist$A
    at javassist.CtNewMethod.make(CtNewMethod.java:79)
    at javassist.CtNewMethod.make(CtNewMethod.java:45)
    at com.a17zuoye.commons.cache.couchbase.TestJavassist.main(TestJavassist.java:28)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: compile error: get() not found in com.a17zuoye.commons.cache.couchbase.TestJavassist$A
    at javassist.compiler.TypeChecker.atMethodCallCore(TypeChecker.java:749)
    at javassist.compiler.TypeChecker.atCallExpr(TypeChecker.java:695)
    at javassist.compiler.JvstTypeChecker.atCallExpr(JvstTypeChecker.java:157)
    at javassist.compiler.ast.CallExpr.accept(CallExpr.java:46)
    at javassist.compiler.CodeGen.doTypeCheck(CodeGen.java:242)
    at javassist.compiler.CodeGen.atStmnt(CodeGen.java:330)
    at javassist.compiler.ast.Stmnt.accept(Stmnt.java:50)
    at javassist.compiler.CodeGen.atStmnt(CodeGen.java:351)
    at javassist.compiler.ast.Stmnt.accept(Stmnt.java:50)
    at javassist.compiler.CodeGen.atMethodBody(CodeGen.java:292)
    at javassist.compiler.CodeGen.atMethodDecl(CodeGen.java:274)
    at javassist.compiler.ast.MethodDecl.accept(MethodDecl.java:44)
    at javassist.compiler.Javac.compileMethod(Javac.java:169)
    at javassist.compiler.Javac.compile(Javac.java:95)
    at javassist.CtNewMethod.make(CtNewMethod.java:74)
    ... 7 more

It works fine if I changed the 'get();' to 'anotherGet();', which is a method in class A, not in the interface. So is this a bug or I misused the 'make' method?

Thank you in advance for your kind help.

Static Inner classes Vs Non-Static Inner Classes

Hi @chibash ,

playing with Javassist, I realize that Javassist actually works pretty fine with static inner classes. I guess that when you mention (section 4.7 of the tutorial) :

Inner classes or anonymous classes are not supported.

you are talking about non static inner classes, as the byte code is more difficult to play with (due to passing a reference to Outer.this).

If so, would you mind to be more precise in the docs ?

Thx in advance,
Stéphane

java.lang.ExceptionInInitializerError when instrumenting the constructor of an inner class

Hi,

I've been working on a library that reports the line coverage of unit test cases, and it uses Javassist to instrument the java code. It works pretty well, actually Javassist API is very easy to use (thanks for that), but there is a weird case that leads to a java.lang.ExceptionInInitializerError. Let suppose that I'm trying to get the coverage of the following class:


public abstract class Foo {

  public static final ExtendsFoo extendsFoo = new ExtendsFoo();

  protected Foo() {
    super();
  }

  public static class ExtendsFoo extends Foo {
    public ExtendsFoo() {
      super();
    }
  }
}

using the following test case:


import static org.junit.Assert.assertNotNull;
import org.junit.Test;

public class TestFoo {

  @Test
  public void test() {
    Foo.ExtendsFoo other_foo = new Foo.ExtendsFoo();
    assertNotNull(other_foo);
  }
}

after instrument the class under test, I got the following bytecode

public abstract class Foo {
  public static final Foo$ExtendsFoo extendsFoo;

  public static final int[] $__my_field;

  protected Foo();
    Code:
       0: getstatic     #26                 // Field $__my_field:[I
       3: iconst_0      
       4: dup2          
       5: iaload        
       6: iconst_1      
       7: iadd          
       8: iastore       
       9: aload_0       
      10: invokespecial #1                  // Method java/lang/Object."<init>":()V
      13: getstatic     #26                 // Field $__my_field:[I
      16: iconst_1      
      17: dup2          
      18: iaload        
      19: iconst_1      
      20: iadd          
      21: iastore       
      22: return        
    LineNumberTable:
      line 7: 0
      line 8: 13

  static {};
    Code:
       0: iconst_2      
       1: newarray       int
       3: putstatic     #26                 // Field $__my_field:[I
       6: new           #2                  // class Foo$ExtendsFoo
       9: dup           
      10: invokespecial #3                  // Method Foo$ExtendsFoo."<init>":()V
      13: putstatic     #4                  // Field extendsFoo:LFoo$ExtendsFoo;
      16: return        
    LineNumberTable:
      line 4: 6
}

public class Foo$ExtendsFoo extends Foo {
  public static final int[] $__my_field;

  public Foo$ExtendsFoo();
    Code:
       0: getstatic     #18                 // Field $__my_field:[I
       3: iconst_0      
       4: dup2          
       5: iaload        
       6: iconst_1      
       7: iadd          
       8: iastore       
       9: aload_0       
      10: invokespecial #1                  // Method Foo."<init>":()V
      13: getstatic     #18                 // Field $__my_field:[I
      16: iconst_1      
      17: dup2          
      18: iaload        
      19: iconst_1      
      20: iadd          
      21: iastore       
      22: return        
    LineNumberTable:
      line 12: 0
      line 13: 13

  static {};
    Code:
       0: iconst_2      
       1: newarray       int
       3: putstatic     #18                 // Field $__my_field:[I
       6: return        
}

and, when I run the test case (using for example JUnit command line) on the instrumented code, I got the following exception:

java.lang.ExceptionInInitializerError
    at TestFoo.test(TestFoo.java:9)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
        ...
Caused by: java.lang.NullPointerException
    at Foo$ExtendsFoo.<init>(Foo.java:12)
    at Foo.<clinit>(Foo.java:4)

it seems that the JVM tries to create a new instance of Foo, which creates a new instance of ExtendsFoo in the static constructor, and the exception occurs. if I don't instrument the constructor of ExtendsFoo class, the java.lang.ExceptionInInitializerError isn't thrown and the test case returns success.

am I doing something really wrong? or, is this a Javassist issue?

Thanks

ECCN for javassist

Hello,
We use javassist 3.19 in our commercial product and therefore need to know the ECCN for it.
The ECCN is an international Export control and compliance number that is necessary for EVERY Export. Most of the european countries specify their goods according to the european commerce control list (EG dual-use list : http://ec.europa.eu/trade/import-and-ex ... -controls/).
So for export of a commercial Software using javassist 3.19 ( or any other open source or OEM Software), we need to document the libs, on one side to comply with license obligations and on the other side the ECCNs for Export restrictions. Please note, as the US regulations also care about re-export of US items ( any stuff that contains US Content above a certain Limit), we need to specify both; the EU-ECCN and the US-ECCN and hopefully the US license exception that applies (e.g. TSU for open source).

So please specify the ECCN for javassist 3.19 or answer the following questions:

  • Country of origin ( where is javassist 3.19 Software mainly developed)
  • is there US Content in there? ( e.g. other open source libs)
  • Is the SW designed or modified to use cryptography performing any cryptographic function other than authentication or digital signature? (y/n)
    –if yes,
    -- key length symetric
    -- Bit length asymmetric

Thanks and kind regards
Maria Beurer

No way to get Field initializer

Hi @chibash ,

first, thank you very much for all your work. I am new to javassist, and must say it's quite a good and complex project.

I am trying to copy all fields from a class A to a class B (and its methods as well). I solved a number of problems already but there is one I can't solve : how to copy the fields initializers from A to B ?

There seems to be no way to get the fields iniatlizers in a given class.

javassist-android-master;makeClass throw EOFException

Hi @chibash
i'm using javassist-android-master for my project,but when i use "makeClass(inputstream classfile) " (the .class file is in SDCard), javassist throw a EOFException:

java.io.EOFException
at libcore.io.Streams.readFully(Streams.java:83)
at java.io.DataInputStream.readInt(DataInputStream.java:124)
at javassist.bytecode.ClassFile.read(ClassFile.java:767)
at javassist.bytecode.ClassFile.(ClassFile.java:114)
at javassist.CtClassType.(CtClassType.java:94)
at javassist.ClassPool.makeClass(ClassPool.java:748)
at javassist.ClassPool.makeClass(ClassPool.java:726)
at org.jamruby.javassistsample.MainActivity.onCreate(MainActivity.java:66)
at android.app.Activity.performCreate(Activity.java:5104)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2258)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2354)
at android.app.ActivityThread.access$600(ActivityThread.java:150)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1244)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5191)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562)
at dalvik.system.NativeStart.main(Native Method)

how to fix it? thx!

Class enhancement fails for default interface methods (Java 1.8)

This issue applies to the current 3.19.0-GA running on Java 8 Update 45 (1.8.0_45-b14) on OS X.

If you have a class that you are enhancing with Javassist that implements an interface with a default method implementation, Javassist enhancement fails with a VerifyError. Here's an example default method implementation on an interface:

public default void foo() {

}

The exception goes away if you use the -noverify JVM command line option.

And here's the exception. Note that we are using Hibernate.

06/10/15 10:01:49 [RMI TCP Connection(3)-127.0.0.1] ERROR o.h.proxy.pojo.BasicLazyInitializer - Javassist Enhancement failed: Reply
java.lang.VerifyError: (class: Reply_$$_javassist_204, method: _d18foo signature: ()V) Illegal use of nonvirtual function call
    at java.lang.Class.getDeclaredFields0(Native Method) ~[na:1.8.0_25]
    at java.lang.Class.privateGetDeclaredFields(Class.java:2575) ~[na:1.8.0_25]
    at java.lang.Class.getField0(Class.java:2967) ~[na:1.8.0_25]
    at java.lang.Class.getField(Class.java:1693) ~[na:1.8.0_25]
    at javassist.util.proxy.ProxyFactory.setField(ProxyFactory.java:352) ~[javassist-3.11.0.GA.jar:na]
    at javassist.util.proxy.ProxyFactory.createClass3(ProxyFactory.java:341) ~[javassist-3.11.0.GA.jar:na]
    at javassist.util.proxy.ProxyFactory.createClass2(ProxyFactory.java:314) ~[javassist-3.11.0.GA.jar:na]
    at javassist.util.proxy.ProxyFactory.createClass(ProxyFactory.java:273) ~[javassist-3.11.0.GA.jar:na]
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.getProxyFactory(JavassistLazyInitializer.java:162) ~[hibernate-core-3.3.2.GA.jar:3.3.2.GA]
    at org.hibernate.proxy.pojo.javassist.JavassistProxyFactory.postInstantiate(JavassistProxyFactory.java:66) [hibernate-core-3.3.2.GA.jar:3.3.2.GA]
    at org.hibernate.tuple.entity.PojoEntityTuplizer.buildProxyFactory(PojoEntityTuplizer.java:188) [hibernate-core-3.3.2.GA.jar:3.3.2.GA]
    at org.hibernate.tuple.entity.AbstractEntityTuplizer.<init>(AbstractEntityTuplizer.java:151) [hibernate-core-3.3.2.GA.jar:3.3.2.GA]
    at org.hibernate.tuple.entity.PojoEntityTuplizer.<init>(PojoEntityTuplizer.java:78) [hibernate-core-3.3.2.GA.jar:3.3.2.GA]
    at sun.reflect.GeneratedConstructorAccessor61.newInstance(Unknown Source) [na:1.8.0_25]
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) [na:1.8.0_25]
    at java.lang.reflect.Constructor.newInstance(Constructor.java:408) [na:1.8.0_25]
    at org.hibernate.tuple.entity.EntityTuplizerFactory.constructTuplizer(EntityTuplizerFactory.java:107) [hibernate-core-3.3.2.GA.jar:3.3.2.GA]
    at org.hibernate.tuple.entity.EntityTuplizerFactory.constructDefaultTuplizer(EntityTuplizerFactory.java:135) [hibernate-core-3.3.2.GA.jar:3.3.2.GA]
    at org.hibernate.tuple.entity.EntityEntityModeToTuplizerMapping.<init>(EntityEntityModeToTuplizerMapping.java:80) [hibernate-core-3.3.2.GA.jar:3.3.2.GA]
    at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:323) [hibernate-core-3.3.2.GA.jar:3.3.2.GA]
    at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:456) [hibernate-core-3.3.2.GA.jar:3.3.2.GA]
    at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:131) [hibernate-core-3.3.2.GA.jar:3.3.2.GA]
    at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:84) [hibernate-core-3.3.2.GA.jar:3.3.2.GA]
    at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:267) [hibernate-core-3.3.2.GA.jar:3.3.2.GA]
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1341) [hibernate-core-3.3.2.GA.jar:3.4.0.GA]
    at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:867) [hibernate-annotations-3.4.0.GA.jar:3.4.0.GA]
...
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4772) [catalina.jar:8.0.15]
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5196) [catalina.jar:8.0.15]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [catalina.jar:8.0.15]
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725) [catalina.jar:8.0.15]
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:701) [catalina.jar:8.0.15]
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:714) [catalina.jar:8.0.15]
    at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1585) [catalina.jar:8.0.15]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_25]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_25]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_25]
    at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_25]
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300) [tomcat-coyote.jar:8.0.15]
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) [na:1.8.0_25]
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) [na:1.8.0_25]
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:463) [catalina.jar:8.0.15]
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:413) [catalina.jar:8.0.15]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_25]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_25]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_25]
    at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_25]
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300) [tomcat-coyote.jar:8.0.15]
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) [na:1.8.0_25]
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) [na:1.8.0_25]
    at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1466) [na:1.8.0_25]
    at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76) [na:1.8.0_25]
    at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1307) [na:1.8.0_25]
    at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1399) [na:1.8.0_25]
    at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:828) [na:1.8.0_25]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_25]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_25]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_25]
    at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_25]
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:323) [na:1.8.0_25]
    at sun.rmi.transport.Transport$1.run(Transport.java:178) [na:1.8.0_25]
    at sun.rmi.transport.Transport$1.run(Transport.java:175) [na:1.8.0_25]
    at java.security.AccessController.doPrivileged(Native Method) [na:1.8.0_25]
    at sun.rmi.transport.Transport.serviceCall(Transport.java:174) [na:1.8.0_25]
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:557) [na:1.8.0_25]
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:812) [na:1.8.0_25]
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:671) [na:1.8.0_25]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_25]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_25]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]

cannot parse method body with parameterized Maps/Lists

I am trying to dynamically generate classes in my application and came across with this limitation/bug? with javassist.

Seems javassist cannot parse the source-body if it has Maps/List with parameterized types.

eg :

public static void main( String[] args ) throws Exception
    {
        ClassPool pool = ClassPool.getDefault();

        CtClass evalClass = pool.makeClass("Eval");

        evalClass.addMethod(
            CtNewMethod.make("public void test () { java.util.Map<java.lang.String, java.lang.String> tmp=null; }", evalClass));


        Class clazz = evalClass.toClass();
        Object obj = clazz.newInstance();

        Class[] formalParams = new Class[] { };
        Method meth = clazz.getDeclaredMethod("test", formalParams);
        Object[] actualParams = new Object[] {  };
         meth.invoke(obj, actualParams);


    }

This will give the error

Exception in thread "main" javassist.CannotCompileException: [source
error] ; is missing at
javassist.CtNewMethod.make(CtNewMethod.java:78) at
javassist.CtNewMethod.make(CtNewMethod.java:44)

but when I change the body to

public void test () { java.util.Map tmp=null; }

It works fine. Same applies to "List" .

Any tips? Is this a limitation or a bug ?

java.lang.VerifyError: Inconsistent stackmap frames at branch target

Getting VerifyError when trying to execute a static method in a generated class.

Using 3.20.0 with Java 1.8.0_51.

The generated code will compile and run with javac/java.

Here's the code:

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtMethod;
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
import javassist.Loader;
import javassist.NotFoundException;
import javassist.Modifier;

public class jA
{
  public static void fatal(String message)
  {
    System.err.println(message);
    System.exit(-1);
  }

  public static void main(String[] args)
  {
    ClassPool pool = ClassPool.getDefault();
    pool.importPackage("ts.Message");
    pool.importPackage("ts.support");

    CtClass theClass = pool.makeClass("test1");

    String theSignature = "public static void main(String args[])" + "{}";
    CtMethod theMethod = null;
    try {
      theMethod = CtNewMethod.make(theSignature, theClass);
    } catch (CannotCompileException ex) {
      fatal("cannot compile the generated main method signature: " +
        ex.getReason());
    }

  String theMethodBody = "";
  theMethodBody += "  {\n";
  theMethodBody += "    double var_tempCounter_0 = 0;\n";
  theMethodBody += "    boolean temp23 = true;\n";
  theMethodBody += "    boolean temp10 = true;\n";
  theMethodBody += "    while(temp10)\n";
  theMethodBody += "    {\n";
  theMethodBody += "      double temp11 = var_tempCounter_0;\n";
  theMethodBody += "      if(temp11 < 1.0)\n";
  theMethodBody += "        break;\n";
  theMethodBody += "    }\n";
  theMethodBody += "    while(temp23)\n";
  theMethodBody += "    {\n";
  theMethodBody += "        temp23 = false;\n";
  theMethodBody += "        double temp20 = var_tempCounter_0;\n";
  theMethodBody += "        boolean temp22 = temp20 < 1.0;\n";
  theMethodBody += "    }\n";
  theMethodBody += "  }\n";
    try {
      theMethod.setBody(theMethodBody);
    } catch (CannotCompileException ex) {
      fatal("cannot compile the generated main method body: " +
        ex.getReason());
    }

    try {
      theClass.addMethod(theMethod);
    } catch (CannotCompileException ex) {
      fatal("cannot add the main method into the main class: " +
        ex.getReason());
    }

    try {
      theClass.addConstructor(CtNewConstructor.defaultConstructor(theClass));
    } catch (CannotCompileException ex) {
      fatal("cannot add a default constructor to the main class: " +
        ex.getReason());
    }

    Loader classLoader = new Loader(pool);
    try {
      classLoader.run("test1", new String[0]);
    } catch (Throwable ex) {
      ex.printStackTrace();
      fatal("uncaught Java exception in execution of generated code:");
    }
  }
}

Here is the output:

java.lang.VerifyError: Inconsistent stackmap frames at branch target 48
Exception Details:
  Location:
    test1.main([Ljava/lang/String;)V @48: iconst_1
  Reason:
    Type top (current frame, locals[6]) is not assignable to double (stack map, locals[6])
  Current Frame:
    bci: @41
    flags: { }
    locals: { '[Ljava/lang/String;', double, double_2nd, integer, integer, top, top, double, double_2nd }
    stack: { integer }
  Stackmap Frame:
    bci: @48
    flags: { }
    locals: { '[Ljava/lang/String;', double, double_2nd, integer, integer, top, double, double_2nd }
    stack: { }
  Bytecode:
    0x0000000: 0387 4804 3e04 3604 a700 1027 3905 1805
    0x0000010: 0f98 9c00 06a7 0008 1504 9aff f1a7 0016
    0x0000020: 033e 2739 0718 070f 989b 0007 03a7 0004
    0x0000030: 0436 091d 9aff ecb1                    
  Stackmap Table:
    append_frame(@11,Double,Integer,Integer)
    same_frame(@24)
    same_frame(@29)
    same_frame(@32)
    append_frame(@48,Top,Double)
    same_locals_1_stack_item_frame(@49,Integer)
    chop_frame(@51,1)

    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
    at java.lang.Class.getDeclaredMethod(Class.java:2128)
    at javassist.Loader.run(Loader.java:288)
    at jA.main(jA.java:92)
uncaught Java exception in execution of generated code:

`

javassist.bytecode

Hi, I tried to use methodinfo in javassist.bytecode package.
But it prompts an error while compiling. (My javassist version is 3.20, jdk is 1.7.0-79)
Any suggestion of this error? Thank you.

error: cannot find symbol
import javassist.bytecode;
^
symbol: class bytecode
location: package javassist
1 error

Wrong method locals after method replacing

I'm trying to use Javassit in Android build with Maven. The orignial method is like this:

public class MyActivity extends Activity{
    public void onCreate(Bundle bundle){
        Log.d("...");
        super.onCreate(bundle);
        setUI();
    }

    public void setUI(){
        // businsess logic here ...
    }
}

I'd like to replace the invoke of setUI() to another static method:

public class InstrumentUtil{
    pubilc static void setUI(MyActivity m){
        // instrument logic at first ...
        m.setUI(); 
    }
}

The instrumentation code is like below:

CtMethod method = activityCtClz.getDeclaredMethod("onCreate", new CtClass[]{bundleCtClz});
method.instrument(new ExprEditor() {
            @Override
            public void edit(MethodCall m) throws CannotCompileException {
                if (m.getMethodName().equals("setUI")) {
                    m.replace("$_=com.example.testapp.InstrumentUtil.setUI($0);");
                }
            }
        });

However, the generated class bytecode is wrong at locals as below. The line below "Code" shows "locals=4" but the actual parameter number is 2, which causes "stack underflow" exception at dex phase in building time.

public void onCreate(android.os.Bundle);
    flags: ACC_PUBLIC
    Code:
      stack=2, **locals=4**, args_size=2
         0: ldc           #2                  // String vliux
         2: ldc           #3                  // String in MyActivity.onCreate()
         4: invokestatic  #4                  // Method android/util/Log.d:(Ljava/lang/String;Ljava/lang/String;)I
         7: pop           
         8: aload_0       
         9: aload_1       
        10: invokespecial #5                  // Method android/app/Activity.onCreate:(Landroid/os/Bundle;)V
        13: aload_0       
        14: astore_2      
        15: aload_2       
        16: invokestatic  #50                 // Method com/example/testapp/InstrumentUtil.setUI:(Lcom/example/testapp/MyActivity;)V
        19: astore_3      
        20: return        
      LineNumberTable:
        line 13: 0
        line 14: 8
        line 15: 13
        line 16: 20
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      21     0  this   Lcom/example/testapp/MyActivity;
               0      21     1 savedInstanceState   Landroid/os/Bundle;

More information:
The build step is that:

  1. the classes are compiled
  2. instrument class files with Javassist
  3. dex the generated class files with Android build tool
    Actually the "stack underflow" error was even reported during dexing. The stack trace is like blow, which might be helpful:
[INFO] Create dex file:/home/vliux/Code/alibaba/hurdle_jassist/testapp/target/classes to:/home/vliux/Code/alibaba/hurdle_jassist/testapp/target/classes.dex
Exception in thread "pool-16-thread-2" com.android.dx.cf.code.SimException: stack: underflow
    at com.android.dx.cf.code.ExecutionStack.throwSimException(ExecutionStack.java:341)
    at com.android.dx.cf.code.ExecutionStack.peek(ExecutionStack.java:206)
    at com.android.dx.cf.code.ExecutionStack.pop(ExecutionStack.java:253)
    at com.android.dx.cf.code.BaseMachine.popArgs(BaseMachine.java:130)
    at com.android.dx.cf.code.BaseMachine.popArgs(BaseMachine.java:157)
    at com.android.dx.cf.code.Simulator$SimVisitor.visitLocal(Simulator.java:591)
    at com.android.dx.cf.code.BytecodeArray.parseInstruction(BytecodeArray.java:524)
    at com.android.dx.cf.code.Simulator.simulate(Simulator.java:94)
    at com.android.dx.cf.code.Ropper.processBlock(Ropper.java:698)
    at com.android.dx.cf.code.Ropper.doit(Ropper.java:653)
    at com.android.dx.cf.code.Ropper.convert(Ropper.java:266)
    at com.android.dx.dex.cf.CfTranslator.processMethods(CfTranslator.java:284)
    at com.android.dx.dex.cf.CfTranslator.translate0(CfTranslator.java:141)
    at com.android.dx.dex.cf.CfTranslator.translate(CfTranslator.java:95)
    at com.android.dx.command.dexer.Main.processClass(Main.java:708)
    at com.android.dx.command.dexer.Main.processFileBytes(Main.java:660)
    at com.android.dx.command.dexer.Main.access$600(Main.java:81)
    at com.android.dx.command.dexer.Main$ParallelProcessor.run(Main.java:1576)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
...at bytecode offset 00000013
locals[0000]: Lcom/example/testapp/MyActivity;
locals[0001]: Landroid/os/Bundle;
locals[0002]: Lcom/example/testapp/MyActivity;
locals[0003]: <invalid>
...while working on block 0013
...while working on method onCreate:(Landroid/os/Bundle;)V
...while processing onCreate (Landroid/os/Bundle;)V
...while processing com/example/testapp/MyActivity.class

You see that there are 4 local variables after method replacing.
Did I make anything wrong in instrumentation?

NotFoundException on Android testcase

Hi,
When I user following lines in an android test case and run it as JUnit Android Test from eclipse than I get NotFoundException exception.
ClassPool classPool = ClassPool.getDefault();
classPool.get(URI.class.getName());

javassist.NotFoundException: java.net.URL
at javassist.ClassPool.get(ClassPool.java:450)
at com.example.search_app.test.factory.impl.SearchTaskFactoryImplTest.testExecuteOfProductSearchTask(SearchTaskFactoryImplTest.java:54)
at java.lang.reflect.Method.invokeNative(Native Method)
at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:204)
at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:194)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:520)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1447)

This is working perfectly when I downloaded the javassist code and added a new test case in it. To me problem seems that class path is not being initialized properly.

I would really appreciate it if you can guide me in how to fix this.

Thanks
Mohammad

Switch with string constant as a label: Exception: [source error] bad case label

Hi,

I'm using javassist 3.12.1.GA with java 8.
When I try to generate method with the switch statement, which uses string constant as a label, javassist presents the following exception: "Exception: [source error] bad case label"
However, generated source is correct and works (I checked it in a real java class).

For example, generated method body:

{
switch($1.getClass().getName()) {
case "example.EventA":
handler0.onEvent((example.EventA)$1);
break;
case "example.EventB":
handler1.onEvent((example.EventB)$1);
break;
}
}

Does javassist support switch statement with string label?

Verify exception with byte code for calling default methods

The following code throws a verify exception (java version is 1.8.0_77)

package test;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtNewMethod;
import javassist.NotFoundException;

public class JavassistTest {
    public static interface A {
        default int aMethod() {
            return 42;
        }
    }

    public static void main(String[] args) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException {
        ClassPool pool = ClassPool.getDefault();

        CtClass ctClass = pool.makeClass("test.Test");
        ctClass.addInterface(pool.get(A.class.getName()));

        ctClass.addMethod(CtNewMethod.make("public int aMethod() { return 1 + " + A.class.getName() + ".super.aMethod(); }", ctClass));

        Class klass = ctClass.toClass();
        klass.newInstance();
    }
}

The reported exception is:

Exception in thread "main" java.lang.VerifyError: Illegal type at constant pool entry 12 in class test.Test
Exception Details:
  Location:
    test/Test.aMethod()I @2: invokespecial
  Reason:
    Constant pool index 12 is invalid
  Bytecode:
    0x0000000: 042a b700 0c60 ac                      

    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2663)
    at java.lang.Class.getConstructor0(Class.java:3067)
    at java.lang.Class.newInstance(Class.java:408)
    at test.JavassistTest.main(JavassistTest.java:31)

Got NPE when replacing a method in `instrument()`

I'm trying to modify some code in static initializer with m.replace("$_ = ($r)false;"), but I got NPE:

Caused by: java.lang.NullPointerException
    at javassist.bytecode.ConstPool.getMethodrefNameAndType(ConstPool.java:418)
    at javassist.expr.MethodCall.getNameAndType(MethodCall.java:43)
    at javassist.expr.MethodCall.getMethodName(MethodCall.java:107)
    at com.github.gfx.javassistexamp.JavassistExample$2.edit(JavassistExample.groovy:29)
    at javassist.expr.ExprEditor.loopBody(ExprEditor.java:192)
    at javassist.expr.ExprEditor.doit(ExprEditor.java:91)
    at javassist.CtBehavior.instrument(CtBehavior.java:712)
    at javassist.CtBehavior$instrument.call(Unknown Source)

I guess it is because the static initializer has no method name, but ClassPool expects a method (behavior) should have a name.

ref. https://github.com/jboss-javassist/javassist/blob/master/src/main/javassist/bytecode/ConstPool.java#L418

FYI, I have correct results with the following patch:

diff --git a/src/main/javassist/bytecode/ConstPool.java b/src/main/javassist/bytecode/ConstPool.java
index f102421..9e62c89 100644
--- a/src/main/javassist/bytecode/ConstPool.java
+++ b/src/main/javassist/bytecode/ConstPool.java
@@ -265,6 +265,9 @@ public final class ConstPool {
      */
     public int getNameAndTypeName(int index) {
         NameAndTypeInfo ntinfo = (NameAndTypeInfo)getItem(index);
+        if (ntinfo == null) {
+            return 0;
+        }
         return ntinfo.memberName;
     }

@@ -415,6 +418,9 @@ public final class ConstPool {
      */
     public int getMethodrefNameAndType(int index) {
         MethodrefInfo minfo = (MethodrefInfo)getItem(index);
+        if (minfo == null) {
+            return 0;
+        }
         return minfo.nameAndTypeIndex;
     }

@@ -635,6 +641,9 @@ public final class ConstPool {
      */
     public String getUtf8Info(int index) {
         Utf8Info utf = (Utf8Info)getItem(index);
+        if (utf == null) {
+            return null;
+        }
         return utf.string;
     }

Adding to enums

public enum Title
{
One("One", 0, 1, "One", 1008, TitleType.NORMAL),
Two("Two", 1, 2, "Two", 1008, TitleType.NORMAL),
...............
}

How can I edit an enum method with javassist? There is nothing on the documentation about it.

Building from source gives error

Hi,

Since we are interested in a new release of javaassist. I forked and ran 'mvn install' ( using java 7).
Am I lacking anything?

br,

//mike

INFO] --- maven-compiler-plugin:3.3:testCompile (default-testCompile) @ javassist ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding ISO-8859-1, i.e. build is platform dependent!
[INFO] Compiling 241 source files to /home/eraonel/git/javassist/target/test-classes
[INFO] /home/eraonel/git/javassist/src/test/testproxy/ProxyFactoryPerformanceTest.java: Some input files use or override a deprecated API.
[INFO] /home/eraonel/git/javassist/src/test/testproxy/ProxyFactoryPerformanceTest.java: Recompile with -Xlint:deprecation for details.
[INFO] /home/eraonel/git/javassist/src/test/javassist/SetterTest.java: Some input files use unchecked or unsafe operations.
[INFO] /home/eraonel/git/javassist/src/test/javassist/SetterTest.java: Recompile with -Xlint:unchecked for details.
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] /home/eraonel/git/javassist/src/test/javassist/JvstTest4.java:[964,26] cannot find symbol
symbol: class Parameter
location: package java.lang.reflect
[ERROR] /home/eraonel/git/javassist/src/test/javassist/JvstTest4.java:[964,49] cannot find symbol
symbol: method getParameters()
location: variable m of type java.lang.reflect.Method
[INFO] 2 errors
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:01 min

Different behaviors against lambda expressions

I want to injecting a class to another class.
I tried to convert this class to a CtClass and find foo CtMethod and insert it to another CtClass

public class Template{
   void foo(){
           Runnable r = () -> {
            System.out.println("Hello world two!");
        };
   }
}

So it works properly.

But If I move r declaration to field statement , javassist throws CannotCompileException

public class Template{
           Runnable r = () -> {
            System.out.println("Hello world two!");
        }; 
}

So why this happens?

How to get method parameter names with javassist?

I want use this code to get parameter names:

CtMethod cm = cc.getDeclaredMethod(method.getName(), parameterCtClasses);
MethodInfo methodInfo = cm.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
for (int i = 0; i < parameterNames.length; i++) {
     parameterNames[i] = attr.variableName(i + pos);
}

But I found that in some situations, the java bytecode may like this:

  public void setOrg(com.hyxq.domain.Org);
LineNumberTable:
  line 275: 0
  line 277: 11
  line 278: 25
  line 279: 37
  line 280: 66
  line 281: 84
  line 282: 90
  line 283: 102
  line 284: 134
  line 285: 149
  line 288: 152
  line 289: 159
LocalVariableTable:
  Start  Length  Slot  Name   Signature
        66      18     3  role   Lcom/hyxq/domain/Role;
        47      40     2    i$   Ljava/util/Iterator; // I got this one
       134      15     3 roleId   I
       112      40     2    i$   Ljava/util/Iterator;
         0     160     0  this   Lcom/hyxq/service/RbacService;
         0     160     1   org   Lcom/hyxq/domain/Org; // I want to get this one

I got this bytecode with jdk1.7.60 on Linux. Then the previous code runs failure.
So, in this situation,how could I get the right parameter name?

Wrong handling of type casting

While using HTTL templating framework, I used Javassist as the template compiler. The templating framework generates a template class. This class can be compiled by JDK 8 with no issues. However, Javassist has a problem with the following method.

protected void doRenderWriter(httl.Context $context, java.io.Writer $output) throws java.lang.Exception {
httl.spi.Filter $filter = getFilter($context, "filter");
httl.spi.Filter filter = $filter;
httl.spi.formatters.MultiFormatter $formatter = getFormatter($context, "formatter");
httl.spi.formatters.MultiFormatter formatter = $formatter;
java.lang.Object hello = (java.lang.Object) $context.get("hello");
java.lang.Object ahoj = (java.lang.Object) $context.get("ahoj");
if (hello instanceof httl.Template) {
((httl.Template)hello).render($output);
} else {
Object $obj1 = (hello instanceof httl.Resource ? httl.util.IOUtils.readToString(((httl.Resource)hello).openReader()) : hello);
if ($obj1 instanceof char[]) $output.write(doFilter(filter, $TXT1, formatter.toChars($TXT1, (char[]) $obj1))); else $output.write(doFilter(filter, $TXT1, formatter.toString($TXT1, $obj1)));
}
$output.write($TXT3);
if ((((ahoj) != null ? (ahoj) : (1))) instanceof httl.Template) {
((httl.Template)(((ahoj) != null ? (ahoj) : (1)))).render($output);
} else {
Object $obj4 = ((((ahoj) != null ? (ahoj) : (1))) instanceof httl.Resource ? httl.util.IOUtils.readToString(((httl.Resource)(((ahoj) != null ? (ahoj) : (1)))).openReader()) : (((ahoj) != null ? (ahoj) : (1))));
if ($obj4 instanceof char[]) $output.write(doFilter(filter, $TXT4, formatter.toChars($TXT4, (char[]) $obj4))); else $output.write(doFilter(filter, $TXT4, formatter.toString($TXT4, $obj4)));
}
$output.write($TXT6);
$output.write(doFilter(filter, $TXT7, formatter.toString($TXT7, httl.util.ClassUtils.toInt(hello) - 1)));
$output.write($TXT8);
}

While parsing the lines
if ((((ahoj) != null ? (ahoj) : (1))) instanceof httl.Template) {
((httl.Template)(((ahoj) != null ? (ahoj) : (1)))).render($output);
Javassist throws CompileError "invalid cast". This is thrown at CodeGen:1429. Conditions for the exception are:
private String checkCastExpr(CastExpr expr, String name) // expr: (instanceof:307:0 ( httl Template) (<?:> (op:!= ahoj:307 id:412) ahoj:307 1)), name: httl/Template
throws CompileError
{
final String msg = "invalid cast";
ASTree oprand = expr.getOprand(); // operand: (<?:> (op:!= ahoj:307 id:412) ahoj:307 1)
int dim = expr.getArrayDim();
int type = expr.getType();
oprand.accept(this);
int srcType = exprType;
if (invalidDim(srcType, arrayDim, className, type, dim, name, true)
|| srcType == VOID || type == VOID) // dim: 0
throw new CompileError(msg);

    if (type == CLASS) { // type: 307
        if (!isRefType(srcType)) // srcType: 324
            throw new CompileError(msg);

I believe there is nothing wrong in the code and Javassist should handle that.

Javassist source code translator

Is there any source code translator which translates a given source code into javassist compatible code. For example, I understand javassist cannot intercept final methods. The translator should be able to translate a final class into functional equivalent non final class.

I understand that this is not right way to ask such question. But I couldnt find any javassist interest forumn. Any help is highly appreciated.

AspectJ concrete aspect class not found

When using Javassist together with AspectJ. The concrete aspect defined in aop.xml is generated dynamically at runtime. Due to the way LoaderClassPath#find() is implemented, it was trying to look up the class by doing the following, but the defined class is not part of the original Jar and hence result in NotFoundException.

public URL find(String classname) {
        String cname = classname.replace('.', '/') + ".class";
        ClassLoader cl = (ClassLoader)clref.get();
        if (cl == null)
            return null;        // not found
        else
            return cl.getResource(cname);
    }

propose patches:

  1. the find method can check if the class is loaded by the loader and return a dummy URL. Or
  2. define a new check method within ClassPool such as:
private boolean isClassLoaded(String classname) {
    ClassLoader cl = (ClassLoader)clref.get();
        if (cl == null)
            return false;        // not found
        else{
             try{
                  cl.loadClass(classname);
                  return true;
             }
             catch(ClassNotFoundException e) {
                     return false; 
            }
        }
}

and add this check in:

protected CtClass createCtClass(String classname, boolean useCache) {
        // accept "[L<class name>;" as a class name. 
        if (classname.charAt(0) == '[')
            classname = Descriptor.toClassName(classname);

        if (classname.endsWith("[]")) {
            String base = classname.substring(0, classname.indexOf('['));
            if ((!useCache || getCached(base) == null) && find(base) == null 
&& !isClassLoaded(base))  // add the check
                return null;
            else
                return new CtArray(classname, this);
        }
        else
            if (find(classname) == null && !isClassLoaded(classname))  //add the check
                return null;
            else
                return new CtClassType(classname, this);
    }

lamda expressions - compile exception

When trying to use lambda in setBody string, i get this (the problem is this line:

$CONSTRUCTORS.put("key", new Function<Integer, Probna>() {
public Probna apply(Integer ordinal) {
//more code that returns new Probna(ordinal);
}
});

Same problem happens if i use (ordinal) -> new Probna(ordinal);

Exception in thread "main" javassist.CannotCompileException: [source error] syntax error near "Function<Integer, Pr"
at javassist.CtBehavior.setBody(CtBehavior.java:446)
at javassist.CtBehavior.setBody(CtBehavior.java:412)
at DynamicEnumOld.makeDynamic(DynamicEnumOld.java:104)
at DynamicEnumOld.main(DynamicEnumOld.java:11)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: compile error: syntax error near "Function<Integer, Pr"
at javassist.compiler.Parser.parseNew(Parser.java:1293)
at javassist.compiler.Parser.parsePrimaryExpr(Parser.java:1244)
at javassist.compiler.Parser.parsePostfix(Parser.java:1031)
at javassist.compiler.Parser.parseUnaryExpr(Parser.java:888)
at javassist.compiler.Parser.parseBinaryExpr(Parser.java:775)
at javassist.compiler.Parser.parseConditionalExpr(Parser.java:719)
at javassist.compiler.Parser.parseExpression(Parser.java:699)
at javassist.compiler.Parser.parseArgumentList(Parser.java:1332)
at javassist.compiler.Parser.parseMethodCall(Parser.java:1180)
at javassist.compiler.Parser.parsePostfix(Parser.java:1036)
at javassist.compiler.Parser.parseUnaryExpr(Parser.java:888)
at javassist.compiler.Parser.parseBinaryExpr(Parser.java:775)
at javassist.compiler.Parser.parseConditionalExpr(Parser.java:719)
at javassist.compiler.Parser.parseExpression(Parser.java:699)
at javassist.compiler.Parser.parseDeclarationOrExpression(Parser.java:591)
at javassist.compiler.Parser.parseStatement(Parser.java:277)
at javassist.compiler.Parser.parseBlock(Parser.java:289)
at javassist.compiler.Parser.parseStatement(Parser.java:243)
at javassist.compiler.Javac.compileBody(Javac.java:214)
at javassist.CtBehavior.setBody(CtBehavior.java:438)
... 8 more

Can not setBoby defaultMethod. (Java8)

ex : setBody("{ ... InterfaceName.super.method($$); }");

javassist.CannotCompileException: [source error] missing member name
    at javassist.CtBehavior.setBody(CtBehavior.java:446)
    at javassist.CtBehavior.setBody(CtBehavior.java:412)
    at javassist.CtNewMethod.make(CtNewMethod.java:138)
    at org.seasar.framework.aop.javassist.AbstractGenerator.createMethod(AbstractGenerator.java:465)
    ... 25 more
Caused by: compile error: missing member name
    at javassist.compiler.Parser.parsePostfix(Parser.java:1069)
    at javassist.compiler.Parser.parseUnaryExpr(Parser.java:888)
    at javassist.compiler.Parser.parseCast(Parser.java:918)
    at javassist.compiler.Parser.parseUnaryExpr(Parser.java:886)
    at javassist.compiler.Parser.parseBinaryExpr(Parser.java:775)
    at javassist.compiler.Parser.parseConditionalExpr(Parser.java:719)
    at javassist.compiler.Parser.parseExpression(Parser.java:699)
    at javassist.compiler.Parser.parseReturn(Parser.java:507)
    at javassist.compiler.Parser.parseStatement(Parser.java:269)
    at javassist.compiler.Parser.parseBlock(Parser.java:289)
    at javassist.compiler.Parser.parseStatement(Parser.java:243)
    at javassist.compiler.Javac.compileBody(Javac.java:214)
    at javassist.CtBehavior.setBody(CtBehavior.java:438)
    ... 28 more

getDeclaredMethod with multiple methods of same name

Hello @chibash ,

would it be possible to add a method in CtClass to retrieve all methods of a given name. Actually the behavior of getDeclaredMethod when there are multiple overloads is to return one of them. It would be nice to have methods like :

public List<CtMethod> getDeclaredMethods(String name);
public CtMethod getDeclaredMethod(String name, Class paramerType...);

(Btw, you should close the issues on github when processed)

The method SerialVersionUID.calculateDefault() should be public

Currently the method SerialVersionUID.calculateDefault() is package protected. Making it public would allow clients of the library to calculate the serialVersionUID without manipulating the instance of CtClass. This helps libraries like japicmp to determine if the default serialVersionUID of a class has changed.

More complex generic example

Documentation has only one example about using generics.

I couldn't find on internet how extend a class that defines more than one generic parameter
using javassist.

I have a class that I want to extend at runtime using javassist, but generic parameter need to exists at runtime for reflection (hibernate needs it).

So, I´m not posting this issue to get a response for my problem.

The issue is true, have no documentation and examples with use of generics in the real world (extends, implements, < T extends MyType < X < V > > , X, V >).

Support for Javaflow bytecode pattern

The Apache Javaflow project instruments class files to provide its Continuation capability. One of the bytecode patterns it generates to handle Category 2 parameters is:

NEW
DUP
DUP2_X2
POP2

Unfortunately, when Javassist sees this pattern when moving instructions, it recognizes the NEW DUP and removes it in order to do the move. However, this leaves the DUP2_X2 POP2 abandoned which leads to stack corruption and javassist throwing an exception due to a negative stack height.

Given this involves Category 2 operands, there is not much short of a complete rearchitecting that can be done in Javaflow to accommodate the existing Javassist patterns for NEW. Therefore, I ask the the above bytecode pattern be added to the javassist.expr.NewExpr.canReplace() method. I will submit a patch with the proposed change.

The reason javassist might end up manipulating a Javaflow instrumented class file is through the use of Powermock, which uses javassist to create mocks. Using Powermock to mock Javaflow instrumented classes results in javassist being used against those class.

Pull request #21 has been submitted.

Deadlock in getDeclaredMethods

javassist.CtClassType.removeClassFile(CtClassType.java:266)
javassist.CtClassType.compress(CtClassType.java:237)
javassist.ClassPool.compress(ClassPool.java:288)
javassist.CtClassType.getClassFile2(CtClassType.java:177)
javassist.CtClassType.makeFieldCache(CtClassType.java:873)
javassist.CtClassType.getMembers(CtClassType.java:864)
   - locked javassist.CtClassType@6bf3da51
javassist.CtClassType.getDeclaredMethods(CtClassType.java:1211)
sun.reflect.GeneratedMethodAccessor323.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:497)
org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
org.codehaus.groovy.runtime.metaclass.MethodMetaProperty$GetBeanMethodMetaProperty.getProperty(MethodMetaProperty.java:73)
org.codehaus.groovy.runtime.callsite.GetEffectivePojoPropertySite.getProperty(GetEffectivePojoPropertySite.java:61)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:227)

Skip synthetic methods

Hi,

I've been trying to write some code to skip synthetic methods, however does not seem to be working.
suppose I have the following class:

public class SyntheticExample {
  public static void main(String[] args) {
    System.out.println(SyntheticExample.class);
  }
}

Compiling it with Java 1.4 (yeah, it has to be 1.4) I get the following bytecode:

$ javac -source 1.4 -target 1.4 SyntheticExample.java
$ javap -v SyntheticExample

public class SyntheticExample
  flags: ACC_PUBLIC, ACC_SUPER

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC

  static java.lang.Class class$(java.lang.String);
    flags: ACC_STATIC
    Synthetic: true

and here the code to skip synthetic methods:

for (CtMethod cb : ct.getDeclaredMethods()) {
  if ( (cb.getMethodInfo().getAccessFlags() & AccessFlag.SYNTHETIC) != 0 ) {
     continue;
  }
  // do stuff
}

it seems that cb.getMethodInfo().getAccessFlags() is returning 8 (i.e., AccessFlag.STATIC) and cb.getMethodInfo().getAccessFlags() & AccessFlag.SYNTHETIC returns 0, for method "class$".

am I doing something wrong? how can I identify (and skip) synthetic methods?

-- Thanks in advance.

Class is frozen exception while isFrozen returns false

I am trying to implement a simple, proof of concept compile time instrumentation with javaassist embedded in a maven plugin.

I have sample compiled classes and trying to use addLocalVariable, insertBefore and instertAfter methods, very simple and straightforward;

for (String className : classes) {
            className = className.replace (classname + "/", "").replace ("/", ".").replace (".class", "");
            modifiedClasses.add (className);
            getLog ().info ("Distilled class name: " + className);
        }

        for (String className : modifiedClasses) {

            CtClass cc;
            try {
                cc = classPool.get (className);

                getLog().info("Class: " + cc.getSimpleName() + " is frozen ? : " + cc.isFrozen());

            } catch (NotFoundException e) {
                e.printStackTrace ();
                continue;
            }

            if (cc.isAnnotation ()
                    || cc.isInterface ())
                continue;

            CtMethod[] methods = cc.getDeclaredMethods ();

            for (CtMethod ctMethod : methods) {

                try {

                    ctMethod.addLocalVariable ("executionStarted", CtClass.longType);
                    ctMethod.insertBefore ("executionStarted = System.currentTimeMillis ();");
                    ctMethod.insertAfter ("{final long executionFinished = System.currentTimeMillis ();"
                            + "System.out.println(\"Execution in ms: \" + (executionFinished-executionStarted));}");

                    cc.writeFile (".");

                } catch (Throwable e) {
                    getLog ().error ("Error on class: "
                            + cc.getName ()
                            + " for method: "
                            + ctMethod.getName ());
                    getLog ().error (e);
                }
            }

Class is definitely not frozen;

[info] Class: SomeClass is frozen ? : false

But still I am getting class is frozen exception all over the place. I couldn't move on the maven plugin phase yet, execution environment is not Maven, just a dummy main method.

[error] Error on class: com.xxxx.utils.logging.SomeClass for method: setSomeString
[error] java.lang.RuntimeException: com.xxxx.utils.logging.SomeClass class is frozen
    at javassist.CtClassType.checkModify(CtClassType.java:294)
    at javassist.CtBehavior.addLocalVariable(CtBehavior.java:582)
    at com.xxxx.maven.plugins.TracerMavenPlugin.optimize(TracerMavenPlugin.java:138)
    at com.xxxx.maven.plugins.TracerMavenPlugin.execute(TracerMavenPlugin.java:75)
    at com.xxxx.maven.plugins.TracerMavenPlugin.main(TracerMavenPlugin.java:38)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

JDK 1.7.0_67
3.20.0-GA

Class unavailable to ClassLoader crashes JavaAssist

Use case: An Android library with optional dependencies provide some methods that are only callable if the user provide the dependency themselves. While a bit unconventional it helps to save both file size and methods which are important on Android.

Example:

public class Foo {
  // Methods

 // Method requiring RxJava as dependency. If people never call this method, they don't have to include RxJava
 public rx.Observable asObservable() {
   // returns an RxJava observable
 }

Normally users don't encounter problems as anyone trying to call the asObservable method from their IDE will get compile time warnings and they can add the dependency.

Problem:
However JavaAssist is used by tools like PowerMock when writing unit tests. JavaAssist unfortunately seem to throw a hard exception if it encounters a class it cannot load:

Caused by: javassist.NotFoundException: rx.Observable
    at javassist.ClassPool.get(ClassPool.java:450)
    at javassist.bytecode.Descriptor.toCtClass(Descriptor.java:592)
    at javassist.bytecode.Descriptor.getReturnType(Descriptor.java:489)
    at javassist.CtBehavior.getReturnType0(CtBehavior.java:306)
    at javassist.CtMethod.getReturnType(CtMethod.java:219)

I am a bit uncertain if this is something that should be solved at the JavaAssist level or if it is a library problem (e.g. PowerMock needs to handle it).

Obtained incorrect original parameter name of method by MethodInfo API

We just want to build a simple log system , create an Spring aspect in order to capture all request parameter's value(certainly require original parameter's name defined inside method to match).Since JDK doesn't provide API to parse the orginal parameter name defined in Java code , we take advantage of javassist to do that . If I use JDK 1.7.0_51 to build my program, could obtain correct parameter's name from java bytecode Method's constant pool by Javassist API and then match the values . But if use JDK1.6.0_31, i cann't get the correct result (find the order of parameter inside bytecode is incorrect , some parameter's name such as "e" or "$i" are in front of the array of constant pool instead of the intend parameter defined inside method). I try to use other java bytecode view tool to check if the index of localVariabletable built by JDK 1.6.0_31 is not as same as JDK 1.7.0_51 , but i find they are the same , no difference. I am not sure if my program has some mistakes by using javassist API , the following is segment of my code :
/**
*
* @param targetClass the fullname of the specific targetClass
* @param targetMethodName the method name defined in the above class
* @return
*/
private String[] getMethodVariableNames(String targetClass, String targetMethodName) {
Class<?> clazz = null;
try {
clazz = Class.forName(targetClass);
} catch (ClassNotFoundException e) {
logger_biz.error("call getMethodVariableNames system error!", e);
}
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(clazz));
CtClass cc;
CtMethod cm = null;
try {
if (null == clazz) {
return null;
}
cc = pool.get(clazz.getName());
cm = cc.getDeclaredMethod(targetMethodName);
} catch (NotFoundException e) {
logger_biz.error("call getMethodVariableNames system error!", e);
}
if (null == cm) {
return null;
}
MethodInfo methodInfo = cm.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
String[] variableNames = new String[0];
try {
variableNames = new String[cm.getParameterTypes().length];
} catch (NotFoundException e) {
logger_biz.error("call getMethodVariableNames system error!", e);
}
int staticIndex = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
for (int i = 0; i < variableNames.length(); i++)
variableNames[i] = attr.variableName(i + staticIndex);
return variableNames;
}

ClassCastException on Stream.of

I am using 3.19.0-GA as part of a Play 2.3.3 instance, with Java 8_45.

If I include a call to Stream.of("") anywhere in my code, I get the following error from javassist:

java.lang.ClassCastException: javassist.bytecode.InterfaceMethodrefInfo cannot be cast to javassist.bytecode.MethodrefInfo
at javassist.bytecode.ConstPool.getMethodrefType(ConstPool.java:452)
at javassist.bytecode.stackmap.Tracer.doInvokeMethod(Tracer.java:800)
at javassist.bytecode.stackmap.Tracer.doOpcode148_201(Tracer.java:597)
at javassist.bytecode.stackmap.Tracer.doOpcode(Tracer.java:81)
at javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:187)
at javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:164)
at javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:108)
at javassist.bytecode.MethodInfo.rebuildStackMap(MethodInfo.java:423)
at javassist.bytecode.MethodInfo.rebuildStackMapIf6(MethodInfo.java:405)
at javassist.expr.ExprEditor.doit(ExprEditor.java:113)
at javassist.CtBehavior.instrument(CtBehavior.java:712)
at play.core.enhancers.PropertiesEnhancer.rewriteAccess(PropertiesEnhancer.java:156)
at play.PlayCommands$$anonfun$PostCompile$1$$anonfun$9.apply(PlayCommands.scala:98)
at play.PlayCommands$$anonfun$PostCompile$1$$anonfun$9.apply(PlayCommands.scala:98)
at scala.collection.TraversableLike$$anonfun$filter$1.apply(TraversableLike.scala:264)
at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:47)
at scala.collection.TraversableLike$class.filter(TraversableLike.scala:263)
at scala.collection.AbstractTraversable.filter(Traversable.scala:105)
at play.PlayCommands$$anonfun$PostCompile$1.apply(PlayCommands.scala:98)
at play.PlayCommands$$anonfun$PostCompile$1.apply(PlayCommands.scala:75)
at scala.Function8$$anonfun$tupled$1.apply(Function8.scala:35)
at scala.Function8$$anonfun$tupled$1.apply(Function8.scala:34)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:42)
at sbt.std.Transform$$anon$4.work(System.scala:64)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
at sbt.Execute.work(Execute.scala:244)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

Removing the Stream.of("") causes the file to be processed successfully.

Note that this does not occur with Stream.of("foo", "bar"). It is only an issue with the singleton version of Stream.of.

Is there any class that javassist can't process?

Hi Chibash,
I don't know whether it is polite to ask for problems of using javassist here, but this one really doesn't make sense.
I'm trying to do something to enhance the sun.security.ssl.X509TrustManangerImpl using this fantastic tool. But it does work properly. I provide test case to reproduce the problem. I used the
-javaagent option to modify the class before it is used.
I will insert "com.CertShim.Dog.bark()" to each method. Here it the bark code:

package com.CertShim;
public class Dog{
    public static void bark(){
        System.out.println("Dog.");
    }
}

Test case 1:
This is used to demonstrate that it works in an ordinary class.

CallTest.java

public class CallTest{
    public static void main(String[] args){
        com.CertShim.Dog.bark();
    }
}

Agent.java

package com.CertShim;
import javassist.*;
import java.lang.instrument.*;
import java.security.ProtectionDomain;
public class Agent{
    public static void premain(String agentArgs, Instrumentation inst){
        inst.addTransformer(new TestDog());
    }
}

class TestDog implements ClassFileTransformer{
    @Override
    public byte[] transform(ClassLoader classLoader, String className, Class<?> arg2, ProtectionDomain arg3, byte[] bytes)
    throws IllegalClassFormatException{
        ClassPool pool=ClassPool.getDefault();
        CtClass curClass;
        String code="com.CertShim.Dog.bark();";
        CtMethod method;
        try{
            if(!className.equals("CallTest"))
                return null;
            curClass=pool.get(className.replace('/', '.'));
            method=curClass.getDeclaredMethod("main");
            method.insertBefore(code);
            return curClass.toBytecode();
        }catch(Exception e){
            System.out.println("Compile fail.");
            return null;
        }

    }
}

This will produce the correct output, i.e. two "Dog." on the screen.

Test case 2:
This will produce the problem.

Agent2.java

package com.CertShim;
import javassist.*;
import java.lang.instrument.*;
import java.security.ProtectionDomain;
public class Agent2{
    public static void premain(String agentArgs, Instrumentation inst){
        inst.addTransformer(new TestDog2());
    }
}

class TestDog2 implements ClassFileTransformer{
    @Override
    public byte[] transform(ClassLoader classLoader, String className, Class<?> arg2, ProtectionDomain arg3, byte[] bytes)
    throws IllegalClassFormatException{
        ClassPool pool=ClassPool.getDefault();
        CtClass curClass;
        CtMethod method;
        String class1="sun/security/ssl/X509TrustManagerImpl";
        //Revising the following class inorder to force the checkIdentity method called.
        String class2="javax/net/ssl/SSLParameters";
        try{
            if(!className.equals(class1)&&!className.equals(class2))
                return null;
            curClass=pool.get(className.replace('/', '.'));
            if(className.equals(class1)){
                method=curClass.getDeclaredMethod("checkIdentity");
                method.insertBefore("com.CertShim.Dog.bark();");
                return curClass.toBytecode();
            }else{
                method=curClass.getDeclaredMethod("setEndpointIdentificationAlgorithm");
                method.insertBefore("if($1==null) $1=\"HTTPS\";");
                return curClass.toBytecode();
            }
        }catch(Exception e){
            System.out.println("Compile fail.");
            return null;
        }

    }
}

SSLSocketClient.java

This code simply build a ssl connection to some website. Nothing special. It will call ssl api and thus call the checkIdentity.

import javax.net.ssl.*;
import java.io.*;
import java.net.*;
import java.security.*;

public class SSLSocketClient {

  public static void main(String args[]) throws Exception {

    String urlString = (args.length == 1) ? 
      args[0] : "http://twitter.com";
    URL url = new URL(urlString);

    Security.addProvider(
      new com.sun.net.ssl.internal.ssl.Provider());

    SSLSocketFactory factory = 
      (SSLSocketFactory)SSLSocketFactory.getDefault();
    SSLSocket socket = 
      (SSLSocket)factory.createSocket(url.getHost(), 443);

    /* Print the SSL parameter - algorithm */
    SSLParameters sslPara = socket.getSSLParameters();
    System.out.println("getCipherSuites(): " +
        sslPara.getCipherSuites() + "\n" +
        "getNeedClientAuth(): " +
        sslPara.getNeedClientAuth() + "\n" +
        "getProtocols(): " +
        sslPara.getProtocols() + "\n" +
        "getWantClientAuth(): " +
        sslPara.getWantClientAuth() + "\n" +
        "getEndpointIdentificationAlgorithm() [1.7]: " +
        sslPara.getEndpointIdentificationAlgorithm()
        );

    PrintWriter out = new PrintWriter(
        new OutputStreamWriter(
          socket.getOutputStream()));
    out.println("GET " + urlString + " HTTP/1.1");
    out.println();
    out.flush();

    BufferedReader in = new BufferedReader(
      new InputStreamReader(
      socket.getInputStream()));

    String line;

    //while ((line = in.readLine()) != null) {
   //   System.out.println(line);
   // }

    out.close();
    in.close();
  }
}

Here is the exception output. I tried to print the current classpath and the result is correct. I just can't
figure out why it can't find my class.
Exception in thread "main" java.lang.NoClassDefFoundError: com/CertShim/Dog
at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:203)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1323)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:702)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:295)
at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141)
at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229)
at java.io.PrintWriter.flush(PrintWriter.java:320)
at SSLSocketClient.main(SSLSocketClient.java:50)

Thanks.

CtClass.getDeclaredMethods() returns duplicated methods

As stated in the documentation, CtClass.getDeclaredMethods() should return only methods declared in the class, not the inherited ones. When I try to get the methods declared in java.lang.StringBuffer, I get some duplicated methods. Test case :

ClassPool p = ClassPool.getDefault();
CtClass clazz = p.get("java.lang.StringBuffer");
CtMethod[] methods = clazz.getDeclaredMethods();
for (CtMethod method : methods) {
System.out.println(method);
}

I get for example these two methods in the console:
javassist.CtMethod@77c141ce[public synchronized append (I)Ljava/lang/StringBuffer;]
javassist.CtMethod@77c141ce[public volatile append (I)Ljava/lang/AbstractStringBuilder;]

java.lang.AbstractStringBuilder seems to be an internal class, but I don't understand why I get these duplicated methods.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.