使用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