有什么关系 大家好 - 我正在看一个名为“有你的蛋糕并且也吃它的演示文稿:Java中的元编程”
主持人是Tapestry的作者Howard M. Lewis Ship(一个?),并且在制作时,一个名为“塑料”的子项目被用来利用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主页(塑料在下载中包含在jar中):http://tapestry.apache.org/
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)
*/
}
}
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 {
}
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;
}
}
答案 0 :(得分: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());
}
}
答案 1 :(得分:0)
我想而不是
PlasticManager.withContextClassLoader()...
使用以下内容可以解决您的问题:
PlasticManager.withClassLoader(getClass().getClassLoader())...