Please refer below example.
public class Human {
private String name;
private int age;
}
public class Teacher {
private String school;
private Human human;
}
And JSON looks like :
{
"school": "My School",
"age": 20,
"name": "My Name"
}
I want to create Teacher from JSON string which has Human as inner object but should match to same level of JSON properties.
I'm using Jackson API to create java object from JSON.
You can mark the human field as #JsonUnwrapped:
public class Teacher {
private String school;
#JsonUnwrapped
private Human human;
// constructor / setters
}
public class Human {
private String name;
private int age;
// constructor / setters
}
public class Test {
String str = "{ \"school\": \"My School\", \"age\": 20, \"name\": \"My Name\" }";
System.out.println(new ObjectMapper().readValue(str, Teacher.class));
}
That will de-serialize into the format you're looking for.
Related
public class Baseproperties
{
#JsonProperty("id")
private String id ;
private Integer ccode;
//...set and geters
}
public class Person
{
#JsonProperty("name")
private String name ;
private Integer age;
#JsonProperty("props")
private Baseproperties bprop;
//...set and geters
}
public class Cars
{
#JsonProperty("model")
private String Model ;
private Integer yearOfMake;
#JsonProperty("props")
private Baseproperties bprop;
//...set and geters
}
public MessageWrapper
{
#JsonProperty("ct")
private String classType;
private Object data;
//...set and geters
}
I need to serialise MessageWrapper class to json, but the approach fails due to unable to desearialize the Object data;
here i am reading the classType and desearializing it to either Person or CarType
//Person
{
"name": "arnold",
"age": 21
}
//car
{
"model": "Moriz",
"yearOfMake": 1892
}
//example MessageWrapper
String s= "{
"ct": "<packagename>.car",
"data": {
"model": "Moriz",
"yearOfMake": 1892
"props":{
"id" : "12312",
"ccode" :33
}
}
}"
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
MessageWrapper mw = mapper.readValue(s, MessageWrapper.class);
if(mw.getclassType().toString().equals("<packagename>.car"))
Cars cw = mapper.readValue(mw.getData(), Cars.class);
but cw is wrong // serialise fails.
This is because there is no ObjectMapper::readValue method that takes Object as first argument.
By default with your approach Jackson will deserialize your data field to LinkedHashMap because you have given it Object type.
To then deserialize this value manually you will have to use ObjectMapper::convertValue and passing Cars.class as argument :
Cars cw = mapper.convertValue(mw.getData(), Cars.class);
And also get rid of :
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
as it does not seem to be needed here.
And just to add, I am not sure that approach with such dynamic data is good because, if you will be creating more and more types of objects you will end up with a tower of ifs or colosal switch statement.
In some incoming JSON there is a list
"age" : 27,
"country", USA,
"fields": [
{
"id": 261762251,
"value": "Fred"
},
{
"id": 261516162,
"value": "Dave"
},
]
I know the key int for what I am looking for [261762251].
I would like to map that to a plain String field firstname in the User object with the rest of the bottom level fields from the JSON. I have tried extending com.fasterxml.jackson.databind.util.StdConverter and adding the annotation #JsonSerialize(converter=MyConverterClass.class) to the variable in the User class with no luck.
My architecture is like this:
public class User {
private String age;
private String country;
private String firstname; // this is the field in the list that needs converting
// getters and setters
}
public class ApiClient{
public User getUsers(){
Response response;
//some code to call a service
return response.readEntity(User.class)
}
}
What is the best approach to achieve this?
You can try something like below:
class Tester
{
public static void main(String[] args) throws Exception {
String s1 = "{\"fields\": [ { \"id\": 261762251, \"value\": \"Fred\" }, { \"id\": 261516162, \"value\": \"Dave\" }]}";
ObjectMapper om = new ObjectMapper();
Myclass mine = om.readValue(s1, Myclass.class);
System.out.println(mine);
}
}
public class User {
private String age;
private String country;
private String firstname; // this is the field in the list that needs converting
#JsonProperty("fields")
private void unpackNested(List<Map<String,Object>> fields) {
for(Map<String,Object> el: fields) {
if((Integer)el.get("id") == 261762251) {
firstname = el.toString();
}
}
}
// getters and setters
}
I have a class that should be deserialized accordingly the header request.
If header is on V1 version, ww should output the information field of Product class, like a String. Otherwise it output an Info object.
Is there another solution to do this, instead duplicate the class?
public class Product{
private String name;
private Integer id;
private Info information;
}
public class Info{
private String generalInfo;
private String fullDescription;
private String code;
}
public class Product{
private String name;
private Integer id;
private String information;
}
Above the JSON when use INFO object and when information is a string.
{
"name": "Paul",
"id": "123123,
"information": {
"generalInfo":"Business Product",
"fullDescription":"23",
"code":"9487987289929222-3"
}
}
{
"name": "Paul",
"id": "123123,
"information": "Business Product - 23 - 9487987289929222-3 "
}
I have a JSON payload that looks like this:
{
"id": 32,
"name": "[Sample] Tomorrow is today, Red printed scarf",
"primary_image": {
"id": 247,
"zoom_url": "www.site.com/in_123__14581.1393831046.1280.1280.jpg",
"thumbnail_url": "www.site.com/in_123__14581.1393831046.220.290.jpg",
"standard_url": "www.site.com/in_123__14581.1393831046.386.513.jpg",
"tiny_url": "www.site.com/in_123__14581.1393831046.44.58.jpg"
}
}
Can I unwrap a specific field and discard all the others? In other words, can I bind this directly to a POJO like this:
public class Product {
private Integer id;
private String name;
private String standardUrl;
}
There are lots of ways. Do you need to deserialize, serialize or both?
One way to deserialize would be to use a creator method that takes the image as a tree node:
public static class Product {
private Integer id;
private String name;
private String standardUrl;
public Product(#JsonProperty("id") Integer id,
#JsonProperty("name") String name,
#JsonProperty("primary_image") JsonNode primaryImage) {
this.id = id;
this.name = name;
this.standardUrl = primaryImage.path("standard_url").asText();
}
}
The creator doesn't have to be a constructor, you could have a static method that is only used for Jackson deserialization.
You'd have to define a custom serializer to reserialize this, though (e.g. a StdDelegatingSerializer and a converter to wrap the string back up as an ObjectNode)
There are different ways to skin this cat, I hope you can use Jackson 2 for this, since it offers great ways to deserialize Json data, one of my favorites deserialization features is the one I'll show you here (using Builder Pattern) because allows you to validate instances when they are being constructed (or make them immutable!). For you this would look like this:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.util.Map;
#JsonDeserialize(builder = Product.Builder.class)
public class Product {
private Integer id;
private String name;
private String standardUrl;
private Product(Builder builder) {
//Here you can make validations for your new instance.
this.id = builder.id;
this.name = builder.name;
//Here you have access to the primaryImage map in case you want to add new properties later.
this.standardUrl = builder.primaryImage.get("standard_url");
}
#Override
public String toString() {
return String.format("id [%d], name [%s], standardUrl [%s].", id, name, standardUrl);
}
#JsonIgnoreProperties(ignoreUnknown = true)
public static class Builder {
private Integer id;
private String name;
private Map<String, String> primaryImage;
public Builder withId(Integer id) {
this.id = id;
return this;
}
public Builder withName(String name) {
this.name = name;
return this;
}
#JsonProperty("primary_image")
public Builder withPrimaryImage(Map<String, String> primaryImage) {
this.primaryImage = primaryImage;
return this;
}
public Product build() {
return new Product(this);
}
}
}
To test it I created this class:
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class Test {
public static void main(String[] args) {
String serialized = "{" +
" \"id\": 32," +
" \"name\": \"[Sample] Tomorrow is today, Red printed scarf\"," +
" \"primary_image\": {" +
" \"id\": 247," +
" \"zoom_url\": \"www.site.com/in_123__14581.1393831046.1280.1280.jpg\"," +
" \"thumbnail_url\": \"www.site.com/in_123__14581.1393831046.220.290.jpg\"," +
" \"standard_url\": \"www.site.com/in_123__14581.1393831046.386.513.jpg\"," +
" \"tiny_url\": \"www.site.com/in_123__14581.1393831046.44.58.jpg\"" +
" }" +
" }";
ObjectMapper objectMapper = new ObjectMapper();
try {
Product deserialized = objectMapper.readValue(serialized, Product.class);
System.out.print(deserialized.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
The output is (using the override toString() method in Product:
id [32], name [[Sample] Tomorrow is today, Red printed scarf], standardUrl [www.site.com/in_123__14581.1393831046.386.513.jpg].
There are two ways to get the response you required. For both methods, we are going to use JsonView.
Create two types of JsonView:
public interface JViews {
public static class Public { }
public static class Product extends Public { }
}
First method
#JsonView(JViews.Public.class)
public class Product {
private Integer id;
private String name;
#JsonIgnore
private Image primaryImage;
#JsonView(JViews.Product.class)
public String getStandardUrl{
return this.primaryImage.getStandardUrl();
}
}
Second way
Using Jackson's #JsonView and #JsonUnwrapped together.
#JsonView(JViews.Public.class)
public class Product {
private Integer id;
private String name;
#JsonUnwrapped
private Image primaryImage;
}
public class Image {
private String zoomUrl;
#JsonView(JViews.Product.class)
private String standardUrl;
}
#JsonUnwrapped annotation flattens your nested object into Product object. And JsonView is used to filter accessible fields. In this case, only standardUrl field is accessible for Product view, and the result is expected to be:
{
"id": 32,
"name": "[Sample] Tomorrow is today, Red printed scarf",
"standard_url": "url"
}
If you flatten your nested object without using Views, the result will look like:
{
"id": 32,
"name": "[Sample] Tomorrow is today, Red printed scarf",
"id":1,
"standard_url": "url",
"zoom_url":"",
...
}
Jackson provided #JsonUnwrapped annotation.
See below link:
http://jackson.codehaus.org/1.9.9/javadoc/org/codehaus/jackson/annotate/JsonUnwrapped.html
I am modelling classes in Java to store a JSON , for a particular JSON
"id":1,
"firstName":"sample",
"lastName":"person",
"Books":{
"bookName":"gone with the wind"
"isbn": 12345
}
I created a class person with int id , String firstName etc...
what would be the best way to store bookName , make a class Books with a String bookName and int isbn , how would I represent books in the person class , As an array? since books always has only one value is there a better way to represent it
For json serialization/deserialization, I suggest the jackson library.Here is my code,it works fine on my computer!
I store the json in the file named json.data as following:
{"id":1,
"firstName":"sample",
"lastName":"person",
"books":[{"bookName":"gone with the wind","isbn":12345}]
}
And the code,I omitted the getter/setter to be short
public class Book
{
private String bookName;
private int isbn;
}
public class BookWriter
{
private String id;
private String firstName;
private String lastName;
private Book[] books;
}
public class JSONTest
{
public static void main(String[] args)
{
try
{
ObjectMapper mapper = new ObjectMapper();
BookWriter writer=(BookWriter)mapper.readValue(new File("json.data"), BookWriter.class);
for(Book book:writer.getBooks())
{
System.out.println(book.getBookName()+","+book.getIsbn());
}
} catch (Exception e)
{
e.printStackTrace();
}
}
}