I would like to know is there a way (probably using deserialiser) in Jackson to copy one attribute value to another object attribute the container has.
For example, documentId from the TestData class also needs to be persisted in the Details.documentId attribute.
json/TestData.json
{
"id": "1",
"documentId" : "234234",
"details" : {
"name": "test",
"lastName": "asdf"
}
}
#RequiredArgsConstructor(onConstructor_ = #Autowired)
#SpringBootTest(classes = ExampleMicroserviceApplication.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
#ActiveProfiles("test")
public class TestDocumentId {
final ObjectMapper objectMapper;
#Value("classpath:json/TestData.json")
Resource testData;
#SneakyThrows
#Test
void testDocumentIdPresentInDetails() {
var data = objectMapper.readValue(testData.getFile(), TestData.class);
assertThat(data.documentId).isNotNull();
assertThat(data.getDetails().name).isNotNull();
assertThat(data.getDetails().documentId).isNotNull();
}
#Data
public static class TestData {
private String id;
private String documentId;
private Details details;
#Data
public static class Details {
private String documentId;
private String name;
private String lastName;
}
}
}
Related
I have my API which takes a FileImportInput and this has the following model
FileImportInput {
private String importType;
private String resourceUri;
#JsonProperty("settings")
private MriImportRequest settings;
}
This MriImportRequest is the base class with the following fields
#JsonTypeInfo(use = Id.NAME, include = As.WRAPPER_OBJECT, property = "settings")
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonSubTypes({
#JsonSubTypes.Type(value = MriExcelImportRequest.class, name = "sheets"),
#JsonSubTypes.Type(value = MriTextFileImportRequest.class, name = "files")
})
public class MriImportRequest {
private int folderId;
private String locale;
private String currency;
}
Below are other two classes with the following definitions.
#JsonTypeName("files")
public class MriTextFileImportRequest extends MriImportRequest {
private int accountsFileId;
private int locationsFileId;
private int reinsuranceFileId;
private int mappingFileId;
}
The other class is as follows
#JsonTypeName("sheets")
public class MriExcelImportRequest extends MriImportRequest {
private int accountsSheetIndex;
private int locationsSheetIndex;
private int reinsuranceSheetIndex;
private int mappingFileIndex;}
The request JSON is below, When i make a request, Unrecognized field "files" I am not sure whats missing. The request Json is below
{
"importType": "mri",
"resourceUri": "riskdata/v1/exposuresets/es1/exposures/sdfd-2232-skdj-3434/portfolios/12",
"settings": {
"files": {
"accountsFileId": 5387,
"locationsFileId": 5388,
"reinsuranceFileId": 5389,
"mappingFileId": 5390
},
"folderId": 1686,
"currency": "USD",
"locale": "US"
}
}
The JsonTypeInfo.As#WRAPPER_OBJECT is used for serialization while you are trying to deserialize your json, so no use for it in this case. Instead you can use the JsonTypeInfo.Id#DEDUCTION to deduce types based on the fields available (in this case if files property is available the value will be automatically deserialized to the MriTextFileImportRequest subclass:
#Data
public class FileImportInput {
private String importType;
private String resourceUri;
#JsonProperty("settings")
private MriImportRequest settings;
}
#Data
#JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
#JsonSubTypes({
#JsonSubTypes.Type(value = MriTextFileImportRequest.class)
})
public class MriImportRequest {
private int folderId;
private String locale;
private String currency;
}
#Data
public class MriTextFileImportRequest extends MriImportRequest {
private Files files;
}
#Data
public class Files {
private int accountsFileId;
private int locationsFileId;
private int reinsuranceFileId;
private int mappingFileId;
}
Then the code below prints the json input file:
FileImportInput fileImportInput = mapper.readValue(json, FileImportInput.class);
//ok it prints the input json file
System.out.println(mapper.writeValueAsString(fileImportInput));
I got a JSON response like this:
{
"status": "success",
"response": {
"entries": [
{
"id": 1,
"value": "test"
},
{
"id": 2,
"value": "test2"
}
]
}
}
And i want to map it with jackson-databind on an object like this:
public class Response {
#JsonProperty("status")
private String status;
#JsonProperty("response.entries")
private Collection<ResponseEntry> entries;
}
So i'm searching for an way to give #JsonProperty a path so it can skip the layer "response".
Welcome to Stack Overflow. You can define a wrapper class for your Collection<ResponseEntry> collection like below :
public class ResponseWrapper {
#JsonProperty("entries")
private Collection<ResponseEntry> entries;
}
The ResponseEntry class could be defined like below :
public class ResponseEntry {
#JsonProperty("id")
private int id;
#JsonProperty("value")
private String value;
}
Once defined these classes you can rewrite your old Response class like below :
public class Response {
#JsonProperty("status")
private String status;
#JsonProperty("response")
private ResponseWrapper responseWrapper;
}
You can flatten using the #JsonUnwrapped annotation.
You can have your classes like this
public class Response {
private String status;
private Collection<ResponseEntry> entries;
}
public class ResponseEntry {
#JsonUnwrapped
private Entry entry;
}
pubic class Entry{
private Integer id;
private String value;
}
Below is the json for pojo creation. I want to create a pojo using Lombok.
I am new to rest assured. How can I create a pojo using Lombok in Eclipse. I want in for nested json, like below Jira API post body request.
{
"fields": {
"project": {
"key": "RA"
},
"summary": "Main order flow broken",
"description": "Creating my fist bug",
"issuetype": {
"name": "Bug"
}
}
}
I have created the below pojo manually, and I am not sure if it's correct. How can I call the generated pojo in post body?
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class createissue {
private fieldss fields;
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public static class fieldss {
private Project poject;
private Sting summary;
private String description;
private Issuetype issuetypessuetype;
}
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public static class Project {
private Sting key;
}
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public static class Issuetype {
private Sting name;
}
}
The POJO is correct, It had some typos which I have corrected
public class Lombok {
public static #Data class fieldss {
private Project project;
private String summary;
private String description;
private Issuetype issuetype;
}
public static #Data class createissue {
private fieldss fields;
}
public static #Data class Issuetype {
private String name;
}
public static #Data class Project {
private String key;
}
}
and the below is how you can test
public static void main(String[] args) {
// TODO Auto-generated method stub
Issuetype a1 = new Issuetype();
a1.setName("Bug");
Project a2 = new Project();
a2.setKey("RA");
fieldss a3 = new fieldss();
a3.setDescription("Creating my fist bug");
a3.setSummary("Main order flow broken");
a3.setIssuetype(a1);
a3.setProject(a2);
createissue a4 = new createissue();
a4.setFields(a3);
ObjectMapper mapper = new ObjectMapper();
String abc = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(a4);
System.out.println(abc);
}
You should be able to see the below in the console
{
"fields": {
"project": {
"key": "RA"
},
"summary": "Main order flow broken",
"description": "Creating my fist bug",
"issuetype": {
"name": "Bug"
}
}
}
I am trying to map a String (with json values) to my POJO but getting a null when I do that.
Can I get some advivec on what I am doing wrong pls. They are matching up correctly from what I see.
I have the following String:
"{\"identifier_type\":\"TEST\",\"simple_construct_response\":[{\"identifier\":\"123451234512435\",\"customer_id\":\"\",\"trim_code\":\"DDD\",\"trim_reason_code\":\"\",\"simple_products\":[{\"product_name\":\"ABC_CPS_ABCD\",\"product_presentment_timestamp\":\"2019-02-28 06:07:20:383\"}]}]}"
It would conform to the following structure.
{
"identifier_type": "TEST",
"simple_construct_response": [
{
"identifier": "123451234512435",
"customer_id": "",
"trim_code": "DDD",
"trim_reason_code": "",
"simple_products": [
{
"product_name": "ABC_CPS_ABCD",
"product_presentment_timestamp": "2019-02-28 06:07:20:383"
}
]
}
]
}
This is my code where the output is null when I map.
String response = "{\"identifier_type\":\"TEST\",\"simple_construct_response\":[{\"identifier\":\"123451234512435\",\"customer_id\":\"\",\"trim_code\":\"DDD\",\"trim_reason_code\":\"\",\"simple_products\":[{\"product_name\":\"ABC_CPS_ABCD\",\"product_presentment_timestamp\":\"2019-02-28 06:07:20:383\"}]}]}";
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
MainResponse output = mapper.readValue(response, MainResponse.class); // this results in null
These are my POJOs to match above string.
#Getter
#Setter
public class MainResponse {
private String identifierType;
private List<SimpleConstructResponse> simpleConstructResponse;
}
#Getter
#Setter
public class simpleConstructResponse {
private String identifier;
private String customerId;
private String trimCode;
private String trimReasonCode;
private List<SimpleProduct> simpleProducts;
}
#Getter
#Setter
public class SimpleProduct {
private String productName;
private String productPresentmentTimestamp;
}
Instead of
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
write following code
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
For the most part,
the fields in your JSON do not match the fields in your class.
Because of this,
you must identify the field mapping for Jackson.
Jackson provides a way to identify the field name in the JSON and to
associate it with a field in the Java class;
the #JsonProperty annotation.
Here is some example code:
#Getter
#Setter
public class MainResponse
{
#JsonProperty("identifier_type")
private String identifierType;
#JsonProperty("simple_construct_response")
private List<SimpleConstructResponse> simpleConstructResponseList;
}
#Getter
#Setter
public class SimpleConstructResponse
{
private String identifier;
#JsonProperty("customer_id")
private String customerId;
#JsonProperty("trim_code")
private String trimCode;
#JsonProperty("trim_reason_code")
private String trimReasonCode;
#JsonProperty("simple_products")
private List<SimpleProduct> simpleProducts;
}
#Getter
#Setter
public class SimpleProduct
{
#JsonProperty("product_name")
private String productName;
#JsonProperty("product_presentment_timestamp")
private String productPresentmentTimestamp;
}
I want to deserialize the following JSON object:
{
"id":"001",
"module_name":"Users",
"name_value_list":
{
"user_name": {"name":"user_name", "value":"admin"},
"full_name": {"name":"full_name", "value":"LluĂs Pi"},
"city": {"name":"full_name", "value":"Barcelona"},
"postal_code": {"name":"postal_code", "value":"08017"},
...
}
}
into some Java object like this:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE)
public class UserEntry
{
private String id;
private String moduleName;
private Person nameValueList;
public String getId()
{
return id;
}
public String getModuleName()
{
return moduleName;
}
public Person getPerson()
{
return nameValueList;
}
}
where Person is the following class:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE)
class Person
{
private String userName;
private String fullName;
private String city;
private String postalCode;
}
using Jackson but I get a deserialization error.
If I change the type of field nameValueList to a Map all the deserialization process goes with no problem and I get a map where the key is the "name" value and the value is the "value" value.
So my question is: is there any simple, or no so simple, way to deserialize this kind of JSON object to a Java Pojo with properties prop_1, prop_2, prop_3and prop_4?
{
"name_value_list":
{
"prop_1": {"name":"prop_1", "value":"value_1"},
"prop_2": {"name":"prop_2", "value":"value_2"},
"prop_3": {"name":"prop_3", "value":"value_3"},
"prop_4": {"name":"prop_4", "value":"value_4"},
...
}
}
Not very simple and not very clean. However you can do it by implementing a any setter field for the JSON attributes in the Person class which don't match any attribute on your UserEntry POJO.
#JsonAnySetter
public void putUserField(String userKey, Map<String, String> userValue)
throws NoSuchFieldException {
String actualFieldName = getActualFieldName(userKey);
Field field = this.getClass().getDeclaredField(actualFieldName);
field.setAccessible(true);
ReflectionUtils.setField(field, this, userValue.get("value"));
}
private String getActualFieldName(String userKey) {
return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, userKey);
}
In addition to that, I had to change the Jackson attributes for the Person class to
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
getterVisibility = JsonAutoDetect.Visibility.NONE)
for it to work for attributes like "city" which don't need any name transformation because jackson tries to directly set the field which fails.