Convert multiple json object into array of object in Java - java

My data is currently stored in this format:
{
"label":["X","Y"],
"data":{
"site1":{
"week":[
{
"idWeek":"9",
"max":2,
"min":0
}
]
},
"site2":{
"week":[
{
"idWeek":"9",
"max":2,
"min":0
}
]
}
}
}
And I need to convert it into this format:
{
"label":["X","Y"],
"myClient":{
"week":[
{
"id":"9",
"access":2,
"lost":0
}
]
}
}
As you can see, I also need to take the keys (site name) and I need remove "data" and change name of property.
Any ideas on how I can do this in Java (I'm using Java 8 with Spring Boot? I'm not very good at restructuring that type of data.
UPDATE
My solutions: I did different interfaces and I used RestTemplate! I don't know it's the best solution however it worked.
public Optional<Consolidate> getCasosPorEstado() {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Consolidate> res = restTemplate.exchange(PATH_CONSOLIDATE, HttpMethod.GET, null,
new ParameterizedTypeReference<Consolidate>() {
});
return Optional.of(res.getBody());
}
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({ "label", "data" })
#Data
public class Consolidate {
#JsonProperty("label")
private List<String> labels = null;
#JsonProperty("data")
private MyClient client;
}
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({ "site1" })
class MyClient {
#JsonProperty("Site")
Site SiteObject;
}
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({ "week" })
class MS {
#JsonProperty("week")
private List<Week> week = null;
}
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class Semana {
#JsonAlias("idWeek")
private String id;
#JsonAlias("max")
private Double access;
#JsonAlias("min")
private Double lost;
}

Related

Ignore enclosing braces with JSON parser while serializing object in Java

I have the following classes:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class User {
private String id;
private List<Reference> references;
.....
}
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Reference {
#JacksonXmlProperty(isAttribute = true)
private String ref;
public Reference(final String ref) {
this.ref = ref;
}
public Reference() { }
public String getRef() {
return ref;
}
}
When serializing to XML the format is as expected, but when I try to serialize to JSON I get the following
"users" : [
{
"references" : [
{
"ref": "referenceID"
}
]
}
]
And I need it to be:
"users" : [
{
"references" : [
"referenceID"
]
}
]
the braces enclosing the reference list I need it to be ignored without the attribute name
You can annotate the ref field in your Reference class with the JsonValue annotation that indicates that the value of annotated accessor is to be used as the single value to serialize for the instance:
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Reference {
#JacksonXmlProperty(isAttribute = true)
#JsonValue //<-- the new annotation
private String ref;
public Reference(final String ref) {
this.ref = ref;
}
public Reference() { }
public String getRef() {
return ref;
}
}
User user = new User();
user.setReferences(List.of(new Reference("referenceID")));
//it prints {"references":["referenceID"]}
System.out.println(jsonMapper.writeValueAsString(user));
Edit: it seems that the JsonValue annotation invalidates the serialization of the class as expected by the OP; to solve this problem one way is the use of a mixin class for the Reference class and putting inside the JsonValue annotation, the original Reference class will be untouched:
#Data
public class MixInReference {
#JsonValue
private String ref;
}
ObjectMapper jsonMapper = new ObjectMapper();
//Reference class is still the original class
jsonMapper.addMixIn(Reference.class, MixInReference.class);
////it prints {"references":["referenceID"]}
System.out.println(jsonMapper.writeValueAsString(user));

How to make serialize missing fields in JSON String with jackson

I am reading a JSON String where every field is optional and i need to either get the values from config or set it to a default value.
Say my JSON is -
{
"action": {
"onWarning":{
"alert":{
"isEnabled": true,
"name": "DVS.sd_service.data-validation.bigdata.warning"
}
},
"onError":{
"alert":{
"isEnabled": false,
"name": "DVS.sd_service.data-validation.bigdata.error"
}
}
}
}
And my code to read this JSON is -
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.registerModule(new Jdk8Module());
JobConfig jobConfig = mapper.readValue(contentJson, JobConfig.class);
And below are my wrapper classes -
#AllArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class JobConfig {
public Optional<AlertConfig> action;
}
#AllArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class AlertWrapper {
public Optional<Alert> alert;
}
#AllArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class AlertConfig {
public Optional<AlertWrapper> onSuccess;
public Optional<AlertWrapper> onWarning;
public Optional<AlertWrapper> onError;
}
#AllArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class Alert{
public Optional<Boolean> isEnabled;
public Optional<String> name;
}
Now the objective here is to read OnError.alert.isEnabled however if this field or the entire onError part is not available then we have to set it to default True
The function i have written for this is :-
private Optional<Boolean> getErrorIsEnabled(JobConfig jobConfig ) {
Optional<Boolean> isEnabled = Optional.empty();
if(jobConfig.action.isPresent()) {
if(jobConfig.action.get().onError.isPresent()){
if(jobConfig.action.get().onError.get().alert.isPresent()) {
if(jobConfig.action.get().onError.get().alert.get().isEnabled.isPresent()){
isEnabled= jobConfig.action.get().onError.get().alert.get().isEnabled;
}
}
}
}
return isEnabled;
}
This way i get to find if the vale is available in config by calling the above function -
getErrorIsEnabled(jobConfig).orElse(true)
The problem is (calling the above function) this works but looks way too ugly to keep on checking if the fields are available or not at every level by calling the isPresent() funtion.
The User can entirely skip the OnError Part, or action Part, or just the alert part, or the alert.isEnabled part. There has to be a better way to acieve this! Open to suggestions or improvements or try a different approach alltogether.
What you should do is create default values for the fields like
private Optional<Boolean> isEnabled = Optional.empty();
private Optional<String> name = Optional.empty();
public Alert(Optional<Boolean> isEnabled , Optional<String> name){
this.isEnabled=isEnabled;
this.name=name;
}
And for every Object like this -
private final Alert alertDetail = new Alert(Optional.empty(), Optional.empty());
private final AlertWrapper alertWrapper = new AlertWrapper(alertDetail);
private AlertWrapper onSuccess = alertWrapper;
private AlertWrapper onWarning = alertWrapper;
private AlertWrapper onError = alertWrapper;
You will have to create constructor so you will have to change your lombok to #NoArgsConstructor also use #Getter #Setter so you can call your objects like below -
jobConfig.getAction().getOnWarning().getAlert().getIsEnabled().orElse(true)

Deserializing JSON in Java using Jackson

I have the following sample fragment of JSON I am trying to deserialize.
{
"total": 2236,
"issues": [{
"id": "10142",
"key": "ID-2",
"fields": {
"attachment": [{
"id": "11132"
}]
}
}]
}
I can deserialize the data up to id and key, but cannot deserialize attachments that is in fields. My attachment class is always null
Here's my code.
Response.java
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class Response {
#JsonProperty
private int total;
#JsonProperty
private List<Issue> issues;
}
Issue.java
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class Issue {
#JsonProperty
private int id;
#JsonProperty
private String key;
#JsonProperty
private Fields fields;
}
Fields.java
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class Fields {
#JsonProperty
private Attachments attachment;
}
Attachments.java
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class Attachments {
#JsonProperty
private List<Attachment> attachment;
}
Attachments.java
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class Attachment {
#JsonProperty
private String id;
}
In your JSON, attachment is an array, not an object.
You don't need an Attachments class, just modify Fields this way:
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class Fields {
#JsonProperty
private List<Attachment> attachment;
}
Think of each variable in your Java classes as corresponding to an attribute in the JSON. "Attachments" is not in the JSON file. You should be able to remove it and change the variable definition in the Fields class.
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class Fields {
#JsonProperty
private List<Attachment> attachment;
}
If you don't want to change class structure then, you can modify JSON.
In attachment, you need to add again an attachment.
JSON would be like below.
{
"total":2233,
"issues":[
{
"id":"13598",
"key":"ID-2368",
"fields":{
"attachment":{
"**attachment**":[
{
"id":"11122"
}
]
}
}
}
]
}

Generic POJO for JSON Object that can take different type of values

I have a json payload (request payload of a rest api) with a defined schema, but there is one property that can take an array of unknown key value pairs. The value for each property can be of different type like number, string, array, range, date, etc. How do i create a POJO for this property and make deserialization work for the same?
I am currently thinking about writing a custom deserializer for my Property class, where i check the type of value and do some custom logic accordingly.
This looks like a typical requirement. I feel that there should be something available in Jackson or Gson that i am missing. I would love to reuse if it already exist. I looked around in SO, but couldnt find a good answer so far. Any suggestions would be appreciated.
{
"id": 1234,
"name": "test name 1",
"properties": [
{
"key_a": 100
},
{
"key_b": [
"string1",
"string2",
"string3"
]
},
{
"key_c": {
"range": {
"min": 100,
"max": 1000
}
}
}
]
}
I am thinking my POJO for property object would look something like this.
class Property {
private String key;
private Value value;
}
It is possible to use inheritance for that. This is the classes for your example with Jackson
public class Sample {
#JsonProperty(value = "id")
Integer id;
#JsonProperty(value = "name")
String name;
#JsonProperty(value = "properties")
List<Property> properties;
}
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.WRAPPER_OBJECT)
#JsonSubTypes({
#JsonSubTypes.Type(value = KeyA.class, name = "key_a"),
#JsonSubTypes.Type(value = KeyB.class, name = "key_b"),
#JsonSubTypes.Type(value = KeyC.class, name = "key_c")
})
public abstract class Property {
}
public class KeyA extends Property{
Integer value;
public KeyA(Integer value) {
this.value = value;
}
#JsonValue
public Integer getValue() {
return value;
}
}
public class KeyB extends Property {
List<String> valueList;
#JsonCreator
public KeyB( List<String> valueList) {
this.valueList = valueList;
}
#JsonValue
public List<String> getValueList() {
return valueList;
}
}
public class KeyC extends Property {
#JsonProperty(value = "range")
Range value;
}
public class Range {
#JsonProperty(value = "min")
Integer min;
#JsonProperty(value = "max")
Integer max;
}
If I understand correctly you want to change to JSON and back. I wrote a small class for my own SpringBoot project, using ObjectMapper
#Component
public final class JsonUtils {
private final ObjectMapper mapper;
#Autowired
public JsonUtils(ObjectMapper mapper) {
this.mapper = mapper;
}
public String asJsonString(final Object object) {
try {
return mapper.registerModule(new JavaTimeModule())
.writeValueAsString(object);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/*
* Customized Objectmapper for reading values compatible with this class' other methods
* #Return the desired object you want from a JSON
* IMPORTANT! -your return object should be a class that has a #NoArgsConstructor-
*/
public Object readValue(final String input, final Class<?> classToRead) {
try {
return mapper
.readValue(input, classToRead);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}`
Perhaps it can be of some use to you.

Why are some of the variables in POJO equal to null after converting JSON RESTful Webservice?

I am consuming a RESTful webservice that returns a JSON payload. I can successfully consume the RESTful webservice and manage to populate some of the POJO attributes with JSON data. However, some other attributes are null when they are supposed to contain a value. How can I ensure that there are no more nulls?
I have defined 4 POJO classes. I have so far debugged by systematically by testing the variables for each class. This is using Springboot 2.2.0 and Jackson-databind.
The JSON schema I am trying to consume:
{
"items":[
{
"timestamp":"2019-09-18T16:42:54.203Z",
"carpark_data":[
{
"total_lots":"string",
"lot_type":"string",
"lots_available":"string"
}
]
}
]
}
For the above, I defined 4 classes:
public class Response {
#JsonProperty
private List<items> i;
#JsonIgnoreProperties(ignoreUnknown = true)
public class items {
private String timestamp;
private List<carpark_data> cpd;
#JsonIgnoreProperties(ignoreUnknown = true)
public class carpark_data {
private List<carpark_info> cpi;
private String carpark_number;
private String update_datetime;
#JsonIgnoreProperties(ignoreUnknown = true)
public class carpark_info {
private int total_lots;
private String lot_type;
private int lots_available;
When I run the below in Spring boot Main: I get null. Is my POJO modeling OK?
Response resp = restTemplate.getForObject("")
c = resp.getItems().get(0).getCarpark_data().get(0);
log.info("The last update time for the car park data = " +
c.getUpdateDatetime());
Your model does not fit to JSON payload. If we assume that JSON payload has a structure like below:
{
"items": [
{
"timestamp": "2019-09-18T16:42:54.203Z",
"carpark_data": [
{
"total_lots": "1000",
"lot_type": "string",
"lots_available": "800"
}
]
}
]
}
We can deserialise it as below:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.util.List;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
Response response = mapper.readValue(jsonFile, Response.class);
System.out.println(response.getItems().get(0).getData().get(0));
}
}
class Response {
private List<Item> items;
//getters, setters, toString
}
class Item {
private String timestamp;
#JsonProperty("carpark_data")
private List<CarParkInfo> data;
//getters, setters, toString
}
class CarParkInfo {
#JsonProperty("total_lots")
private int totalLots;
#JsonProperty("lot_type")
private String lotType;
#JsonProperty("lots_available")
private int lotsAvailable;
//getters, setters, toString
}
Above code prints:
CarParkInfo{totalLots=1000, lotType='string', lotsAvailable=800}
Hope you find the solution.
It is in POJO, you need to check the fieldName and object structure.
Seeing the Json above, your response model returns list of items and in each item you have list of carpark_data. So, basic modelling should be like this. And you can include respective setter and getter.
public class Response {
#JsonProperty
private List<items> items;
#JsonIgnoreProperties(ignoreUnknown = true)
public class items {
private String timestamp;
private List<carpark_data> carpark_data;
#JsonIgnoreProperties(ignoreUnknown = true)
public class carpark_data {
private int total_lots;
private String lot_type;
private int lots_available;
}
You need to have fields name in POJO class same in the Json response or you can set JsonProperty for that field. Like this
#JsonProperty("items")
private List<items> i;
#JsonProperty("carpark_data")
private List<carpark_data> cpd;

Categories