Java 在使用塑料框架生成代码时遇到棘手的ClassCastException

Java 在使用塑料框架生成代码时遇到棘手的ClassCastException,java,classloader,Java,Classloader,这是怎么回事 大家好,我正在看一个名为“吃蛋糕,也吃蛋糕:Java元编程”的演示文稿 演示者是Tapestry的作者之一Howard M.Lewis Ship,在制作过程中,制作了一个名为“塑料”的子项目,以利用ASM修改字节码 我不会假装是专家,但最终的结果应该是我可以编写代码,这样就可以使用带注释的类、方法和字段生成进一步的java代码,从而减少样板代码 我的问题 下面的代码是一个完整的例子来演示我的问题。测试示例应该修改EqualsDemo类,使其包含equals()和hashCode()

这是怎么回事 大家好,我正在看一个名为“吃蛋糕,也吃蛋糕:Java元编程”的演示文稿

演示者是Tapestry的作者之一Howard M.Lewis Ship,在制作过程中,制作了一个名为“塑料”的子项目,以利用ASM修改字节码

我不会假装是专家,但最终的结果应该是我可以编写代码,这样就可以使用带注释的类、方法和字段生成进一步的java代码,从而减少样板代码

我的问题 下面的代码是一个完整的例子来演示我的问题。测试示例应该修改EqualsDemo类,使其包含equals()和hashCode()的实现。 当运行它时,我得到一个错误,它基本上表明我不能将“com.example.plastic.transformed.EqualsDemo”类型的对象强制转换为“com.example.plastic.transformed.EqualsDemo”(是的,相同的类)

演示者刚刚提到,这些错误很烦人,但没有提到它们的来源——到目前为止,我的搜索表明它们属于不同的类加载器。 然而,我完全无法解决这个问题,因此我的问题在这里(!)

那么我需要做什么呢?替换类加载器?(如果是的话,怎么做?)或者有没有我没有得到的塑料部分?生成代理对象或类似对象的一些方法,我需要使用这些方法才能使事情顺利进行

PS! 到目前为止,我发现的示例都在最后使用带注释的实例时使用了我认为是Groovy的东西

希望有人比我更有能力:)

链接: Tapestry主页(塑料作为一个罐子包含在下载中):

主类 EqualsHashCodeTransformer.java 我想不是

PlasticManager.withContextClassLoader()...
使用以下方法可以解决您的问题:

PlasticManager.withClassLoader(getClass().getClassLoader())...

您不想将包添加到plastic manager中——它使用不同的类加载器并加载这些类,在这些包中创建两个类副本(一个在父类加载器中,一个在plastic类加载器中)当框架试图向您的类强制转换时,您将看到ClassCastException。请尝试以下方法:

import org.apache.tapestry5.internal.plastic.StandardDelegate;
import org.apache.tapestry5.plastic.ClassInstantiator;
import org.apache.tapestry5.plastic.PlasticManager;

public class MainClass {

  public static void main(String[] args) {
      PlasticManager pm = PlasticManager
            .withContextClassLoader()
            .delegate(new StandardDelegate())
            .create();
      ClassInstantiator<EqualsDemo> ci = pm.createClass(EqualsDemo.class, new EqualsHashCodeTransformer());
      System.out.println(ci.newInstance().hashCode());
   }
}
import org.apache.tapestry5.internal.plastic.StandardDelegate;
导入org.apache.tapestry5.plastic.ClassInstallator;
导入org.apache.tapestry5.plastic.PlasticManager;
公共类主类{
公共静态void main(字符串[]args){
塑料管理器pm=塑料管理器
.withContextClassLoader()
.delegate(新的StandardDelegate())
.create();
ClassInstallator ci=pm.createClass(EqualsDemo.class,新EqualsHashCodeTransformer());
System.out.println(ci.newInstance().hashCode());
}
}

.withClassLoader(Thread.currentThread().getContextClassLoader())
将不起作用,
EqualsDemo.class.getClassLoader()
getClass().getClassLoader()
似乎不起作用,因为我无法将getClass视为静态方法。关于
getClass()
的说法是对的,我错过了。但至少
EqualsDemo.class.getClassLoader()
应该可以工作。。。嗯……哦,是的,我可能不太清楚这一部分,
EqualsDemo.class.getClassLoader()
起作用,但仍然会导致相同的ClassCastException。
package com.example.plastic.transformer;

import java.util.ArrayList;
import java.util.List;

import org.apache.tapestry5.plastic.FieldHandle;
import org.apache.tapestry5.plastic.MethodAdvice;
import org.apache.tapestry5.plastic.MethodDescription;
import org.apache.tapestry5.plastic.MethodInvocation;
import org.apache.tapestry5.plastic.PlasticClass;
import org.apache.tapestry5.plastic.PlasticClassTransformer;
import org.apache.tapestry5.plastic.PlasticField;

import com.example.plastic.annotations.*;

public class EqualsHashCodeTransformer implements PlasticClassTransformer {
    private MethodDescription EQUALS = new MethodDescription("boolean", "equals", "java.lang.Object");

    private MethodDescription HASHCODE = new MethodDescription("int", "hashCode");

    private static final int PRIME = 37;

    public void transform(PlasticClass plasticClass){

        //check that the class is annotated
        if(!plasticClass.hasAnnotation(ImplementEqualsHashCode.class)) {
            return;
        }

        List<PlasticField> fields = plasticClass.getAllFields();


        final List<FieldHandle> handles = new ArrayList<FieldHandle>();
        for(PlasticField field : fields){
            handles.add(field.getHandle());
        }

        //HashCode method introduction :)
        plasticClass.introduceMethod(HASHCODE).addAdvice(new MethodAdvice() {
            public void advise(MethodInvocation invocation){
                Object instance = invocation.getInstance();
                int result = 1;

                for(FieldHandle handle : handles){
                    Object fieldValue = handle.get(instance);

                    if(fieldValue != null)
                        result = (result * PRIME) + fieldValue.hashCode();
                }

                invocation.setReturnValue(result);

                //Don't proceed to the empty introduced method
            }

        });

        plasticClass.introduceMethod(EQUALS).addAdvice(new MethodAdvice() {
            public void advise(MethodInvocation invocation) {
                Object thisInstance = invocation.getInstance();
                Object otherInstance = invocation.getParameter(0);

                invocation.setReturnValue(isEqual(thisInstance, otherInstance));

                //Don't proceed to the empty introduced method
            }

            private boolean isEqual(Object thisInstance, Object otherInstance) {

                if(thisInstance == otherInstance)
                    return true;

                if(otherInstance == null)
                    return false;

                if(!(thisInstance.getClass() == otherInstance.getClass())) 
                    return false;

                for(FieldHandle handle : handles){
                    Object thisValue = handle.get(thisInstance);
                    Object otherValue = handle.get(otherInstance);

                    if(!(thisValue == otherValue || thisValue.equals(otherValue)))
                        return false;
                }

                return true;
            }
        });
    }
}
package com.example.plastic.transformed;

import com.example.plastic.annotations.ImplementEqualsHashCode;


@ImplementEqualsHashCode
public class EqualsDemo {
    private int intValue;
    private String stringValue;

    public int getIntValue(){
        return intValue;
    }

    public void setIntValue(int intValue){
        this.intValue = intValue;
    }

    public String getStringValue(){
        return stringValue;
    }

    public void setStringValue(String stringValue){
        this.stringValue = stringValue;
    }
}
PlasticManager.withContextClassLoader()...
PlasticManager.withClassLoader(getClass().getClassLoader())...
import org.apache.tapestry5.internal.plastic.StandardDelegate;
import org.apache.tapestry5.plastic.ClassInstantiator;
import org.apache.tapestry5.plastic.PlasticManager;

public class MainClass {

  public static void main(String[] args) {
      PlasticManager pm = PlasticManager
            .withContextClassLoader()
            .delegate(new StandardDelegate())
            .create();
      ClassInstantiator<EqualsDemo> ci = pm.createClass(EqualsDemo.class, new EqualsHashCodeTransformer());
      System.out.println(ci.newInstance().hashCode());
   }
}