Search code examples
javareflectionclone

Java reflection with clone


Example I have data layer after

public class DemoData implements Cloneable {

    private String name;
    private String value;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); //To change body of generated methods, choose Tools | Templates.
    }
}

I want to assign data values (DemoData) to a duplicate data (DemoData clone) layer as follows

public static void main(String[] args) {
        DemoData demoData = new DemoData();
        demoData.setName("Class Sources");
        testReflectionDemo(demoData);
    }

    private static DemoData testReflectionDemo(DemoData demoData) {
        try {
            DemoData clone = (DemoData) demoData.clone();
            clone.setName(demoData.getName());
            clone.setValue(demoData.getValue());
            return clone;
        } catch (CloneNotSupportedException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

I want to convert the method testReflectionDemo(DemoData demoData) to method testReflectionDemo(T t) reflection as shown below.I do not know how to continue, please help me

public <T> T testReflectionDemo(T t){
        Class<?> aClass = t.getClass();
        for (Method method : aClass.getMethods()) {

        }
        return null;
    }

Solution

  • If the argument of testReflectionDemo is a javabean,it means that the class of argument have several a pair method of setXXX and 'getXXX,and thegetXXXdon't have argument,thesetXXX` just have one argument.If is this,the following code can copy the property from old object to new object.

        Class<?> aClass = t.getClass();
        Object result = aClass.newInstance();
        Map<String,MethodHolder> map=new HashMap<>();
        for (Method method : aClass.getMethods()) {
            if(method.getName().startsWith("get") && method.getParameterTypes().length==0){
                String property=method.getName().substring(3);
                MethodHolder hodler = map.get(property);
                if(hodler ==null){
                    map.put(property, new MethodHolder(property, method, null));
                    continue;
                }
                hodler.getMethod=method;
            }else if (method.getName().startsWith("set") && method.getParameterTypes().length==1) {
                String property=method.getName().substring(3);
                MethodHolder holder = map.get(property);
                if(holder ==null){
                    map.put(property, new MethodHolder(property, null, method));
                    continue;
                }
                holder.setMethod=method;
            }
        }
        List<MethodHolder> collect = map.values().stream().filter(item -> item.setMethod != null && item.getMethod != null).collect(Collectors.toList());
        for (MethodHolder holder : collect) {
            Object property = holder.getMethod.invoke(t);
            holder.setMethod.invoke(result,property);
        }
        return (T)result;
    

    The MethodHolder just have some field:

    public static class MethodHolder{
        private String property;
        private Method getMethod;
        private Method setMethod;
    
        public MethodHolder() {
        }
    
        public MethodHolder(String property, Method getMethod, Method setMethod) {
            this.property = property;
            this.getMethod = getMethod;
            this.setMethod = setMethod;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof MethodHolder)) return false;
            MethodHolder that = (MethodHolder) o;
            return Objects.equals(property, that.property);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(property);
        }
    }
    

    Pay attention of that the following code just make shallow copy.