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