Jackson JSON deserialization - java

I am trying to deserialize the following Json payload using Jackson:
[{
"owner" : "345MWyh7w4hY98W6",
"url" : "http://www.google.com",
"items" : [{
"createdAt" : 1342099411415,
"amount" : 1,
"note" : "item 1",
"product" : "car"
}, {
"createdAt" : 1342100231111,
"amount" : 4,
"note" : "item 2",
"product" : "wheels"
}],
"createdAt" : 1342096943777,
"title" : "Car order",
"description" : "car order",
"id" : "98hw85Y945e6U358"
}]
I am using the following code to deserialize:
ObjectMapper mapper = new ObjectMapper().configure(
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
List<Order> result = null;
try {
result = mapper.readValue(jsonString,new TypeReference<List<Order>>() { });
} catch (IOException e) {
e.printStackTrace();
}
However I get the following error:
org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor aroundWriteTo
SEVERE: MessageBodyWriter not found for media type=application/json, type=class org.glassfish.jersey.client.InboundJaxrsResponse, genericTyp
e=class org.glassfish.jersey.client.InboundJaxrsResponse.
Feb 06, 2015 8:14:45 PM org.glassfish.jersey.filter.LoggingFilter log
The class Orders is generated by RAML -> JAX-RS maven plug-in and this does not have a zero argument constructor. Is there any way of doing this de-serialization other than modifying the generated class to add a zero-args constructor ?

Was able to fix with a work-around. I created a wrapper DTO over the Order as follows:
#XmlRootElement
public class OrderDTO {
private List<Order> orderList;
public List<Order> getOrderList() {
return orderList;
}
public void setOrderList(List<Order> orderList) {
this.orderList = orderList;
}
public void addOrder(Order order){
orderList.add(order);
}
public OrderDTO() {
super();
orderList = new ArrayList<Order>();
}
}
here I was able to add the zero-args constructor. Now it works :).

Related

Unwrap config settings during the serialisation

I try to make config manager for my app. I have some problems with Jackson. Here is my object mapper config:
val mapper = ObjectMapper()
val jackson = mapper.setVisibility(
mapper.getSerializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.NONE)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE)
)
.configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.enable(SerializationFeature.INDENT_OUTPUT)
and then we saving arraylist of modules.every module has
#JsonProperty("config") public ArrayList<SettingAbstract> settings = new ArrayList<SettingAbstract>( );
SettingAbstract have name and value. i did this
#JsonProperty("property") public abstract String saveCfg();
and then this in SettingAbstract child classes
#Override
public String saveCfg() {
return this.name + ": " + this.value;
}
The result JSON is:
..., {
"enabled" : false,
"name" : "ESP",
"config" : [ {
"property" : "Players: true"
}, {
"property" : "Mobs: false"
}, {
"property" : "Hostiles: false"
} ],
"currentSettingsPage" : 0
}, {
"enabled" : false,
"name" : "Custom Time",
"config" : [ {
"property" : "Ticks: 19000"
} ],
"currentSettingsPage" : 0
}, ...
What I want is:
..., {
"enabled" : false,
"name" : "ESP",
"Players": true",
"Mobs": "false",
"Hostiles": "false",
"currentSettingsPage" : 0
}, {
"enabled" : false,
"name" : "Custom Time",
"Ticks": "19000",
"currentSettingsPage" : 0
}, ...
Main problems:
how to remove theese [] <- from arraylist
how to remove {} <- from SettingAbstract class (because im saving only 1 property)
and how to save key as setting name (various modules has various settings)
You need to unwrap config property. It is a list, so you need to ignore it and add extra method which converts that list to Map. In Kotlin it could look like this:
#JsonAnyGetter
fun getSettingsAsMap(): Map<String, String>? {
return settings.stream().collect(Collectors.toMap(SettingAbstract::name, SettingAbstract::value));
}
And you need to ignore list:
#JsonIgnore public ArrayList<SettingAbstract> settings

Spring Data REST - Unrecognized field "_embedded" by consuming list of entities, Java HATEOAS

I am trying to consume a list of entities from the following REST HAL response:
{
"_embedded" : {
"posts" : [ {
"branch" : 1,
"article" : "aaaaaaa",
"featuredImage" : "aaaaaaa",
"authorId" : 1,
"datePublished" : "2020-05-05T09:11:13.336+0000",
"commentsEnabled" : true,
"enabled" : false,
"views" : 0,
"snippetTitle" : null,
"snippetDescription" : null,
"comments" : null,
"_links" : {
"self" : {
"href" : "http://localhost:8081/posts/1"
},
"post" : {
"href" : "http://localhost:8081/posts/1"
},
"categories" : {
"href" : "http://localhost:8081/posts/1/categories"
}
}
}, {
"branch" : 1,
"article" : "aaaaaaa",
"featuredImage" : "aaaaaaa",
"authorId" : 1,
"datePublished" : "2020-05-05T10:45:15.999+0000",
"commentsEnabled" : true,
"enabled" : false,
"views" : 0,
"snippetTitle" : null,
"snippetDescription" : null,
"comments" : null,
"_links" : {
"self" : {
"href" : "http://localhost:8081/posts/3"
},
"post" : {
"href" : "http://localhost:8081/posts/3"
},
"categories" : {
"href" : "http://localhost:8081/posts/3/categories"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8081/posts/search/byAuthorId?authorId=1&page=0&size=10"
}
},
"page" : {
"size" : 10,
"totalElements" : 3,
"totalPages" : 1,
"number" : 0
}
}
I would like to map these entities to this class:
#Setter
#Getter
#AllArgsConstructor
public class Post {
private int id;
private int branch;
private String article;
private Date datePublished;
private String featuredImage;
private Boolean commentsEnabled;
private Boolean enabled;
private int views;
private String snippetTitle;
private String snippetDescription;
}
However, I keep getting the error:
Unrecognized field "_embedded" (class
org.springframework.hateoas.PagedModel), not marked as ignorable (3
known properties: "links", "page", "content"])
With this code:
ObjectMapper mapper = new ObjectMapper();
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
messageConverter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json"));
messageConverter.setObjectMapper(mapper);
ResponseEntity<PagedModel<Post>> responseEntity =
new RestTemplate(Arrays.asList(messageConverter)).exchange(uri, HttpMethod.GET, HttpEntity.EMPTY, new ParameterizedTypeReference<PagedModel<Post>>() {});
The versions are:
Jackson-databind version: 2.11.0
Spring-hateoas version: 1.0.5.RELEASE
Any help would be appreciated!
Response structure seems like PagedResources<T> type.
Use org.springframework.hateoas.PagedResources in ParameterizedTypeReference
ResponseEntity<PagedResources<Post>> responseEntity =
new RestTemplate(Arrays.asList(messageConverter)).exchange(uri, HttpMethod.GET, HttpEntity.EMPTY, new ParameterizedTypeReference<PagedResources<Post>>() {});

I want to map json object nested inside another object to POJO using jackson library

I have an object nested inside another object in Json file. I want to map this object with fields to a Model class.
{
"code": 200,
"time": "2019-09-05T07:09:44.228+0000",
"data": {
"statuses": [
{
"statusType": "IN_PROGRESS",
"statusTimestamp":"019-09-05T17:04:54+1000"
},
{
"statusType": "SENT",
"statusTimestamp":"2019-09-05T21:04:55+1000"
},
{
"statusType": "OPENED",
"statusTimestamp":"2019-09-05T23:04:55+1000"
},
{
"statusType": "INTERACTION_ID_RECEIVED",
"statusTimestamp":"2019-09-06T00:04:55+1000"
}
]
},
"status": 200,
"message": null,
"errors": null,
}
I want to map the statusType and TimeStamp to a custom model class.
Model Class:
public class Model{
private String statusType;
private DateTime statusTimestamp;
public Model(String statusType, String statusTimestamp) {
this.statusType=statusType;
this.statusTimestamp=new DateTime(statusTimestamp);
}
public String getStatusType() {
return statusType;
}
public void setStatusType(String statusType) {
this.statusType = statusType;
}
public DateTime getStatusTimestamp() {
return statusTimestamp;
}
public void setStatusTimestamp(String statusTimestamp) {
this.statusTimestamp = new DateTime(statusTimestamp);
}
}
I want to map the statuses to this model class and store these objects in a link something like this
List statuses = ParsedJson.read("$..['statuses'][*]", List.class)
If you don't want to model the entire response, you could use Jackson to parse the JSON into tree nodes and then map only the parts you care about:
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(json);
JsonNode statusesNode = rootNode.path("data").path("statuses");
List<Status> statuses = mapper.convertValue(statusesNode,
new TypeReference<List<Status>>(){});
I saw 2 errors in the json string fixing it should help you to create Object using java or any other language easily.
line 12: " was missing
line 26: invalid placement of ,
Json after fixing issues
{
"code": 200,
"time": "2019-09-05T07:09:44.228+0000",
"data": {
"statuses": [
{
"statusType": "IN_PROGRESS",
"statusTimestamp":"019-09-05T17:04:54+1000"
},
{
"statusType": "SENT",
"statusTimestamp":"2019-09-05T21:04:55+1000"
},
{
"statusType": "OPENED",
"statusTimestamp":"2019-09-05T23:04:55+1000"
},
{
"statusType": "INTERACTION_ID_RECEIVED",
"statusTimestamp":"2019-09-06T00:04:55+1000"
}
]
},
"status": 200,
"message": null,
"errors": null
}

Converting Linear json to nested json in mule

I need help in the logic for transforming one json file to another json file. I am trying to achieve this in mule without dataweave in the custom java component.
I want to convert a linear json to nested json, The input data is a linear json containing the details of all files and directory in particular FTP server. The output Json file should be able to nest the files and directory based on the root directory. Here is the example of input and output json.
{
"InputJson": [
{
"type": "dir",
"id": "RootDir",
"name": "abcd",
"Dir": "/abcd"
},
{
"type": "dir",
"name": "Folder1",
"Dir": "/abcd/Folder1",
"id": "XXXXX"
},
{
"type": "file",
"name": "Folder1SubFolder1",
"Dir": "/abcd/Folder1/Folder1SubFolder1",
"id": "XXXXXX"
},
{
"type": "dir",
"name": "Folder2",
"Dir": "/abcd/Folder2"
"id": "XXXXXX"
},
{
"type": "dir",
"name": "Folder2SubFolder1",
"Dir": "/abcd/Folder2/Folder2SubFolder1"
"id": "XXXXXX"
},
{
"type": "file",
"name": "Folder2SubFolder1SubFolder1",
"Dir": "/abcd/Folder2/Folder2SubFolder1/Folder2SubFolder1SubFolder1"
"id": "XXXXXX"
}
]
}
Output
{
"id": "RootDir",
"value": "Files",
"type": "folder"
"OutData": [{
"value": "Folder1",
"OutData": [{
"value": "Folder1SubFolder1"
}
]
}
]
"OutData": [{
"value": "Folder2",
"OutData": [{
"value": "Folder2SubFolder1",
"OutData":[{
"value": "Folder2SubFolder1SubFolder1",
}]
}
]
}
]
the logic
1. CREATE (java) `outputElemtsList` = []
2. FOR EACH (json) `inputElement` IN `InputJson`
3. CREATE (java) `outputElemt`
4. ADD `outputElement` TO `outputElemtsList`
5. IF `outputElement` HAS `parent`
6. ADD `outputElement` TO `parent`.outData
7. CONVERT `outputElemtsList`[0] TO `Json`
assuming, the list in InputJson, is ordered in the same as the sample, (the child never come before their parent)
if not, you'll need to add some checks as:
3. create `outputElement` if not in `outputElemtsList`; else continue
6. create `parent` if not in `outputElemtsList`
in practice
you can use a Json parser, such jakson, to:
// parse InputJson, to Java Objects
Map<String, Object> rootNode = mapper.readValue(jsonString, Map.class);
// ... implement the logic ...
// serialize a java Object into Json
String outputJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(routOutputs);
the code
updated to distinguish between file and folders(dir)
1- OutputElement class
public class OutputElement {
String id, value, type;
public void addOutData(OutputElement outputElement) {}
// constructor, accessors ...
}
1.2- class OutputDir extends OutputElement
public class OutputElement {
List<OutputElement> outData = new ArrayList<>();
#Override
public void addOutData(OutputElement outputElement) {
this.outData.add(outputElement);
}
}
2- Main class : LinearToNestedJson
method to check if outputElements List contains an outputElement
public static boolean contains(List<OutputElement> outputElements, String value) {
for (OutputElement outputElement : outputElements) {
if (outputElement.getValue().equals(value))
return true;
}
return false;
}
main method
public static void main(String args[]) {
JacksonTester tester = new JacksonTester();
try {
ObjectMapper mapper = new ObjectMapper();
String jsonString = IN_JSON;
#SuppressWarnings("unchecked")
Map<String, Object> rootNode = mapper.readValue(jsonString, Map.class);
#SuppressWarnings("unchecked")
List<Map<String, Object>> inputElemnts =
(ArrayList<Map<String, Object>>) rootNode.getOrDefault("InputJson", null);
List<OutputElement> outputElements = new ArrayList<>();
for (Map inputElemnt : inputElemnts) {
String fullpath = (String) inputElemnt.get("Dir");
String[] tree = fullpath.substring(1).split("/");
final int deepth = tree.length;
String dirName = tree[deepth - 1];
final String value = (String) inputElemnt.get("name");
final String id = (String) inputElemnt.get("id");
String type = (String) inputElemnt.get("type");
OutputElement outputElement;
if (type != null && type.equals("dir")) {
outputElement = new OutputDir();
} else {
if(type==null) type = "file";
outputElement = new OutputElement();
}
outputElement.setValue(value);
outputElement.setId(id);
outputElement.setType(type);
if (!contains(outputElements, value)) {
outputElements.add(outputElement);
}
if (deepth > 1) {
String parentName = tree[deepth - 2];
for (OutputElement element : outputElements) {
if (element.getValue().equals(parentName)) {
element.addOutData(outputElement);
}
}
}
// for (int i = 0; i < deepth -1; i++) {
// System.out.println(tree[i]);
// }
}
OutputElement routOutputs = outputElements.get(0);
String outputJson = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(routOutputs);
System.out.println(outputJson);
} catch (JsonParseException | JsonMappingException e) {
} catch (IOException e) {
}
}
it's output, for the given input (after validation)
{
"id" : "RootDir",
"value" : "abcd",
"type" : "dir",
"outData" : [ {
"id" : "XXXXX",
"value" : "Folder1",
"type" : "dir",
"outData" : [ {
"id" : "XXXXXX",
"value" : "Folder1SubFolder1",
"type" : "file"
} ]
}, {
"id" : "XXXXXX",
"value" : "Folder2",
"type" : "dir",
"outData" : [ {
"id" : "XXXXXX",
"value" : "Folder2SubFolder1",
"type" : "dir",
"outData" : [ {
"id" : "XXXXXX",
"value" : "Folder2SubFolder1SubFolder1",
"type" : "file"
} ]
} ]
} ]
}
Use groupBy - that's exactly what you need.
Here is code:
%dw 1.0
%output application/json
---
items : payload.InputJson groupBy $.id pluck {
id: $$,
values: $
}
Here is result:

How to consume Spring HATEOAS REST resources containing links to another resources?

I have /studentCourses endpoint on the server (built with Spring Data REST) which returns the following content:
{
"_embedded" : {
"studentCourses" : [
{
"uid" : "5f23abe9-b24e-4e76-86b0-d539950a0a41",
"registrationDate" : "7/23/2016",
"_links" : {
"self" : {
"href" : "http://localhost:8080/studentCourses/5f23abe9-b24e-4e76-86b0-d539950a0a41"
},
"studentCourse" : {
"href" : "http://localhost:8080/studentCourses/5f23abe9-b24e-4e76-86b0-d539950a0a41"
},
"course" : {
"href" : "http://localhost:8080/studentCourses/5f23abe9-b24e-4e76-86b0-d539950a0a41/course"
},
"student" : {
"href" : "http://localhost:8080/studentCourses/5f23abe9-b24e-4e76-86b0-d539950a0a41/student"
}
}
},
{
...
},
...
]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/studentCourses"
},
"profile" : {
"href" : "http://localhost:8080/profile/studentCourses"
}
},
"page" : {
...
}
}
And the following client code:
class StudentCourseDTO {
String uuid;
String registrationDate;
StudentDTO student; // contains uuid, firstName, lastName, etc.
CourseDTO course; // contains uuid, name, etc.
// getters, setters
}
RestTemplate restTemplate() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jackson2HalModule());
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
MappingJackson2HttpMessageConverter messageConverter =
new MappingJackson2HttpMessageConverter();
messageConverter.setObjectMapper(objectMapper);
messageConverter.setSupportedMediaTypes(Arrays.asList(MediaTypes.HAL_JSON));
return new RestTemplate(Arrays.asList(messageConverter));
}
...
Collection<StudentCourseDTO> studentCourses = restTemplate().exchange(
"http://localhost:8080/studentCourses",
HttpMethod.GET, null,
new ParameterizedTypeReference<PagedResources<StudentCourseDTO>>() {})
.getBody().getContent();
The problem is that StudentCourseDTO.student and StudentCourseDTO.course are always null, but StudentCourseDTO.uuid and StudentCourseDTO.registrationDate are retrieved correctly from the server.
Anyone has an idea what I have missed?
I think there must be someway to tell RestTemplate to automatically follow the links in the returned content like student and course in the example above, but I haven't found a way to do this.
Just because there are links that does not mean they are automatically followed.
I would change the StudentCourseDTO to:
class StudentCourseDTO {
String uuid;
String registrationDate;
}
And then you would deserialize the response to a
PagedResources<Resource<StudentCourseDTO>> studentCourses = restTemplate().exchange(
"http://localhost:8080/studentCourses",
HttpMethod.GET, null,
new ParameterizedTypeReference<PagedResources<Resource<StudentCourseDTO>>>() {})
.getBody().getContent();
For each Resource<StudentCourseDTO> you can then follow the links for studentand course, e.g. by using the RestTemplate to retrieve the resources.
Of course this gives you two additional calls per response item - but the only way to avoid this is to change the service to embed this information in the list resource.

Categories

Resources