Avinash Kharche
Avinash Kharche

Reputation: 441

Convert POJO to POJO with custom converter using json configuration

We have two Pojo files.

Person {
  String name;
  int age;
  String address;
  String phoneNo;
  boolean isMarried;
}

and

 OtherPerson {
//mandatory fields are name and age
  String name_other;
  int age_other;
//other fields
  Map<String, Object> otherFields;
}

and a json file which defines the mapping between the fields using name

mappingJson {
 "name":"name_other",
 "age":"age_other",
 "address":"address_other",
 "phoneNo":"phoneno_other",
 "isMarried":"ismarried_other"
}

Please let me know the best approach to convert Person to OtherPerson. So that the mandatory fields map to name_other and age_other while the other fields should be added to the map(otherFields)

It may be

Person->Person(json)->OtherPerson

Or Person->OtherPerson.

EDIT: "Use case: We have an API which used to accepts a POJO 'A' but now it needs to accept POJO 'B' as an input argument. This POJO needs to get converted into POJO 'A' which can then be used for persisting into the database. Also POJO 'B' is not under our control"

Upvotes: 0

Views: 5036

Answers (2)

Bartosz Piorunski
Bartosz Piorunski

Reputation: 114

That's a perfect fit for Jackson Converter! :) It could work like this:

class OtherPerson {
    @JsonProperty("name")
    public String name_other;
    @JsonProperty("age")
    public int age_other;

    Map<String, Object> otherFields = new LinkedHashMap<>();;

    @JsonAnySetter
    public void add(String key, Object value) {
        otherFields.put(key, value);
    }
}
// ...

Person person = new Person();
person.name = "Avinash";
person.age = 25;
person.address = "Mumbai";
person.phoneNo = "910731";
person.isMarried = true; // :( sorry ladies!

// ...

ObjectMapper mapper = new ObjectMapper();

// If we cannot put @JsonAutoDetect on top of Person.class,
// we need to add handling of non-public fields
// since Person seems to neither have public fields nor setters
mapper.configOverride(Person.class)
        .setVisibility(JsonAutoDetect.Value.defaultVisibility()
                .withFieldVisibility(JsonAutoDetect.Visibility.NON_PRIVATE));

OtherPerson other = mapper.convertValue(person, OtherPerson.class);

Voilà!

Upvotes: 4

SedJ601
SedJ601

Reputation: 13859

I personally would do this without JSON. It's my understanding that some fields in the Map are optional while name and age are mandatory. In the case of the optional content, I would use the Ternary operator to create the person object. This allows you to add some default value if the optional field is not available.

Main

import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author blj0011
 */
public class JavaApplication30 {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        Map<String, Object> map1 = new HashMap();
        map1.put("address", "123 Hello Street");
        map1.put("phoneNo", "555-555-5555");
        map1.put("isMarried", true);
        OtherPerson otherPerson = new OtherPerson("John Doe", 22, map1);

        Map<String, Object> map2 = new HashMap();
        map2.put("address", "4456 Bye Road");
        map2.put("isMarried", false);
        OtherPerson otherPerson2 = new OtherPerson("Jane Doe", 21, map2);


        Person person1 = new Person(otherPerson.getName_other(), otherPerson.getAge_other(), 
                otherPerson.getOtherFields().containsKey("address") ? otherPerson.getOtherFields().get("address").toString(): "", 
                otherPerson.getOtherFields().containsKey("phoneNo") ? otherPerson.getOtherFields().get("phoneNo").toString(): "",
                otherPerson.getOtherFields().containsKey("isMarried") ? Boolean.valueOf(otherPerson.getOtherFields().get("isMarried").toString()): false);

        System.out.println(person1);

        Person person2 = new Person(otherPerson2.getName_other(), otherPerson2.getAge_other(), 
                otherPerson2.getOtherFields().containsKey("address") ? otherPerson2.getOtherFields().get("address").toString(): "", 
                otherPerson2.getOtherFields().containsKey("phoneNo") ? otherPerson2.getOtherFields().get("phoneNo").toString(): "",
                otherPerson2.getOtherFields().containsKey("isMarried") ? Boolean.valueOf(otherPerson2.getOtherFields().get("isMarried").toString()): false);

        System.out.println(person2);
    }    
}

Person

/**
 *
 * @author blj0011
 */
public class Person {
    private String name;
    private int age;
    private String address;
    private String phoneNo;
    private boolean isMarried;

    public Person(String name, int age, String address, String phoneNo, boolean isMarried) {
        this.name = name;
        this.age = age;
        this.address = address;
        this.phoneNo = phoneNo;
        this.isMarried = isMarried;
    }

    public boolean isIsMarried() {
        return isMarried;
    }

    public void setIsMarried(boolean isMarried) {
        this.isMarried = isMarried;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhoneNo() {
        return phoneNo;
    }

    public void setPhoneNo(String phoneNo) {
        this.phoneNo = phoneNo;
    }

    @Override
    public String toString() {
        return "Person{" + "name=" + name + ", age=" + age + ", address=" + address + ", phoneNo=" + phoneNo + ", isMarried=" + isMarried + '}';
    }    
}

OtherPerson

/**
 *
 * @author blj0011
 */
public class OtherPerson {
    //mandatory fields are name and age
     private String name_other;
    private int age_other;
    //other fields
    private Map<String, Object> otherFields;

    public OtherPerson(String name_other, int age_other, Map<String, Object> otherFields) {
        this.name_other = name_other;
        this.age_other = age_other;
        this.otherFields = otherFields;
    }

    public Map<String, Object> getOtherFields() {
        return otherFields;
    }

    public void setOtherFields(Map<String, Object> otherFields) {
        this.otherFields = otherFields;
    }

    public String getName_other() {
        return name_other;
    }

    public void setName_other(String name_other) {
        this.name_other = name_other;
    }

    public int getAge_other() {
        return age_other;
    }

    public void setAge_other(int age_other) {
        this.age_other = age_other;
    }
}

Output

Person{name=John Doe, age=22, address=123 Hello Street, phoneNo=555-555-5555, isMarried=true}
Person{name=Jane Doe, age=21, address=4456 Bye Road, phoneNo=, isMarried=false}

As you can see in the output OtherPerson2 did not have a phone number. Empty string was use as the default value.

Upvotes: 0

Related Questions