使用Objensis创建静态内部类实例时出现java.lang.InstanceOnError
我试图创建一个实用方法,应该能够深度克隆任何对象。 (使用Objensis创建静态内部类实例时出现java.lang.InstanceOnError,java,reflection,objenesis,Java,Reflection,Objenesis,我试图创建一个实用方法,应该能够深度克隆任何对象。 (Object.clone()仅适用于对象实现Cloneable,我听说它有缺陷。) 我使用创建对象的新实例,而不使用构造函数 但是,在尝试克隆JFrame时,出现以下异常: (使用这个类是因为我认为它应该是一个好的、复杂的测试) 我对任何解决方案都持开放态度,不一定局限于Objenesis 我的代码: private static ObjenesisStd OBJENESIS = new ObjenesisStd(); @SuppressW
Object.clone()
仅适用于对象实现Cloneable
,我听说它有缺陷。)
我使用创建对象的新实例,而不使用构造函数
但是,在尝试克隆JFrame时,出现以下异常:
(使用这个类是因为我认为它应该是一个好的、复杂的测试) 我对任何解决方案都持开放态度,不一定局限于Objenesis 我的代码:
private static ObjenesisStd OBJENESIS = new ObjenesisStd();
@SuppressWarnings("unchecked")
public static <T> T clone(T object, boolean deep){
if(object == null){
return null;
}else{
try {
T clone = (T) OBJENESIS.newInstance(object.getClass());
List<Field> fields = ReflectionUtil.getAllFieldsInHierarchy(object.getClass());
for(Field field : fields){
boolean isAccessible = field.isAccessible();
boolean isFinal = ReflectionUtil.isFinal(field);
field.setAccessible(true);
ReflectionUtil.setFinal(field, false);
Class<?> type = field.getType();
if(!deep || type.isPrimitive() || type == String.class){
field.set(clone, field.get(object));
}else{
field.set(clone, clone(field.get(object), true));
}
field.setAccessible(isAccessible);
ReflectionUtil.setFinal(field, isFinal);
}
return clone;
} catch (Throwable e) {
e.printStackTrace();
//throw new RuntimeException("Failed to clone object of type " + object.getClass(), e);
return null;
}
}
}
public static void main(String[] args) {
GetterSetterAccess access = new GetterSetterAccess(JFrame.class);
JFrame frame = new JFrame("Test Frame");
for(String attr : access.getAttributes()){
System.out.println(attr + " " + access.getValue(frame, attr));
}
System.out.println("----------------------------------------------");
frame = clone(frame, true);
for(String attr : access.getAttributes()){
System.out.println(attr + " " + access.getValue(frame, attr));
}
}
private static ObjenesisStd OBJENESIS=new ObjenesisStd();
@抑制警告(“未选中”)
公共静态T克隆(T对象,布尔深度){
if(object==null){
返回null;
}否则{
试一试{
T clone=(T)OBJENESIS.newInstance(object.getClass());
列表字段=ReflectionUtil.getAllFieldsInHierarchy(object.getClass());
用于(字段:字段){
布尔值isAccessible=field.isAccessible();
布尔值isFinal=ReflectionUtil.isFinal(字段);
字段。setAccessible(true);
ReflectionUtil.setFinal(字段,false);
类类型=field.getType();
如果(!deep | | type.isPrimitive()| | type==String.class){
set(克隆,field.get(对象));
}否则{
set(克隆,克隆(field.get(object),true));
}
字段设置可访问(可访问);
ReflectionUtil.setFinal(字段,isFinal);
}
返回克隆;
}捕获(可丢弃的e){
e、 printStackTrace();
//抛出新的RuntimeException(“克隆类型为“+object.getClass(),e”的对象失败);
返回null;
}
}
}
公共静态void main(字符串[]args){
GetterSetterAccess访问=新的GetterSetterAccess(JFrame.class);
JFrame框架=新JFrame(“测试框架”);
for(字符串attr:access.getAttributes()){
System.out.println(attr+“”+access.getValue(frame,attr));
}
System.out.println(“-------------------------------------------------------------”;
frame=克隆(frame,true);
for(字符串attr:access.getAttributes()){
System.out.println(attr+“”+access.getValue(frame,attr));
}
}
编辑:让它与接受的答案和一些其他修复一起工作:
- 避免克隆基元类型的包装器(
等)Integer.class
- 避免克隆类(类的对象
)class.class
- 将克隆的对象存储在地图中并重用它们,因此如果对象a引用对象B,对象B引用对象a,则不会陷入无限循环。我还使用了一个检查精确相等的映射(
),而不是使用==
equals()
- 创建了一个自定义的异常类,该类只会被传递,而不是在每个级别上抛出一个新的异常(由深度引起的巨大异常)
- 我终于明白了。您的代码不处理数组。因此,实例化节点数组“[Ljava.util.concurrent.ConcurrentHashMap$Node;”失败
但是,我主张,实际上,您不应该这样做。您将得到相当复杂的代码。根据您想要做什么,您可以使用Jackson或XStream进行marshall/unmarshall来执行复制
如果您确实想继续该路径,那么在对
clone
方法进行空检查之后,您将需要类似的内容
if(object.getClass().isArray()) {
int length = Array.getLength(object);
Object array = Array.newInstance(object.getClass().getComponentType(), length);
for (int i = 0; i < length; i++) {
Array.set(array, i, clone(Array.get(object, i), true));
}
return (T) array;
}
if(object.getClass().isArray()){
int length=Array.getLength(对象);
对象数组=array.newInstance(Object.getClass().getComponentType(),长度);
for(int i=0;i
我终于明白了。您的代码不处理数组。因此,实例化节点数组“[Ljava.util.concurrent.ConcurrentHashMap$Node;”失败
但是,我主张,实际上,您不应该这样做。您将得到相当复杂的代码。根据您想要做什么,您可以使用Jackson或XStream进行marshall/unmarshall来执行复制
如果您确实想继续该路径,那么在对clone
方法进行空检查之后,您将需要类似的内容
if(object.getClass().isArray()) {
int length = Array.getLength(object);
Object array = Array.newInstance(object.getClass().getComponentType(), length);
for (int i = 0; i < length; i++) {
Array.set(array, i, clone(Array.get(object, i), true));
}
return (T) array;
}
if(object.getClass().isArray()){
int length=Array.getLength(对象);
对象数组=array.newInstance(Object.getClass().getComponentType(),长度);
for(int i=0;i
它应该可以很好地工作。您使用的是哪个Objensis版本以及哪个JVM和版本?Objensis 3.0.1和JDK 1.8.0\u 212将其更改为Objensis 2.5和JDK 1.6.0\u 25(因为我更希望它与Java 6兼容)它仍然不起作用。Objensis 2.6的发行说明是“放弃Java 5支持”,所以我认为Java 6应该与以前的版本一起工作。克隆这样复杂的对象是非常糟糕的,而且你没有跳过静态字段。克隆这样的对象会有很多问题,我可以理解这样的解决方案简单的beans/dto类。是的,我知道,我也不打算克隆Swing对象,因为这可能会破坏Swing。我只是使用JFrame,因为我知道这是对象可以得到的最复杂的东西,我希望它能适用于所有事情。但是我确实需要一个能够克隆映射的克隆方法,这是这里失败的地方。静态ReflectionUtil.GetAllFieldsHierarchy(我自己的实用程序)已经删除了字段。它应该可以很好地工作。您使用的是哪个Objensis版本,以及哪个JVM和版本?Ob