Generate json request body using Lombok annotation - java

I tried multiple pattern , but still no success how can I create JSON Array object with nested JSON object similar like below
{
"deduction": [
{
"id": "50258779",
"amount": {
"value": 13.24,
"currency": "INR"
},
"transfer": "DEPOSIT",
"fund": "RL",
"description": "TD description",
"code": "codeNumber"
},
{
"id": "50258779",
"amount": {
"value": 13.24,
"currency": "INR"
},
"transfer": "DEPOSIT",
"fund": "RL",
"description": "TD description",
"code": "codeNumber"
}
]
}
I had generated Class to build this request schema :
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
#Builder
#Getter
#Setter
#JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Transf{
private List<Deduction> deduction;
#Builder
#Getter
#Setter
public class Deduction {
private Amount amount;
private String transfer;
private String code;
private String fund;
private String description;
private Integer id;
}
#Builder
#Getter
#Setter
public class Amount {
private String currency;
private Double value;
}
}
Trying to create json request body to be send using rest assured
public Transf trans()
{
return Transf.builder()
.deduction(Transf.Deduction.builder().transfer("")).build();
}
But getting syntax error on this , need to know how can I make this work

Instead of
Transf.Deduction.builder().transfer("")
you need to have
Transf.Deduction.builder().transfer("").build()

First, you define private List<Deduction> deduction; --> you will supply List.
Second, to make builder work, you have to call .build()
public Transf trans() {
return Transf.builder()
.deduction(Arrays.asList(Transf.Deduction.builder().transfer("").build()))
.build();
}

Related

Inner object deserialization with Jackson

I have a json
{
"params": [
{
"key": "path",
"options": {
"string": {
"prefix": "test_pref"
}
},
"default": {
"url": ""
}
}
]}
I have the following POJO class, where i want to map inner objects like option.string.prefix in json to prefix in Params POJO class.
#Data
#Accessors(chain = true)
public class Data {
private List<Params> params;
}
#Data
#Accessors(chain = true)
public class Params {
private String key;
#JsonProperty("options.string.prefix")
private String prefix;
#JsonProperty("default.url")
private String url;
}
Is there any Jackson annotation that helps me do this without #JsonProperty?
The is #JsonGetter which is an alternative to #JsonProperty You can read a very nice article on the topic here: Jackson Annotation Examples

Unable to find data in DTO from JSON object - parsing error ZonedDateTime

I am trying to convert the JSON timestamp object into Java
I have researched converting a JSON string to java but unsure what I'm looking for.
I can get it to work if the JSON uses an array but unfortunately it does not use this approach.
JSON Payload
{
"type": "RFID-read",
"event": {
"id": "3892fec6-9246-4699-ba86-99ab1df369a9",
"timestamp": "2020-11-19T15:01:11.391+0000",
"deviceId": "FX9600FB2D21",
"data": {
"format": "epc",
"id": "000000000000000000000115",
"reads": 1,
"rssi": -72,
"antennaId": "1"
}
},
"analytics": {
"tenant": "73876942a20c12550f996b2152e5ca9e",
"resourceId": "000000000000000000000115",
"location": "FX9600FB2D21",
"timestamp": "2020-11-19T15:01:11.391+0000",
"meta": {
"type": "inventory"
}
}
}
Event DTO
#Data
#Builder(toBuilder = true)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ZebraEventReadsDto {
private String id;
private ZonedDateTime timestamp;
#NotNull
#Size(min = 1, max = 100)
private String deviceId;
private String format;
ZebraDataReadsDto data;
Update DTO
#Data
#Builder(toBuilder = true)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ZebraLocationUpdateDto {
private String type;
ZebraEventReadsDto event;
public static List<LocationUpdateDom> toDomainModel(ZebraLocationUpdateDto zebraLocationUpdateDto) {
List<LocationUpdateDom> locationUpdateDomList = new ArrayList<>();
locationUpdateDomList.add(LocationUpdateDom.builder()
.deviceName(zebraLocationUpdateDto.zebraEventReadsDto.getDeviceId())
.dateTime(zebraLocationUpdateDto.zebraEventReadsDto.getTimestamp())
.tagId(zebraLocationUpdateDto.zebraEventReadsDto.data.getId())
.latLng(Optional.empty())
.build());
return locationUpdateDomList;
}
}
To resolving the parsing error I used the following annotation above my timestamp variable.
#JSONFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
private ZonedDateTime timestamp;
I can now return 200 OK

Using Jackson how to map JSONs to objects when it contains an object list

Here is my JSON Payload
{
"allEnvs": ["qa", "dev", "prestaging"],
"env": "qa",
"envUrls": [{
"qa": {
"cutomeUrl": "testUrl",
"adminUrl": "",
"webUrl": "https://test.try.val",
"salesUrl": ""
},
"dev": {
"cutomeUrl": "testUrl",
"webUrl": "",
"salesUrl": ""
},
"prestaging": {
"cutomeUrl": "testUrl",
"webUrl": "",
"salesUrl": ""
}
}],
"isCommonUsers": "true",
"commonUsers":[ {
"teacher": {
"fName": "test",
"lName": "test"
},
"student": {
"fName": "test",
"lName": "test"
},
"ta": {
"fName": "test",
"lName": "test"
}
}],
"commonCodes": ["test1", "test2", "test3"]
}
I would like to know how to map 'envUrls', 'commonUsers' for my 'Conf.class'
ObjectMapper mapper = new ObjectMapper();
CommonConf cnf = mapper.readValue( new File("src/main/resources/configs/config.json"), Conf.class);
envUrls and commonUsers properties can be represented by List<Map<String, PojoX>> type, where PojoX is EnvUrls or User from below model:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import lombok.Data;
import lombok.ToString;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
public class CommonConfApp {
public static void main(String[] args) throws IOException {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = JsonMapper.builder().build();
System.out.println(mapper.readValue(jsonFile, CommonConf.class));
}
}
#Data
#ToString
class CommonConf {
private List<String> allEnvs;
private String env;
private List<Map<String, EnvUrls>> envUrls;
private String isCommonUsers;
private List<Map<String, User>> commonUsers;
private List<String> commonCodes;
}
#Data
#ToString
class EnvUrls {
private String cutomeUrl;
private String adminUrl;
private String webUrl;
private String salesUrl;
}
#Data
#ToString
class User {
#JsonProperty("fName")
private String fName;
#JsonProperty("lName")
private String lName;
}
Lombok is used for removing boilerplate code. Above app prints:
CommonConf(allEnvs=[qa, dev, prestaging], env=qa, envUrls=[{qa=EnvUrls(cutomeUrl=testUrl, adminUrl=, webUrl=https://test.try.val, salesUrl=), dev=EnvUrls(cutomeUrl=testUrl, adminUrl=null, webUrl=, salesUrl=), prestaging=EnvUrls(cutomeUrl=testUrl, adminUrl=null, webUrl=, salesUrl=)}], isCommonUsers=true, commonUsers=[{teacher=User(fName=test, lName=test), student=User(fName=test, lName=test), ta=User(fName=test, lName=test)}], commonCodes=[test1, test2, test3])
You can annotate your class Conf with following:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Conf {
...
}
It ignores unknown properties while parsing JSON
Documention: JsonIgnoreProperties

Why is the Jackson Object Mapper unable to deserialize this nested JSON?

I am in the process of updating some code to hit a new API which returns the same type of data but in a different JSON format. This is a sample of the return from a request:
{
"code": 200,
"message": "OK",
"data": [
{
"start_time": "2017-09-20T00:00:00.000-04:00",
"end_time": "2017-09-21T00:00:00.000-04:00",
"value": 8612.637512577203
},
{
"start_time": "2017-09-21T00:00:00.000-04:00",
"end_time": "2017-09-22T00:00:00.000-04:00",
"value": 8597.89155775999
},
{
"start_time": "2017-09-22T00:00:00.000-04:00",
"end_time": "2017-09-23T00:00:00.000-04:00",
"value": 24584.603303989123
}
],
"meta": {
"space_id": "e1c38410-f912-4ae3-9db9-10a1ad1e3bf5",
"channel_id": 1,
"aggregation_type": "period_beginning",
"pids_count": 1,
"timezone": "America/New_York"
}
}
I want to ignore the code and message properties, and put the array of data into a list within a map, with the key being the "space_id" property (Map<String, List<Reading>>) for compatibility with the old implementation. Here is the POJO that I have created to contain the deserialized object:
#JsonIgnoreProperties({"code", "message", "meta"})
public class GetReadingsResult {
#JsonIgnore
private Map<String, List<Reading>> readings;
#JsonIgnore
public GetReadingsResult(Map<String, List<Reading>> readings) {
this.readings = readings;
}
#JsonCreator
public GetReadingsResult(#JsonProperty("data")Reading[] data, #JsonProperty("space_id")String spaceId) {
this.readings.put(spaceId, Arrays.asList(data));
}
//...other getters and setters...
}
In my test I am calling readValue on a test JSON file and getting the following error:
com.fasterxml.jackson.databind.JsonMappingException: Instantiation of [simple type, class model.GetReadingsResult] value failed: null
What is the proper way to set up/annotate my POJO to deal with this nested file?
This is the correct way to implement.
Please pay attention to object point of view of all thing:
These are the pojos:
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"start_time",
"end_time",
"value"
})
public class Datum {
#JsonProperty("start_time")
public String startTime;
#JsonProperty("end_time")
public String endTime;
#JsonProperty("value")
public Double value;
}
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"space_id",
"channel_id",
"aggregation_type",
"pids_count",
"timezone"
})
public class Meta {
#JsonProperty("space_id")
public String spaceId;
#JsonProperty("channel_id")
public Integer channelId;
#JsonProperty("aggregation_type")
public String aggregationType;
#JsonProperty("pids_count")
public Integer pidsCount;
#JsonProperty("timezone")
public String timezone;
}
This is the wrapper root Object:
import java.util.List;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"code",
"message",
"data",
"meta"
})
public class ExampleStack {
#JsonProperty("code")
public Integer code;
#JsonProperty("message")
public String message;
#JsonProperty("data")
public List<Datum> data = null;
#JsonProperty("meta")
public Meta meta;
}
And this is the working example:
import com.fasterxml.jackson.databind.ObjectMapper;//<--IMPORTANT!
public class TestJacksonObject {
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
ExampleStack stack = null;
try {
stack = mapper .readValue( new FileInputStream(new File("C://test.json")) , ExampleStack.class);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(stack.message);//<--Do whatever you want...
.....
If it's too hard to produce all these classes, which is actually tedious I suggest you to autoproduce them online through this useful site:
Json2Pojo
Hope it helps you out!

JsonMappingException: no single-String constructor/factory method

[This is not a duplicate of Can not instantiate value of type from JSON String; no single-String constructor/factory method: that is a far simpler POJO and JSON. The solution in my case was different as well.]
The JSON I want to parse and create a POJO from:
{
"test_mode": true,
"balance": 1005,
"batch_id": 99,
"cost": 1,
"num_messages": 1,
"message": {
"num_parts": 1,
"sender": "EXAMPL",
"content": "Some text"
},
"receipt_url": "",
"custom": "",
"messages": [{
"id": 1,
"recipient": 911234567890
}],
"status": "success"
}
If the response happens to be an error, it looks like:
{
"errors": [{
"code": 80,
"message": "Invalid template"
}],
"status": "failure"
}
Here's the POJO I have defined:
#Data
#Accessors(chain = true)
public class SmsResponse {
#JsonProperty(value = "test_mode")
private boolean testMode;
private int balance;
#JsonProperty(value = "batch_id")
private int batchId;
private int cost;
#JsonProperty(value = "num_messages")
private int numMessages;
private Message message;
#JsonProperty(value = "receipt_url")
private String receiptUrl;
private String custom;
private List<SentMessage> messages;
private String status;
private List<Error> errors;
#Data
#Accessors(chain = true)
public static class Message {
#JsonProperty(value = "num_parts")
private int numParts;
private String sender;
private String content;
}
#Data
#Accessors(chain = true)
public static class SentMessage {
private int id;
private long recipient;
}
#Data
#Accessors(chain = true)
public static class Error {
private int code;
private String message;
}
}
The annotations #Data (tells Lombok to automatically generate getters, setters, toString() and hashCode() methods for the class) and #Accessors (tells Lombok to generate the setters in such a way that they can be chained) are from Project Lombok.
Seems like a straightforward setup, but every time I run:
objectMapper.convertValue(response, SmsResponse.class);
I get the error message:
Can not instantiate value of type [simple type, class com.example.json.SmsResponse]
from String value ... ; no single-String constructor/factory method
Why do I need a single-string constructor for SmsResponse, and if so, which string do I accept in it?
To parse and map a JSON String with ObjectMapper you need to use the readValue method:
objectMapper.readValue(response, SmsResponse.class);

Categories