3

class Person:

@Data
public class Person<T extends Parent> implements Serializable {
    private static final long serialVersionUID = 7822965786010192978L;

    private static final ObjectMapper objectMapper = new ObjectMapper();  
    private String id;    
    private T people; // change (String peopleInfo) to object extends Parent after read data from database
    private String peopleInfo; // change (T people) to string and save in the dataBase as an string

    @SneakyThrows
    public void setPeople(T people) {
        this.people = people;
        peopleInfo = objectMapper.writeValueAsString(people);
    }

    @SneakyThrows
    public void setPeopleInfo(String peopleInfo) {
        this.peopleInfo = peopleInfo;
        if (!Strings.isNullOrEmpty(peopleInfo)) {
            people = objectMapper.readValue(peopleInfo, new TypeReference<T>() {});
        }
    }
}

class Parent:

@Data
public class Parent implements Serializable {
    private static final long serialVersionUID = 2092353331893381153L;
    private String name;
}

class Child:

@Data
public class Child extends Parent {
    private static final long serialVersionUID = 3318503314202792570L;
    private String pocketMoney;
}

and the test function: I want to save the persnInfo to the database as String and change this string to an object people automatically after reading data from database.

@Test
public void testReadData() throws Exception {
    Child child = new Child();
    child.setName("_child");
    child.setPocketMoney("10$");

    Person<Child> person = new Person<>();
    person.setId("1");
    person.setPeople(child);

    // assume this json was read from database
    String json = person.getPeopleInfo();
    System.out.println(json);

    Person<Child> readPerson = new Person<>();
    readPerson.setId("1");
    readPerson.setPeopleInfo(json);

    Child readChild = readPerson.getPeople();
    System.out.println(readChild.getPocketMoney());
}

The error happened:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "pocketMoney" (class pers.test.common.objmapper.Parent), not marked as ignorable (one known property: "name"])

at [Source: {"name":"_child","pocketMoney":"10$"}; line: 1, column: 33] (through reference chain: pers.test.common.objmapper.Parent["pocketMoney"])

at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:51)

I have no idea to solve this, anyone can help me make it pass without changing the testReadData()' but change the modelPeople`.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
Jarvis
  • 371
  • 1
  • 10
  • 22
  • @GhostCat in the `Person.setPeopleInfo ()` `people = objectMapper.readValue(peopleInfo, new TypeReference() {});` – Jarvis Jul 18 '17 at 08:46

1 Answers1

5

Your problem is here:

new TypeReference<T>()

This doesn't do what you expect it to do. Java generics are erased at runtime; therefore the above statement is basically new TypeReference<Object>.

In other words - the fact that you declared

Person<Child> readPerson = new Person<>();

to expect Child objects is simply not sufficient!

You probably have to pass the specific class Child.class to the code that maps JSON strings back. For further information, look here.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • I know that pass in the test fun as : `ObjectMapper objectMapper = new ObjectMapper(); Child readChild = objectMapper.readValue(readPerson.getPeopleInfo(), Child.class);` and this will work, but still I want do it in the pojo `People` self dynamically. – Jarvis Jul 18 '17 at 09:07
  • As said: then you **have** to somehow pass down the specific type, like Child.class. That is why I added that second link! – GhostCat Jul 18 '17 at 09:10
  • I do think so. And in case I am mistaken, and somebody has a **better** solution (which I doubt, because, as said: those generic types are **erased** at runtime) - feel free to accept that other answer. – GhostCat Jul 18 '17 at 09:13