Best way to map json to a Java object - java

I'm using restTemplate to make a rquest to a servlet that returns a very simple representation of an object in json.
{
"id":"SomeID"
"name":"SomeName"
}
And I have a DTO with those 2 fields and the corresponding setters and getters.
What I would like to know is how to create the object using that json response
without having to "parse" the response.

Personally I would recommend Jackson. Its fairly lightweight, very fast and requires very little configuration. Here's an example of deserializing:
#XmlRootElement
public class MyBean {
private String id;
private String name;
public MyBean() {
super();
}
// Getters/Setters
}
String json = "...";
MyBean bean = new ObjectMapper().readValue(json, MyBean.class);

Here's an example using Google Gson.
public class MyObject {
private String id;
private String name;
// Getters
public String getId() { return id; }
public String getName() { return name; }
}
And to access it:
MyObject obj = new Gson().fromJson(jsonString, MyObject.class);
System.out.println("ID: " +obj.getId());
System.out.println("Name: " +obj.getName());
As far as the best way, well that's subjective. This is one way you can accomplish what you need.

http://code.google.com/p/json-simple/ is nice and lightweight for this

Related

Spring Boot parse JSON data to Java Class with different field names

I am new to Spring Boot and I am trying to figure out how to parse json data. I see a lot of tutorials on how to map json string object to an annotated Java class and using and object mapper, like this:
json:
{
"UUID": "xyz",
"name": "some name"
}
public class MyClass{
#JsonProperty
private UUID id;
#JsonProperty
private String name;
#JsonAnyGetter
public UUID getId() {
return this.id;
}
#JsonAnySetter
public void setId(UUID id) {
this.id = id;
}
#JsonAnyGetter
public String getName() {
return this.name;
}
#JsonAnySetter
public void setName(String name) {
this.name = name;
}
}
ObjectMapper objectMapper = new ObjectMapper();
MyClass customer = objectMapper.readValue(jsonString, MyClass.class);
The problem is that the system I am getting the json string from does not match the class naming conventions we use (and I cannot change either one). So, instead of having the example json string above, it might look like this:
{
"randomdstring-fieldId": "xyz",
"anotherrandomstring-name": "some name"
}
This use case only has two fields, but my use case has a larger payload. Is there a way to either map the field names from the json object to the field names in the Java class or is there a way to just parse the json string as a key value pair (so that I can just manually add the fields to my Java object)?
In Jackson with #JsonProperty you can customize the field name with it's annotation parameter value
Therefore, you just have to annotate the entity fields with the #JsonProperty annotation and provide a custom JSON property name, like this:
public class MyClass{
#JsonProperty("original_field_name_in_json")
private UUID id;
...
The #JsonProperty will do it for you:
#JsonProperty("name_in_json")
private Long value;

How to use autobean for converting json to java class in GWT

I have a class Person in gwt and I have sent an instance of Person with servlet converted using Gson from server to client. But in the client side seems I can't use Gson. From what I read in forums it seems that the best way is using AutoBeans to convert Json to object Person again.
However in AutoBeans I can only use an interface. I will appreciate if anyone can help me write it.
A json example I get from server and want to convert to Person class again:
{"name":"aaa","family":"fff","username":"uuu","age":20,"phones":[{"id":0,"phoneNumber":"0911111"}],"relatives":[null]}
public class Person implements Serializable {
private String name;
private String family;
private String username;
private int age;
private List<Phone> phones;
private List<Person> relatives;
public Person() {
}
public Person(String name, String family, String username, int age, List<Phone> phones, List<Person> relatives) {
this.name = name;
this.family = family;
this.username = username;
this.age = age;
this.phones = phones;
this.relatives = new ArrayList<Person>();
this.relatives = relatives;
}
public void addPhone(Phone p) {
phones.add(p);
}
public String getName() {
return this.name;
}
public String getFamily() {
return this.family;
}
public int getAge() {
return this.age;
}
public String getUsername() {
return this.username;
}
public List<Phone> getNumbers() {
return this.phones;
}
public List<Person> getRelatives() {
return this.relatives;
}
public String getAllNumbers() {
return Phone.convertPhonesToText(phones);
}
public static Person findPerson(List<Person> personList, String username) {
// .....
}
public static List<Person> convertTextToPersons(List<Person> personList, String personsText) {
// .....
}
public String convertPersonsToText() {
// ....
}
}
Yep, as commented by Tobika the other answer indicates that AutoBeans requires an Interface. AutoBeans feets better if you use it on both sides, client and server side and you define all your models as interfaces.
If you want to use your class models, you can use GWT Jackson which is pretty similar to AutoBeans but it uses your models, binding the json to your model (like other server side libraries; jackson, gson, etc):
https://github.com/nmorel/gwt-jackson
public static interface PersonMapper extends ObjectMapper<Person> {}
#Override public void onModuleLoad() {
PersonMapper mapper = GWT.create(PersonMapper.class);
String json = mapper.write(new Person("John", "Doe"));
GWT.log( json ); // > {"firstName":"John","lastName":"Doe"}
Person person = mapper.read(json);
GWT.log(person.getFirstName() + " " + person.getLastName());
}
Alternatively, you can use just plain GWT with JsInterop. This has many limitations but even with this limitation, it is a pretty good option. This is my favorite option if you can avoid inheritance in your DTOs. But this has the big advantage of being super lightweight (actually zero overhead mapping overhead and zero code overhead as it uses native parsing and no copies, accesing directly to the parsed json object). Limitations: cannot use inheritance, "broken type system" (all X instanceof SomeDtoType returns always true as all DTOs are of type Object wich makes sense because we are actually using the parsed JSON), cannot use collections only native arrays (but thanks to java8 Stream this should not be a problem, whatever you want to do with start with Stream.of(arr)), and only Double and Boolean boxed types supported (not supported any fancy type like Date or BigInteger, not supported long/Long...).
#JsType(isNative=true, package=GLOBAL, name="Object") final class Person {
// you can use getter/setter but as this class is final DTO adds no value
public String firstName; public String lastName; public Phome[] numbers;
// you can add some helper methods, don't forget to skip serialization!
public final #JsOverlay #JsonIgnore List<Phone> getNumberList() {
return Stream.of(numbers).collect(Collectors.toList());
}
}
#JsType(isNative=true, package=GLOBAL, name="Object) final class Phone {
public String number;
}
#JsMethod(namespace = "JSON") public static native <T> T parse(String text);
#Override public void onModuleLoad() {
Person person = parse("{\"firstName\":\"John\",\"lastName\":\"Doe\"}");
GWT.log(person.firstName + " " + person.lastName);
}
These simple and limited DTOs are more a DTO scheme than a type. But has a big advantage, this DTOs works out of the box with most of the server side parsers. Jackson and GSON will encode and parse without any configuration.

Asymmetric serialization and deserialization using Jackson

I am using Jackson to serialize and deserialize data for a RESTful API. I'd like to have a REST resource (/comments) that allows to POST comments as well as to GET a list of comments.
Here's a (simplified) example of what gets posted to /comments.
{"text":"Text","author":"Paul","email":"paul#example.org"}
Here's what the result of GET /comments should look like:
[{"text":"Text","author":"Paul","emailHash":"76w0kjKP9HpsdhBjx895Sg=="}]
Since email addresses shouldn't be visible to anyone, I decided to return only a MD5 hash of the email addresses in the response.
I have created a simple POJO class Comment that has fields with getters and setters for text, author, email, and emailHash.
Now, when I serialize the result, what I get is the following:
[{"text":"Text","author":"Paul","email":null,"emailHash":"76w0kjKP9HpsdhBjx895Sg=="}]
But I really don't like email to be returned as null here. It rather shouldn't be included at all.
Using the annotation #JsonIgnore on that field will also ignore it on deserialization. Do I have to create two classes, say CreationComment and ResultComment with a super-class Comment that shares common fields or is there a way that avoids creating additional classes?
You don't have to create 2 classes at all. With Jackson you have full control of the behavior of a property during serialization and deserialization using annotations, with #JsonIgnorein the getter you prevent the property from being serialized in your Json response and using #JsonProperty annotation in the setter the property will be set during deserialization. The code will look like this:
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Comment {
private String author;
private String email;
#JsonIgnore
public String getEmail() {
return email;
}
#JsonProperty
public void setEmail(String email) {
this.email = email;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public static void main(String[] args) {
ObjectMapper objectMapper = new ObjectMapper();
Comment comment = new Comment();
comment.setAuthor("anAuthor");
comment.setEmail("email#example.com");
try {
System.out.println(objectMapper.writeValueAsString(comment));
String json = "{\"author\":\"anAuthor\",\"email\":\"another#email.com\"}";
Comment fromJson = objectMapper.readValue(json, Comment.class);
System.out.println("Result from Json: author= " + fromJson.getAuthor() + ", email= " + fromJson.getEmail());
} catch (Exception e) {
e.printStackTrace();
}
}
}
The output after running the main() method to test the solution:
{"author":"anAuthor"}
Result from Json: author= anAuthor, email= another#email.com
Hope it helps,
Jose Luis
You can put #JsonIgnore on getEmail to prevent it from being serialized to JSON and use #JsonCreator to indicate to Jackson a constructor to use for deserialization. The constructor would then only accept an email property and would hash and assign to your emailHash field.
You can put a #JsonInclude annotation on your Comment class to prevent serialization of null fields too.
Your class would probably end up looking something like this:
#JsonInclude(Include.NON_NULL)
public class Comment {
private final String email;
private final String emailHash;
#JsonCreator
public Comment(#JsonProperty("email") String email) {
this.email = email;
this.emailHash = MD5.hash(email);
}
#JsonIgnore
public String getEmail() {
return email;
}
public String getEmailHash() {
return emailHash;
}
}

Json string partial deserial to Java object with embeded another Json string using jackson

I have one java object
class packet {
int id;
String sender;
String content; // this is an embedded json string
}
here is my original json string
{"id":0,"sender":"jack","content":{"title":"test1","author":"john"}}.
I want Jackson only parse outer id, sender, and keep the
content = {"title":"test1","author":"john"},
how to do it?
I have tried #JsonUnwrapped on content variable, but it don't work.
In order to use an "embedded" JSON string you can use the JsonNode class. If you specify the Packet class like this:
public class Packet {
private final int id;
private final String sender;
private final JsonNode content; // this is the embedded content
#JsonCreator
public Packet(#JsonProperty("id") final int id,
#JsonProperty("sender") final String sender,
#JsonProperty("content") final JsonNode content) {
this.id = id;
this.sender = sender;
this.content = content;
}
public JsonNode getContent() {
return content;
}
public int getId() {
return id;
}
public String getSender() {
return sender;
}
}
Then, you can do your mapping according to this:
final String json = "{\"id\":0,\"sender\":\"jack\",\"content\":{\"title\":\"test1\",\"author\":\"john\"}}";
final ObjectMapper mapper = new ObjectMapper();
final Packet packet = mapper.readValue(json, Packet.class);
System.out.println(packet.getContent().toString());
The output will be:
{"title":"test1","author":"john"}
Also note that JsonNode has methods so that it is still possible to get the inner attributes (methods are called get() and path()).
Edit:
After some input from #HotLicks I have provided a shorter example of the code as well. Please note that this code does not follow best practices for e.g. immutable objects but it is, well, short. However, I would strongly recommend to encapsulate POJOs properly using immutable objects, proper constructors and to avoid field deserialization and instead use a creator-method.
public class Packet {
#JsonProperty("id")
private int id;
#JsonProperty("sender")
private String sender;
#JsonProperty("content")
private JsonNode content; // this is the embedded content
// Other methods...
}

Partially deserialize a json object in a restful post call

I am trying to get a method in springmvc to accept a partial json string of an object, and have jackson automatically de-serialize it for me.
I can solve it by making a temporary object with only the attributes I want, or pass it in as a string and use Gson to desearialize it for me, but these feel hacky. Is there any way to tell jackson how to do it?
Here is the controller snippet:
#RequestMapping(value = "/task",
method = RequestMethod.POST,
consumes="application/json")
public #ResponseBody String postTask(#RequestBody Task task){
if(task.getId() == null){
task.setId(UUID.randomUUID());
}
if(task.getDate_entered() == 0){
task.setDate_entered(System.currentTimeMillis());
}
TaskDao.addTask(task);
return "success";
}
And the task, a basic pojo:
#JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public class Task {
private UUID id;
private String name;
private String description;
private long date_entered;
private long finish_by;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
// Rest of the getters and setters
}
If you can't tell by my other spring related questions, I'm kind of flying blind, and can't figure out the proper google query for this one.
Thanks!
You need to use #JsonIgnoreannotation of jackson on the method (on setter for deserialization and on getter for serialization) or field, for which you want to ignore serialization and/or deserialization. e.g.
In your example, if you don't want to serialize description, then you can do,
#JsonIgnore
public void setDescription(String description) {
this.description = description;
}
And you will see, that you won't get value of description in converted model.

Categories