jboss-javassist / javassist Goto Github PK
View Code? Open in Web Editor NEWJava bytecode engineering toolkit
Home Page: www.javassist.org
License: Other
Java bytecode engineering toolkit
Home Page: www.javassist.org
License: Other
Hello,
this is more a question than a bug report:
Is Javassist fully java 8 compliant?
If it claims to be, please have a look at this stackoverflow question.
There might be a problem with Javassist and java 8's lambda expressions.
Thank you.
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.
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.
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:
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);
}
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.
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;
}
Greetings @chibash,
Can you please let us know the estimated release date of javassist 3.20-GA?
We are waiting for the fix https://issues.jboss.org/browse/JASSIST-241 in the new release of javassist
Regards
Abed
I guess there was a similar thread posted around 2 years ago. Happens when I am including the name of the class I am writing test case for in @PrepareForTest annotation. I am using javassist 3.20 jar. When I exclude the class name in the annotation, my mocked object isn't getting passed and the real constructor is being called instead.
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]
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).
Classes, methods and fields can be marked by the compile with the property flags ACC_BRIDGE and ACC_SYNTHETIC (see The class file format). In order to query if this flag is set or not, the class javassist.Modifier
should provide the methods isBridge()
and isSynthetic()
.
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
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
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.
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:
`
"(Object) $_" causes "invalid cast" when the return value is a byte array.
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.
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 ?
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.
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:
Thanks and kind regards
Maria Beurer
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
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.
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.
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)
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
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.
I want to remove a certain annotation from CtField, but I couldn't find any methods for this purpose.
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?
For what reason do you suppose classpool implementation is fixed? A pool can be implemented in many ways:)
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?
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
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)
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
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:
[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?
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
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!
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)
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?
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.
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
Many projects on GH use Travis for continuous integration. One big advantage is to get a build for every PR, so you can get sure not to break the build when merging other contrib's stuff.
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)
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;
}
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
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 >).
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.
public class CallTest{
public static void main(String[] args){
com.CertShim.Dog.bark();
}
}
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.
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;
}
}
}
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.
When will this version be released? Mainly because it fix #13.
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.
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.
The CtClass#hasAnnotation(String clazzName) and CtMember#hasAnnotation(String clazzName) are required because a classpath in ClassPool for java assist doesn't equal to the classpath(loader?) of driving thread. I've already refactored. I can send a pull request for this issue.
would you consider adding support for Runtime[In]VisibleTypeAnnotations?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.