5

I have two Objects of same type.I want to create a method which can merge the properties of two object and can return a single object.

For Example: Consider a class ABC having 4 fields

Class ABC{
String name;
String id;
String salary;
String status;
}

Suppose the first object is

ABC[name=ZEE,id=2,salary=null,status=1]

and the second object is

ABC[name=john,id=null,salary=12200,status=null]

I want to make a generic method which can merge these two objects and can give result output as:

ABC[name=ZEE,id=2,salary=12200,status=1]

The method Should take two parameters of Object type:

Object  mergeObject(Object Obj1, Object Obj2){
}

Note: It will take the first object property if both the objects have non-null value for that property.

Deepak Kumar
  • 1,669
  • 3
  • 16
  • 36
  • 10
    what happened to `john` – Uma Kanth Jun 11 '15 at 13:24
  • How will you handle collisions? e.g. `Obj1` has a field and so does `Obj2`. Depending on that logic, just setup some accessor/mutator (getter/setter) methods for the class variables and in your `mergeObject` method, create a new object and set fields as you go by checking `Obj1` vs. `Obj2` – Avantol13 Jun 11 '15 at 13:26
  • 1
    Generic as "will work for all objects"? This is not going to be possible. Consider enums, for example. Even getting close will require some serious reflection stunts. – RealSkeptic Jun 11 '15 at 13:27
  • And what have you done so far yourself? Besides writing up this question? You understand you don't just drop your requirements here; and other people do your work? – GhostCat Jun 11 '15 at 13:27
  • This isn't genericity, and this isn't good programming – Dici Jun 11 '15 at 13:30
  • Seriously, **what happened to** `john` as a name on collision? The second object's value was overridden.... is this intended behavior? – EpicPandaForce Jun 11 '15 at 13:31
  • It will take the first object property if both the objects have non-null value for that property. – Deepak Kumar Jun 11 '15 at 13:31
  • @jsonwilczak that is not generic one – Deepak Kumar Jun 11 '15 at 13:33

4 Answers4

19

You're going to have to go the reflection route. I'm assuming you have a default constructor, otherwise the following won't work. Also, it needs two same types. It won't copy inherited fields, for that, you also need to add some code from here.

@SuppressWarnings("unchecked")
public static <T> T mergeObjects(T first, T second) throws IllegalAccessException, InstantiationException {
    Class<?> clazz = first.getClass();
    Field[] fields = clazz.getDeclaredFields();
    Object returnValue = clazz.newInstance();
    for (Field field : fields) {
        field.setAccessible(true);
        Object value1 = field.get(first);
        Object value2 = field.get(second);
        Object value = (value1 != null) ? value1 : value2;
        field.set(returnValue, value);
    }
    return (T) returnValue;
}

Here's an example

public static class ABC {
    private int id;
    private String name;
    private int[] numbers;

    public ABC() {
    }


    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public int[] getNumbers() {
        return numbers;
    }

    public void setNumbers(int[] numbers) {
        this.numbers = numbers;
    }
}

public static void main(String[] args) throws InstantiationException, IllegalAccessException {
    ABC abc = new ABC();
    abc.setId(1);
    abc.setName("Hello");
    int[] newnumbers = new int[5];
    for(int i = 0; i < newnumbers.length; i++) {
        newnumbers[i] = i;
    }
    abc.setNumbers(newnumbers);
    ABC abc2 = new ABC();
    abc2.setName("World");

    ABC abcFinal = mergeObjects(abc, abc2);
    System.out.println("Properties of ABC Final:");
    System.out.println("ID: " + abcFinal.getId());
    System.out.println("Name: " + abcFinal.getName());
    System.out.println("Numbers: " + Arrays.toString(abcFinal.getNumbers()));
}

Output:

Properties of ABC Final:
ID: 1
Name: Hello
Numbers: [0, 1, 2, 3, 4]
Community
  • 1
  • 1
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
4

In case you want to create a new Object use:

public ABC mergeABC(ABC obj1, ABC obj2){
    ABC retVal = new ABC();
    retVal.name   = ((obj1.name   != null) ? obj1.name   : obj2.name   );
    retVal.id     = ((obj1.id     != null) ? obj1.id     : obj2.id     );
    retVal.salary = ((obj1.salary != null) ? obj1.salary : obj2.salary );
    retVal.status = ((obj1.status != null) ? obj1.status : obj2.status );
    return retVal;
}

If you want to "reuse" obj1 or obj2, simply use this as return value.

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
dosw
  • 431
  • 2
  • 10
  • 2
    This is the most sensible answer so far, however it does not answer the question. You should clearly start saying why what the OP wants is hard and bad, and then present this more sensible (and different) solution – Dici Jun 11 '15 at 13:35
0

If you want to prioritize the values in Object 1 (in case both objects have values), then follow something like this..

private CustomObject mergeObject(CustomObject Obj1, CustomObject Obj2) {
    CustomObject tempObject = new CustomObject();
     If (Obj1.getName() == null) {
      tempObject.setName(Obj2.getName());
     } else {
         tempObject.setName(Obj1.getName());
     }
     return tempObject;
} 

Iterate over the if statement for each parameter within the object.

Othya
  • 390
  • 1
  • 3
  • 18
-2

If you want to do it generically, your only option is going to be reflection.

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
Karrde
  • 471
  • 2
  • 9