简体   繁体   English

使用Objenesis创建静态内部类的实例时出现java.lang.InstantiationError

[英]java.lang.InstantiationError when creating instance of static inner class with Objenesis

I am trying to create a utility method that should be able to deep-clone any object. 我正在尝试创建一个实用程序方法,该方法应该能够深克隆任何对象。 ( Object.clone() only works on Object implementing Cloneable and I heard it's flawed anyways.) Object.clone()仅在实现Cloneable对象上起作用,我听说它还是有缺陷的。)

I am using Objenesis to create new instances of objects without the use of constructors. 我正在使用Objenesis来创建对象的新实例,而无需使用构造函数。

However, when trying to clone a JFrame I get the following Exception: 但是,当尝试克隆JFrame时,出现以下异常:
(using this class because I think it should be a good and complex test) (使用该类,因为我认为这应该是一个很好且复杂的测试)

java.lang.InstantiationError: [Ljava.util.concurrent.ConcurrentHashMap$Node;
    at sun.reflect.GeneratedSerializationConstructorAccessor12.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
    at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)

I am open to any solution, not necessarily limited to Objenesis. 我对任何解决方案持开放态度,不一定仅限于Objenesis。

My Code: 我的代码:

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

EDIT: Got it to work with the accepted answer and a few more fixes: 编辑:得到了它与接受的答案和一些其他修复一起使用:

  • Avoided cloning Wrappers of Primitive Types ( Integer.class etc.) 避免克隆原始类型的包装器( Integer.class等)
  • Avoided cloning Classes (Objects of the class Class.class ) 避免克隆类( Class.class类的对象)
  • Stored the cloned objects in a Map and reused them, so if Object A has a reference to Object B and Object B one to Object A it doesn't get stuck in an infinite loop. 将克隆的对象存储在Map中并重用它们,因此,如果对象A引用对象B,对象B引用对象A,则不会陷入无限循环。 I also used a Map that checks for exact equality ( == ) instead of using equals() . 我还使用了一个检查完全相等( == )的Map,而不是使用equals()
  • Created a custom exception class which would just be passed on instead of throwing a new exception on every level (causing a huge caused-by-depth). 创建了一个自定义的异常类,该类将被传递,而不是在每个级别上引发新的异常(导致大量的由深度引起的)。

I finally figured it out. 我终于弄明白了。 Your code doesn't handle arrays. 您的代码无法处理数组。 So it fails with instantiating "[Ljava.util.concurrent.ConcurrentHashMap$Node;" 因此,由于实例化“ [Ljava.util.concurrent.ConcurrentHashMap $ Node;”而失败。 which is an array of Nodes. 这是一个节点数组。

However, I will advocate that indeed, you should not do that. 但是,我会主张,实际上,您不应该这样做。 You will end up with fairly complicated code. 您将得到相当复杂的代码。 Depending on what you want to do, you could use Jackson or XStream to do a marshall / unmarshall to perform the copy. 根据您要执行的操作,可以使用Jackson或XStream进行编组/解组来执行复制。

If you really want to continue that path, you will need something like this after the null check of your clone method. 如果您确实想继续该路径,则在对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;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM