2017-05-08 7 views
0

アプリケーションを再コンパイルせずにメソッド(計算式)を変更する必要があります。私はこれがジャワシストの助けを借りてできることを知っています。これまで私は単純な例を試しています。 postメソッドでは、createMethodHelper()メソッドを呼び出します。このメソッドは、Helper2メソッドを変更する必要があります。大丈夫。しかし、繰り返しコール(ページをリロード)、エラーjavassist.CannotCompileException後:java.lang.LinkageErrorのことで:だからローダー 、私はそこからjava javassist.CannotCompileException:java.lang.LinkageError:loader

package ru.testScandJavaCafee.controller; 

public class Helper2 { 
public String createList() 
    { 
     System.out.println("++++"); 
     return "1000"; 
    } 
} 

とクラスを変更する唯一の方法を含むクラス私は、エラーを修正する方法を理解するために2回目の呼び出し(リロードページ)、エラー

javassist.CannotCompileException: by java.lang.LinkageError: loader (instance of org/apache/catalina/loader/WebappClassLoader): attempted duplicate class definition for name: "ru/testScandJavaCafee/controller/Helper2" 
    at javassist.ClassPool.toClass(ClassPool.java:1085) 
    at javassist.ClassPool.toClass(ClassPool.java:1028) 
    at javassist.ClassPool.toClass(ClassPool.java:986) 
    at javassist.CtClass.toClass(CtClass.java:1110) 
    at ru.testScandJavaCafee.controller.CoffeeTypeController.createMethodHelper(CoffeeTypeController.java:108) 
    at ru.testScandJavaCafee.controller.CoffeeTypeController.doPost(CoffeeTypeController.java:56) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:650) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:731) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218) 
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:110) 
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506) 
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169) 
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) 
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:962) 
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) 
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:452) 
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1087) 
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637) 
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 
    at java.lang.Thread.run(Thread.java:745) 
Caused by: java.lang.LinkageError: loader (instance of org/apache/catalina/loader/WebappClassLoader): attempted duplicate class definition for name: "ru/testScandJavaCafee/controller/Helper2" 
    at java.lang.ClassLoader.defineClass1(Native Method) 
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763) 
    at java.lang.ClassLoader.defineClass(ClassLoader.java:642) 
    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:498) 
    at javassist.ClassPool.toClass2(ClassPool.java:1098) 
    at javassist.ClassPool.toClass(ClassPool.java:1079) 
    ... 27 more 

助けた後方法

public String createMethodHelper() throws NotFoundException, CannotCompileException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, InstantiationException, ClassNotFoundException { 

     ClassPool pool = ClassPool.getDefault(); 
pool.insertClassPath(new ClassClassPath(this.getClass())); 
     CtClass cc = pool.get("ru.testScandJavaCafee.controller.Helper2"); 
     cc.defrost(); 
     CtMethod cm = cc.getMethod("createList","()Ljava/lang/String;"); 
     cc.defrost(); 
     cm.setBody("{ return \"300 \" ;}"); 

     cc.defrost(); 
     Class c = cc.toClass(); 
     cc.defrost(); 
ru.testScandJavaCafee.controller.Helper2 test = (ru.testScandJavaCafee.controller.Helper2) c.newInstance(); 
     String sum = test.createList(); 

     return sum; 
    } 

を変更する

+0

重複したクラス定義 'name:" ru/testScandJavaCafee/controller/Helper2 "'に対して重複したクラス定義が試行されました。 – SubOptimal

+0

似たようなテーマがありますが、私のプロジェクトにどのように適用するのか分かりませんhttp://stackoverflow.com/questions/23336172/adding-an-annotation-to-a-runtime-generated-class-using-javassist –

答えて

0

私はdocumentationtutorialからこれに関するいくつかの調査を行いました。そして、あなたが方法を変更するために複数回をしたい場合、あなたはこのようにそれを行うことができます。

public static void main(String[] args) { 
    try { 
     // get a new instance of version 1 
     Object newClassInstance1 = m2("com.tima.Helper2", "public String createList() { System.out.println(\"++++\"); return \"200\";}"); 
     Method method1 = newClassInstance1.getClass().getMethod("createList"); 

     // this executes the createList in the new class com.tima.Helper2 
     String sum1 = (String) method1.invoke(newClassInstance1); 
     System.out.println("com.tima.Helper2: " + sum1); 

     // this shows that the original Helper method was not modified 
     Helper h = new Helper(); 
     System.out.println("com.tima.Helper: " + h.createList()); 

     // this shows that the com.tima.Helper2 overrides Helper and can be used as Helper with a modified method 
     Helper h2 = (Helper) newClassInstance1; 
     System.out.println("com.tima.Helper2 as Helper: " + h2.createList()); 

     // below does the same thing a second time 

     Object newClassInstance2 = m2("com.tima.Helper3", "public String createList() { System.out.println(\"++++\"); return \"300\";}"); 
     Method method2 = newClassInstance2.getClass().getMethod("createList"); 
     String sum2 = (String) method2.invoke(newClassInstance2); 
     System.out.println("com.tima.Helper3: " + sum2); 

     Helper h3 = new Helper(); 
     System.out.println("com.tima.Helper: " + h3.createList()); 

     Helper h4 = (Helper) newClassInstance2; 
     System.out.println("com.tima.Helper3 as Helper: " + h4.createList()); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

public static Object m2(String className, String methodBody) 
     throws CannotCompileException, InstantiationException, IllegalAccessException, NotFoundException { 
    // get the pool 
    ClassPool classPool = ClassPool.getDefault(); 

    // this seems optional, but if it isn't Main.class (my test class) should be replaced with this.getClass() 
    classPool.insertClassPath(new ClassClassPath(Main.class)); 

    // get the helper class 
    CtClass helperClass = classPool.get("com.tima.Helper"); 

    // create a new class 
    CtClass newCtClass = classPool.makeClass(className); 

    // make it child of Helper 
    newCtClass.setSuperclass(helperClass); 

    // this overrides the method in Helper 
    newCtClass.addMethod(CtNewMethod.make(methodBody, newCtClass)); 

    // get a new instance 
    Class<?> newClass = newCtClass.toClass(); 
    Object newClassInstance = newClass.newInstance(); 

    return newClassInstance; 
} 

出力

++++ 
com.tima.Helper2: 200 
++++ 
com.tima.Helper: 1000 
++++ 
com.tima.Helper2 as Helper: 200 
++++ 
com.tima.Helper3: 300 
++++ 
com.tima.Helper: 1000 
++++ 
com.tima.Helper3 as Helper: 300 

は基本的に、あなたはそれが新しいクラスを作成し、そのメソッドを呼び出すたびに、Helperクラスを作りますそのスーパークラスであり、createListメソッドをオーバーライドします。明らかな問題は、このメソッドを何度呼び出すかによって生成されるクラスがたくさんあることになります。したがって、作成する前にこれらのクラスが既にロードされているかどうかのチェックを追加することができます。

このメソッドは、ページをリフレッシュ/ロードするときに実行されるので、一度だけ実行したい場合は、このコードをアプリケーションの起動時に実行されるシングルトンに入れることをお勧めします。私はあなたがWebアプリケーション用に何を使用しているのか分かりませんが、JSFとSpringはどちらもこのタイプの使用のためのシングルトンBeanを持っています。

関連する問題