0

大家好 ——我正在看一个名为“吃蛋糕也吃蛋糕:Java 中的元编程”的演示文稿

演示者是 Tapestry 的作者 Howard M. Lewis Ship(其中之一?)——在制作过程中,创建了一个名为“plastic”的子项目,以利用 ASM 更改字节码。

我不会假装自己是专家,但最终结果应该是我可以编写代码,以便可以使用带注释的类、方法和字段来生成更多的 java 代码,从而减少样板代码。

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

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

com.example.plastic.transformed.EqualsDemo cannot be cast to com.example.plastic.transformed.EqualsDemo
        at MainClass.main(MainClass.java:28)

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

PS!到目前为止,我发现的示例都使用了我认为是 Groovy 的注释实例的最终用途。

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

链接:Tapestry 主页(塑料以罐子形式包含在下载中):http ://tapestry.apache.org/

主.java

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

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

import com.example.plastic.transformer.EqualsHashCodeTransformer;
import com.example.plastic.transformed.EqualsDemo;

public class MainClass {

    public static void main(String[] args) {


        List<String> pList = new ArrayList<String>();
        pList.add("com.example.plastic.transformed");

        PlasticManager pm = PlasticManager
                .withContextClassLoader()
                .delegate( new StandardDelegate(new EqualsHashCodeTransformer()) )
                .packages(pList)
                .create();


        final String EQUALSDEMO = "com.example.plastic.transformed.EqualsDemo";
        ClassInstantiator<EqualsDemo> i = pm.getClassInstantiator(EQUALSDEMO);
        i.newInstance().hashCode();
        /*
        com.example.plastic.transformed.EqualsDemo cannot be cast to com.example.plastic.transformed.EqualsDemo
        at MainClass.main(MainClass.java:28)
        */
    }
}

实现EqualsHashCode.java

package com.example.plastic.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ImplementEqualsHashCode {

}

EqualsHashCodeTransformer.java

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;
            }
        });
    }
}

等于Demo.java

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;
    }
}
4

2 回答 2

1

您不想将包添加到塑料管理器中——它使用不同的类加载器并将加载这些类,在这些包中制作两个类的副本(一个在父类加载器中,一个在塑料类加载器中),这将当框架尝试投射到你的类时,给你你看到的 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());
   }
}
于 2012-07-12T17:46:16.373 回答
0

我想而不是

PlasticManager.withContextClassLoader()...

使用以下内容应该可以解决您的问题:

PlasticManager.withClassLoader(getClass().getClassLoader())...
于 2012-06-06T20:23:08.950 回答