0

I'm trying to deserialize a json like this:

{
  //other fields

  "name": "John",
  "surname": "Doe"
}

into an object like this:

public class SomeClass {

  //other fields

  private User user;

  public class User {

      private String name;
      private String surname;
        
      //getters and setters
  }


//getters and setters
}

I tried to use @JsonCreator annotated on a static method, but it's not working (I'm not that practical with @JsonCreator). Is there a way to achieve this, maybe using Jackson Annotations? How can I populate User fields and having a correctly populated "user" field of a "SomeClass" object?

Notes: I will not change either the structure of the json or the class.

Updates: I found the solution, but it's not a good solution imo:

@JsonAnySetter
public void setFields(String key, String value) {

    if (user == null)
        user = new User();

    if (key.equals("name"))
        user.setName(value);
    else if (key.equals("surname"))
        user.setSurname(value);

}

Is there a better way?

Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219
Daesos
  • 99
  • 10

3 Answers3

0

Possible Option: Jackson's ObjectMapper, Using Class or TypeReference

The Direct Answer

ObjectMapper mapper = new ObjectMapper(); // To do the work of serialization/deserialization
String json = "{"
      + "\"name\": \"John\",\n"
      + "\"surname\": \"Doe\"\n"
      + "}";

try {
    User user = mapper.readValue(json, User.class); // Deserializing directly to a Class is this easy :)

    String msg = String.format("With Class, User's Name: %s, User's Surname: %s", user.getName(), user.getSurname());
    System.out.println(msg);
} catch (JsonProcessingException e) {
    e.printStackTrace();
}

As a Whole

(Using IntelliJ to easily access the test library)

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.testng.annotations.Test;

public class TestDeserialization {

    private ObjectMapper mapper = new ObjectMapper(); // To do the work of serialization/deserialization
    private String json = "{"
                          + "\"name\": \"John\",\n"
                          + "\"surname\": \"Doe\"\n"
                          + "}"; // Not a good way to store JSON, but here for demonstration :)

    @Test
    public void testDeserializationWithClass() {
        try {
            User user = mapper.readValue(json, User.class); // Deserializing directly to a Class is this easy :)

            String msg = String.format("With Class, User's Name: %s, User's Surname: %s", user.getName(), user.getSurname());
            System.out.println(msg);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }


    @Test
    public void testDeserializationWithTypeReference() {
        try {
            /*
                TypeReference can handle complexity where the simple Class argument cannot; such as if we needed a Map<String, User>:
                    Map<String, User> userMap = mapper.readValue(json, new TypeReference<Map<String, User>>() {}); 
            */
            User user = mapper.readValue(json, new TypeReference<User>() {}); 

            String msg = String.format("With TypeReference, User's Name: %s, User's Surname: %s", user.getName(), user.getSurname());
            System.out.println(msg);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

}
package test.example;

public class User {

    private String name;
    private String surname;

    public String getName() {
        return name;
    }

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

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }
}

Output

With Class, User's Name: John, User's Surname: Doe
With TypeReference, User's Name: John, User's Surname: Doe

References

Phacops
  • 76
  • 7
-1

You can use the Jackson for this. I have used Jackson 2.12.1 and Project Lombok for getter and setter. Here is the complete code for JSON serialization and deserilization.

Your JSON structure needs to be changed to the following:

{
  "user":{
     "name": "John",
    "surname": "Doe" 
  }
}

User.java class:

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class User {
    private String name;
    private String surname;
}

SomeClass.Java class:

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class SomeClass {
    private User user;
}

Main.java class:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {

    public static void main(String[] args) throws JsonMappingException, JsonProcessingException {
        String inputJSON = "{\"user\":{\"name\":\"John\",\"surname\":\"Doe\"}}";
        SomeClass myUserRead = new ObjectMapper().readValue(inputJSON, SomeClass.class);
        System.out.println(myUserRead.getUser().getName());
        System.out.println(myUserRead.getUser().getSurname());

        String myUserWrite = new ObjectMapper().writeValueAsString(myUserRead);
        System.out.println(myUserWrite);
    }
BATMAN_2008
  • 2,788
  • 3
  • 31
  • 98
  • As specified in the question, the json structure cannot be changed. So the wrapper "user" cannot be written. – Daesos Feb 16 '21 at 15:58
-1

@JsonCreator will be called on initialization for the given fields, i.e. first.

The remaining fields will be changed already through setters. This is the solution for this case, since the structure of your Json object is different from the structure of your class

@Getter
@Setter
public static class SomeClass {
    private User user;
    private String otherField;

    @JsonCreator
    public SomeClass(@JsonProperty("name") String name,
                     @JsonProperty("surname") String surname) {
        this.user = new User(name, surname);
    }

    @Getter
    @Setter
    @AllArgsConstructor
    public class User {
        private String name;
        private String surname;
    }
}
d_ser
  • 59
  • 4