How to access JSON subfield using #JsonProperty annotation? - java

I need transform json in another diferent json , im using #JsonProperty annotation for change name fields JSON result , but i dont know access fields encapsulate in differents json level for example :
{ "prop1" : "value1",
"prop2" : "value2",
"prop3" : {
"prop4" : "value4",
"prop5" : {
"prop6" : "value6"
}
}
}
json result
{
"prop1_new_name":"value1",
"prop4_new_name":"value4",
"prop6_new_name":"value6"
}

This seems like a continuation of your previous question. So, in addition of using #JsonUnwrapped as explained in the answer, you need to add #JsonProperty on the field in the class where it is declared. Modifying the previous answer with #JsonProperty gives you this:
#RunWith(JUnit4.class)
public class Sample {
#Test
public void testName() throws Exception {
SampleClass sample = new SampleClass("value1", "value2", new SubClass("value4", "value5", new SubSubClass("value7")));
new ObjectMapper().writeValue(System.out, sample);
}
#JsonAutoDetect(fieldVisibility=Visibility.ANY)
public static class SampleClass {
private String prop1;
private String prop2;
#JsonUnwrapped
private SubClass prop3;
public SampleClass(String prop1, String prop2, SubClass prop3) {
this.prop1 = prop1;
this.prop2 = prop2;
this.prop3 = prop3;
}
}
#JsonAutoDetect(fieldVisibility=Visibility.ANY)
public static class SubClass {
#JsonProperty("prop4_new_name")
private String prop4;
private String prop5;
#JsonUnwrapped
private SubSubClass prop6;
public SubClass(String prop4, String prop5, SubSubClass prop6) {
this.prop4 = prop4;
this.prop5 = prop5;
this.prop6 = prop6;
}
}
#JsonAutoDetect(fieldVisibility=Visibility.ANY)
public static class SubSubClass{
#JsonProperty("prop7_new_name")
private String prop7;
public SubSubClass(String prop7) {
this.prop7 = prop7;
}
}
}
With this as a result:
{"prop2":"value2","prop5":"value5","prop7_new_name":"value7","prop4_new_name":"value4","prop1_new_name":"value1"}

"prop3" would be a Map in your Java object when deserializing (if you have it properly annotated). Then you can create a custom JsonSerializer to output your expected result.
To create your custom JsonSerializer, you can follow this guide: http://dev.sghill.net/2012/04/how-do-i-write-jackson-json-serializer.html

Related

Using #JsonCreator to create two instances of same class in one JSON DTO

I would like to deserialize JSON of this structure:
{
"employee_pricing_type":"COMPUTE_BY_OWN_RATE",
"employee_rate":10,
"customer_pricing_type":"COMPUTE_BY_OWN_RATE",
"customer_rate":200
}
I have such POJO to create price setting from a HTTP request:
public class ObjectPricingSetting {
#JsonProperty("pricing_type") // describes output
private final ObjectPricingType pricingType;
#JsonProperty("own_rate") // describes output
private final BigDecimal ownRate;
public ObjectPricingSetting(final ObjectPricingType pricingType, final BigDecimal ownRate) {
AssertUtils.notNull(pricingType, "pricingType");
this.pricingType = pricingType;
if (ownRate != null) {
AssertUtils.isGtZero(ownRate, "ownRate");
this.ownRate = ownRate;
} else {
this.ownRate = null;
}
}
public ObjectPricingType getPricingType() {
return pricingType;
}
public BigDecimal getOwnRate() {
return ownRate;
}
}
this is DTO:
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ObjectPricingCommand extends BaseDto<ObjectId> {
#JsonProperty(value = "employee_pricing_setting")
private ObjectPricingSetting employeePricingSetting;
#JsonProperty(value = "customer_pricing_setting")
private ObjectPricingSetting customerPricingSetting;
}
I would like to create these two instances of ObjectPricingSetting with #JsonCreator.
Q: How should I anotate #JsonProperty parameter in ObjectPricingSetting constructor to recognize what JSON value should use to create these two instances?
You can use #JsonUnwrapped with a prefix in your parent class:
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ObjectPricingCommand extends BaseDto<ObjectId> {
#JsonUnwrapped(prefix = "employee_")
private ObjectPricingSetting employeePricingSetting;
#JsonUnwrapped(prefix = "customer_")
private ObjectPricingSetting customerPricingSetting;
}
Then you can use the normal #JsonCreator/#JsonProperty in your nested DTO, without the prefix:
public class ObjectPricingSetting {
#JsonCreator
public ObjectPricingSetting(
#JsonProperty("pricing_type") final ObjectPricingType pricingType,
#JsonProperty("rate") final BigDecimal ownRate) {
...

Parse json using ObjectMapper where json key contains json as a value

I have a class with such structure:
class SomeClass {
private String stringValue;
private Collection<String> collectionValue = new ArrayList<>();
private String jsonStringValue;
private boolean booleanValue;
}
And then I use
objectMapper.readValue(jsonString, SomeClass.class);
to parse this object from JSON.
The main problem is that jsonStringValue is a json inside of json:
{"stringValue" : "someString",
"collectionValue" : ["123456", "234567", "hello"],
"jsonStringValue" : "{
"someKey" : 1,
"anotherKey" : {
"againKey" : "value"
}
},
"booleanValue" : true
}
And trying to parse jsonStringValue it throws
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('a' (code 97)): was expecting comma to separate Object entries
Exactly "a" character from my example (json modified on security purposes)
I believe there should be some escaping rule for parsing json as a String.
How do I parse json value as a string?
First, your JSON string is not valid because there is a redundant double quote before the left bracket in jsonStringValue. The valid one looks like this:
{
"stringValue" : "someString",
"collectionValue" : ["123456", "234567", "hello"],
"jsonStringValue" : {
"someKey" : 1,
"anotherKey" : {
"againKey" : "value"
}
},
"booleanValue" : true
}
Second, jsonStringValue is not a simple String object, it is a nested JSON objects. Therefore, you are supposed to create corresponding classes for it as follows:
Class SomeClass {
private String stringValue;
private List<String> collectionValue = new ArrayList<>();
private JsonStringValue jsonStringValue;
private boolean booleanValue;
//general getters and setters
}
Class JsonStringValue {
private int someKey;
private AnotherKey anotherKey;
//general getters and setters
}
Class AnotherKey {
private String againKey;
//general getters and setters
}
At last, the given JSON string can be transformed into SomeClass POJO with ObjectMapper.
ObjectMapper mapper = new ObjectMapper();
SomeClass someClass = mapper.readValue(jsonStr, SomeClass.class);
System.out.println(someClass.getjsonStringValue().getAnotherKey().getAgainKey());
Console output:
value
UPDATED
If you still want to transform the jsonStringValue object into String, an alternative way is shown as follows:
Create 2 classes - SomeClassOriginal and SomeClass, the only difference between them is the data type of jsonStringValue. The former one is JsonNode and later one is String.
Class SomeClassOriginal {
private String stringValue;
private List<String> collectionValue = new ArrayList<>();
private JsonNode jsonStringValue;
private boolean booleanValue;
//general getters and setters
}
Class SomeClass {
private String stringValue;
private List<String> collectionValue = new ArrayList<>();
private String jsonStringValue;
private boolean booleanValue;
public SomeClass(SomeClassOriginal someClassOriginal) {
super();
this.stringValue = someClassOriginal.stringValue;
this.collectionValue = someClassOriginal.collectionValue ;
this.jsonStringValue= someClassOriginal.jsonStringValue.toString();
this.booleanValue= someClassOriginal.booleanValue;
}
//general getters and setters
}
Then you can get the jsonStringValue as String like this:
ObjectMapper mapper = new ObjectMapper();
SomeClassOriginal someClassOriginal = mapper.readValue(jsonStr, SomeClassOriginal.class);
SomeClass someClass = new SomeClass(SomeClassOriginal);
System.out.println(someClass.getjsonStringValue());
Console output:
{"someKey":1,"anotherKey":{"againKey":"value"}}

Can get field from inner json object with jackson?

I have json like that:
{
"somethingElse": "foobar",
"snils": {
"number": "123"
}
}
And class:
#Data
public class Documents {
private String snilsNumber;
private String somethingElse;
}
Can I easily map json to my class with annotation or something else?
You can use '#JsonRootName'
#Data
#JsonRootName(value = "snils")
#JsonIgnoreProperties(unknown = true)
public class Documents {
private String number;
}
You can deserialise it using one extra update method with JsonProperty annotation.
class Documents {
private String snilsNumber;
private String somethingElse;
#JsonProperty("snils")
private void unpackSnils(Map<String, Object> brand) {
this.snilsNumber = (String) brand.get("number");
}
// getters, setters, toString
}
See also:
Jackson nested values
unwrap inner json object using jackson

Unable to parse json with List elements inside it

I have a Java class which has 2 List Object inside it and i am Json serializing the parent class.
#JsonSerialize
public class RequestSalesJson {
#JsonProperty("nonUniqueSalesList")
private List<SalesDataJson> getNonUniqueSalesDataJson;
#JsonProperty("uniqueSalesList")
private List<SalesDataJson> uniqueSalesDataJson;
public List<SalesDataJson> getGetNonUniqueSalesDataJson() {
return getNonUniqueSalesDataJson;
}
public void setGetNonUniqueSalesDataJson(List<SalesDataJson> getNonUniqueSalesDataJson) {
this.getNonUniqueSalesDataJson = getNonUniqueSalesDataJson;
}
public List<SalesDataJson> getUniqueSalesDataJson() {
return uniqueSalesDataJson;
}
public void setUniqueSalesDataJson(List<SalesDataJson> uniqueSalesDataJson) {
this.uniqueSalesDataJson = uniqueSalesDataJson;
}
}
SalesReturnJson.java
#JsonSerialize
public class SalesReturnJson {
#JsonProperty("starttime")
private String startTime;
#JsonProperty("pn")
private String partNumber;
#JsonProperty("so")
private String SalesOrderNumber;
#JsonProperty("wo")
private String workOrderNumber;
#JsonProperty("loc")
//other variables declared..
}
Controller.java :-
#RequestMapping(value = "/addAllSalesData",method = RequestMethod.POST)
public void addAllSalesData(#RequestBody RequestSalesJson requestSalesJsons){
log.info("POST : '/addSalesData'");
try{
System.out.print("In Controller "+requestSalesJsons.getUniqueSalesDataJson());
//salesService.processSalesData(requestSalesJsons);
}
catch(Exception e){
// return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}
}
The value here is coming to be null.
Below is the json i am using :-
{ "uniqueSalesJson": [{"SO":4000955,"Part Number":"000","Locator":255638,"Lot Number":"P01-2059139","Reservation Quantity":2,"Status":"Released to warehouse","COE":"Fabrication","ORG":"P07","Start_Time":"2017-09-19 11:21:36"},{"SO":4000955,"Part Number":"000","Locator":255652,"Lot Number":"P01-2059140","Reservation Quantity":10,"Status":"Released to warehouse","COE":"Fabrication","ORG":"P07","Start_Time":"2017-09-19 11:21:36"}],"nonUniqueSalesJson":[{"SO":4000992,"Part Number":"1276M84G15","Locator":12345,"Lot Number":"P01-2344141","Reservation Quantity":6,"Status":"PACKED","COE":"Fabrication","ORG":"P07","Start_Time":"2017-09-19 11:21:36"},{"SO":4000992,"Part Number":"1276M84G15","Locator":12345,"Lot Number":"P01-2344141","Reservation Quantity":6,"Status":"PICKED","COE":"Fabrication","ORG":"P07","Start_Time":"2017-09-19 11:21:36"}]}
There are some issues in your code that let me doubt that your application compiles. First of all, rename the SalesReturnJson class to SalesDataJson.
Then check your #JsonProperty annotations. The value here must match exactly the property key in the Json String. Refactoring all this stuff will lead you to your root entity class:
#JsonSerialize
public class RequestSalesJson {
#JsonProperty("nonUniqueSalesJson")
private List<SalesDataJson> nonUniqueSalesDataJson;
#JsonProperty("uniqueSalesJson")
private List<SalesDataJson> uniqueSalesDataJson;
...
}
and your SalesDataJson class (missing a lot of attributes which the mapper ignores by configuration):
#JsonSerialize
public class SalesDataJson {
#JsonProperty("Start_Time")
private String startTime;
#JsonProperty("Part Number")
private String partNumber;
#JsonProperty("SO")
private String SalesOrderNumber;
}
This sample works as expected with the com.fasterxml.jackson.databind.ObjectMapper
Hope that helps!

Serializing JSON string to object

I am trying to parse through a JSON string and convert it to the following POJO:
package apicall;
//POJO representation of OAuthAccessToken
public class OAuthAccessToken {
private String tokenType;
private String tokenValue;
public OAuthAccessToken(String tokenType,String tokenValue) {
this.tokenType=tokenType;
this.tokenValue=tokenValue;
}
public String toString() {
return "tokenType="+tokenType+"\ntokenValue="+tokenValue;
}
public String getTokenValue() {
return tokenValue;
}
public String getTokenType() {
return tokenType;
}
}
In order to do this I have written the following code:
Gson gson=new Gson();
String responseJSONString="{\"access_token\" : \"2YotnFZFEjr1zCsicMWpAA\",\"token_type\" : \"bearer\"}";
OAuthAccessToken token=gson.fromJson(responseJSONString, OAuthAccessToken.class);
System.out.println(token);
When I run the code, I get the following output:
tokenType=null
tokenValue=null
Instead of
tokenType=bearer
tokenValue=2YotnFZFEjr1zCsicMWpAA
I don't understand if there's anything I've done wrong. Please help.
You can get the expected result by annotating your fields like:
#SerializedName("token_type")
private final String tokenType;
#SerializedName("access_token")
private final String tokenValue;
How is Gson supposed to know how to populate your object? You don't have a no-arg constructor, and the fields of your object don't match the fields in the JSON object.
Make your object as following:
public class OAuthAccessToken {
private String accessToken;
private String tokenType;
OAuthAccessToken() {
}
...
}
The class should have the exact field name as the json, so if your json have 2 keys: "access_token" and "token_type", the class should have 2 fields:
private String access_token;
private String token_type;
And, of course you need to change the getters/setters accordingly.

Categories