Touya Akira
Touya Akira

Reputation: 311

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

Upvotes: 0

Views: 3306

Answers (2)

Touya Akira
Touya Akira

Reputation: 311

Thank you all for the help for my question,I've removed the clone method, I just applied reflection.Hi @dabaicai.Your code helped me with the idea,I thought passing the value to the private field would be easier a little.

public static <T> T clazzClone(T t) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
        Class<?> clazzRoot = t.getClass();

        Object newInstance = clazzRoot.newInstance();
        Field[] fieldsClone = newInstance.getClass().getDeclaredFields();
        for (Field fieldClone : fieldsClone) {
            fieldClone.setAccessible(true);
            fieldClone.set(newInstance, getContent(t, fieldClone.getName()));
        }
        return (T) newInstance;
    }

    private static String getContent(Object aClass, String name) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        Field declaredField = aClass.getClass().getDeclaredField(name);
        declaredField.setAccessible(true);
        return (String) declaredField.get(aClass);
    }

My program means when I need to edit user input data to output the results I want,with a common filter function

 fieldClone.set(newInstance,methodYourEdit(getContent(t, fieldClone.getName())));

Upvotes: 3

dabaicai
dabaicai

Reputation: 999

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.

Upvotes: 1

Related Questions