GSON Json Mapping for HashMap Nested Object - java

I have a json context like below:
{
"data": {
"details": {
"en-CA": {
"languageCode": "en-CA",
"isPrimaryLocale": false
},
"en-US": {
"languageCode": "en-US",
"isPrimaryLocale": true,
"languageDisplayName": "English (United States)",
}
}
}
}
To map it with GSON in java:
I created this classes:
public class ApiResponseSingleDto
{
private ResponseDetail data;
}
public class ResponseDetail
{
private ResponseDetails details;
#Getter
public static class ResponseDetails
{
public HashMap<String, LocaleDetail> row = new HashMap<>();
}
}
public class LocaleDetail
{
private String languageCode;
private Boolean isPrimaryLocale;
private String languageDisplayName;
}
When I try to map json to Java POJO class, HashMap doesn't work. Is there any suggestion?
To map it:
GSON.fromJson("...json", Type type...);

Just try to replace:
public class ApiResponseSingleDto
{
private ResponseDetail data;
}
public class ResponseDetail
{
private Map<String, LocaleDetail> details;
}
public class LocaleDetail
{
private String languageCode;
private Boolean isPrimaryLocale;
private String languageDisplayName;
}
Also json seems to be incorrect: "languageDisplayName": "English (United States)",
should be just "languageDisplayName": "English (United States)"
One more note: I believe you should have public fields or at least getters for them

Related

Deserialize json to java object using jackson. Design Patterns

json:
{
"events": [
{
"child_id": "unknown",
"some_info": "text",
"data": {
<some string>: {
"id": 1,
"prop": "propValue"
}
}
},
{
"child_id": "known",
"some_info": "text1",
"data": {
"id": 2,
"prop": "propValue1"
}
]
}
i am using structure like this:
public inteface EventService {
void handle();
}
public class EventsDto {
private List<Event> events;
//getter, setter, constructors
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "child_id")
#JsonSubTypes({
#JsonSubTypes.Type(value = UnknownEvent.class, name = "unknown"),
#JsonSubTypes.Type(value = KnownEvent.class, name = "known")
})
public static abstract class Event implements EventService {
#JsonProperty("some_info")
private String someInfo;
//getter, setter, constructors
}
}
public class UnknownEvent extends EventsDto.Event {
private JsonNode data;
//getter, setter, constructors
#Override
public void handle() {
//something is happening
}
}
public class KnownEvent extends EventsDto.Event {
private Data data;
//getter, setter, constructors
#Override
public void handle() {
//something is happening
}
public static class Data {
private Integer id;
private String prop;
//getters, setters, constructors
}
}
public class Main {
public static void main(String[] args) {
String json = "<json>";
EventsDto eventsDto = objectMapper.readValue(json, EventsDto.class);
eventsDto.getEvents().forEach(event -> event.handle());
}
}
Is it possible to do something with UnknownEvent, to deserialize into a java object with all fields like KnownEvent without using JsonNode?
some string in json is dynamic and cannot be known in advance.
How can I pull the implementation of the "handle" method from the DTO into a separate class? If possible - do not change the logic of the main class.
I would like to hear advice on how to improve the code.

How to map attribute value into two fields during Jackson deserialisation

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;
}
}
}

Jackson-databind mapping JSON skip layer

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;
}

Deserialising complex nested Json using Jackson

I am struggling to deserialise complex nested Json data into Java objects I think my class structure is wrong. Here is my Json data:
{
"resultsPerPage": 20,
"startIndex": 0,
"totalResults": 2,
"result": {
"dataType": "CPE",
"feedVersion": "1.0",
"cpeCount": 2,
"feedTimestamp": "2021-03-19T13:06",
"cpes": [
{
"deprecated": false,
"cpe23Uri": "cpe:2.3:o:microsoft:windows_10:1511:*:*:*:*:*:x64:*",
"lastModifiedDate": "2015-12-09T17:28Z",
"titles": [
{
"title": "Microsoft Windows 10 1511 64-bit",
"lang": "en_US"
}
],
"refs": [
{
"ref": "https://www.microsoft.com/en-us/",
"type": "Vendor"
}
],
"deprecatedBy": [],
"vulnerabilities": [
"CVE-2016-0174",
"CVE-2016-0171"
]
}
Here is the class I map the Json data to:
public class RESPONSE {
Result result;
}
class Result {
List<Cpes> cpes;
}
class Cpes {
String cpe23Uri;
List<Titles> titles;
List<String> vulnerabilities;
}
class Titles{
String title;
}
When I debug my code r in the below code is null and I think it's because my RESPONSE class isn't set up right.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
RESPONSE r = mapper.readValue(response.getContent(), RESPONSE.class);
System.out.println(r);
Your object model should match the structure of the JSON you are trying to read. For example, it'll have to look something like the following:
public class Response {
private int resultsPerPage;
private int startIndex;
private int totalResults;
private Result result;
// Should include getters and setters
}
public class Result {
private String dataType;
private String feedVersion;
private int cpeCount;
private String feedTimestamp;
private CPE[] cpes;
// Should include getters and setters
}
public class CPE {
private boolean deprecated;
private String cpe23Uri;
private String lastModifiedDate;
private Title[] titles;
private Ref[] refs;
private String[] deprecatedBy;
private String[] vulnerabilities;
// Should include getters and setters
}
public class Title {
private String title;
private String lang;
// Should include getters and setters
}
public class Ref {
private String ref;
private String type;
// Should include getters and setters
}
Note that to keep the code sample short, I've omitted the getters and setters.
Edit: As Tugrul pointed out below, since fail on unknown property is disabled, it won't fail if there are missing fields in your model. The only issue is the missing getters and setters.
I also found another way to solve this issue for future reference.
I used a tree data structure to access my Json fields which means I can just declare a flat class:
public class Test {
private String cpe23Uri;
private String title;
private List<String> vulnerabilities;
public String getCpe23Uri() {
return cpe23Uri;
}
public void setCpe23Uri(String cpe23Uri) {
this.cpe23Uri = cpe23Uri;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<String> getVulnerabilities() {
return vulnerabilities;
}
public void setVulnerabilities(List<String> vulnerabilities) {
this.vulnerabilities = vulnerabilities;
}
}
I then mapped using a Tree
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JsonNode resultNode = mapper.readTree(response.getContent());
Test t = new Test();
t.setCpe23Uri(resultNode.get("result").get("cpes").get(0).get("cpe23Uri").textValue());

How to generate pojo with Lombok for complex json in Eclipse

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"
}
}
}

Categories

Resources