2

In Java, I have a method that modifies properties of object to according to the corresponding properties of the object from.

public static void shape(SomeType from, SomeType to) {
    to.setA( from.getA() );
    to.setB( from.getB() );
    to.setC( from.getC() );
    ...
}

I can imagine that this task/idiom is recurring so often in software development that it both is given a name and also has existing libraries that can take care of doing it automatically for me. Do you know about any such libraries?

Abdull
  • 26,371
  • 26
  • 130
  • 172
  • 2
    Are you looking for [`Copy Constructors`](http://en.wikipedia.org/wiki/Copy_constructor)? – Rohit Jain Feb 02 '13 at 21:55
  • 1
    @RohitJain "Copy constructor" as in C++? Both objects referenced by `from` and `to` already exist, so a copy constructor would create a new object but not change the object `to` that I intend to change. Notice that in my case, `to` can be referenced to at other places as well. – Abdull Feb 02 '13 at 22:29

5 Answers5

2

I would not want such a library. Your objects could end up having lots of unexpected state. As others said, use Copy Constructor.

In general, if you can afford it, strive for immutability when transitioning state. It usually makes reasoning about the problem easier and reduces the risk of side effects. A good example of this is joda time which makes heavy use of immutability.

nansen
  • 2,912
  • 1
  • 20
  • 33
1

The usual way this is done is just using copy constructors or copy methods.

public SomeType(SomeType other)
{
  a = other.a;
  b = other.b;
  c = other.c;
}

public void copy(SomeType other)
{
  a = other.a;
  b = other.b;
  c = other.c;
}

I'm not sure whether anyone would actually do this in practice, but you could theoretically use reflection to automate the process (getMethods may be a good start). Apart from possible performance issues (no idea how fast this is), the main problem I would imagine is that this could result in data you don't want copied to be copied, which is especially likely when multiple people work on the same code.

Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
1

I don't think there is a general solution to this. Perhaps AOP could help but this would probably be a bad practice.

If you want to copy all the data of the object and they are of the same class then the implementor of the class may implement Cloneable interface and you may just call clone().

And if classes differ then only you know which members of the source object should be copied to which members of the target one. And copying them one-by-one is the simplest and most readable method of doing this.

There is also a problem of "shallow" or "deep" copy of members, out of scope of the question but worth remembering.

Grzegorz
  • 504
  • 1
  • 3
  • 14
  • No general solution!? OP appears to be asking for a way to copy an object! – Dave Feb 02 '13 at 22:08
  • A solution should solve and not complicate. I think that using any library to do such things obscures readability of code and - as said in other responses - can backfire by copying unneeded data. – Grzegorz Feb 02 '13 at 22:15
  • Of course, unless you have dynamically generated classes and don't know the members at compile time... – Grzegorz Feb 02 '13 at 22:16
  • @Dave In my ( == OP's) specific case, I'm not looking for a copy of an object (depending on the meaning of copy). Both objects `to` and `from` already exist, so Java's Object.clone() semantics (which, by contract, "create"/construct a new object) don't apply either. – Abdull Feb 02 '13 at 22:18
  • @Grzegorz Good catch on the "library" part of the question; I didn't see that until now. – Dave Feb 02 '13 at 22:20
  • @Abdull I'm not sure this is a common problem. At a minimum, I've never experienced it. It sounds like you want to "merge" two objects. Is that correct? – Dave Feb 02 '13 at 22:21
1

This has allready ask beford here. Look at Copy all values from fields in one class to another through reflection .

I've used dozer - but got back to using copy constructors as mentioned by @dukeling.

Community
  • 1
  • 1
Dirk Lachowski
  • 3,121
  • 4
  • 40
  • 66
  • Thanks! While the question you are refering to differs from mine (potentially private fields versus public properties), the answers there seem to be promising to apply to my question too! I will check them out; especially the suggestion `org.apache.commons.beanutils.BeanUtilscopyProperties(Object dest, Object orig)` seems promising... – Abdull Feb 02 '13 at 22:25
0

Try to implement cloneable interface

public class SomeType implements Cloneable {
    private String a;

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    public Object clone() {
        try {
            return super.clone();
        } catch(CloneNotSupportedException e) {
            System.out.println("Cloning not allowed.");
            return this;
        }
    } 
}

and you can test this::

public class Test {

    public static void main (String args[]) {
        SomeType a = new SomeType();
        SomeType b = (SomeType) a.clone();
        if ( a == b ) {
            System.out.println( "yes" );
        } else {
            System.out.println( "no" );
        }
    }

}

yes, you can try with reflection if the object types are different, but keep in mind that the names of the attributes must be equal

and this is the answer using reflection, with this class you can pass all the parameters from one object to another, regardless of type as long as the names of methods and attributes are the same.

package co.com;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class SetAttributes {

public static String capitalize( String word ) {
    return Character.toUpperCase( word.charAt( 0 ) ) + word.substring( 1 );
}

public static void setAttributes( Object from, Object to ) {
    Field [] fieldsFrom = from.getClass().getDeclaredFields();
    Field [] fielsdTo = to.getClass().getDeclaredFields();
    for (Field fieldFrom: fieldsFrom) {
        for (Field fieldTo: fielsdTo) {
            if ( fieldFrom.getName().equals( fieldTo.getName() ) ) {
                try {
                    Method [] methodsTo = to.getClass().getDeclaredMethods();
                    for ( Method methodTo: methodsTo ) {
                        if ( methodTo.getName().equals( "set" + capitalize( capitalize( fieldTo.getName() ) ) ) ) {
                            Method methodFrom = from.getClass().getDeclaredMethod( "get" + capitalize( fieldFrom.getName() ), null );
                            methodTo.invoke(to, methodFrom.invoke( from, null ) );
                            break;
                        }
                    }
                } catch (SecurityException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
            System.err.println( fieldFrom );
        }
    }
}

public static void main (String args[]) {
    SomeType a = new SomeType();
    SomeType b = new SomeType();
    a.setA( "This" );
    setAttributes( a, b );
    System.err.println( b.getA() );
}

}
jdurango
  • 533
  • 1
  • 4
  • 15