Json deserialization with key value mapped object - java

I'm trying to deserialize a json string to Java object. Here is my json string.
{
"header": {
"transactionId": "12345",
"application": "testApp"
},
"items": {
"item": [
{
"attributes": {
"attribute": [
{
"key": "accountType",
"value": "TYPE1"
},
{
"key": "accountId",
"value": "123"
}
]
}
},
{
"attributes": {
"attribute": [
{
"key": "userType",
"value": "TYPE2"
},
{
"key": "userId",
"value": "321"
}
]
}
}
]
}
}
And I want to deserialize this json to Java classes that shown as below.
public class Response {
private Header header;
private List<Object> items;
//getters and setters
}
public class Header {
private String transactionId;
private String application;
//getters and setters
}
public class Account {
private String accountType;
private String accountId;
//getters and setters
}
public class User {
private String userType;
private String userId;
//getters and setters
}
How can I deserialize by using jackson or objectmapper etc.? The main problem is the field names are in the attribute object and the value of 'key' field. Is it possible to find the right field on Java object by using value of the 'key' field and to set the right value with the value of the 'value' field?

One possible solution is to transform the JSON structure before converting to POJO.
https://github.com/octomix/josson
Josson josson = Josson.fromJsonString(yourJsonString);
JsonNode node = josson.getNode(
"map(header," +
" items: items.item#" +
" .attributes.attribute" +
" .map(key::value)" +
" .mergeObjects()" +
" )");
System.out.println(node.toPrettyString());
Output
{
"header" : {
"transactionId" : "12345",
"application" : "testApp"
},
"items" : [ {
"accountType" : "TYPE1",
"accountId" : "123"
}, {
"userType" : "TYPE2",
"userId" : "321"
} ]
}

Related

Issue with a Json schema validation

I'm running into an issue with a Json schema validation.
I have a Java class like this
package com.ebc.jackson.exampe.data;
public class FormElement {
private String fieldName;
private String fieldType;
private Object value;
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public String getFieldType() {
return fieldType;
}
public void setFieldType(String fieldType) {
this.fieldType = fieldType;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
I'm using below code to generate the schema:
JsonSchemaGenerator generator =
new JsonSchemaGenerator(objectMapper);
JsonNode schema = generator.generateJsonSchema(FormElement.class);
String strSchema = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema);
this code generates below schema
{
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "Form Element",
"type" : "object",
"additionalProperties" : false,
"properties" : {
"fieldName" : {
"type" : "string"
},
"fieldType" : {
"type" : "string"
},
"value" : {
"$ref" : "#/definitions/Object"
}
},
"definitions" : {
"Object" : {
"type" : "object",
"additionalProperties" : false,
"properties" : { }
}
}
}
In the request, I could receive a Json Object like
{
"fieldName": "user-name",
"fieldType": "textInput",
"value": "Alex"
}
When I try to validate this object against the Json schema, "value" attribute is not valid, it is expecting a "key: value" pair but, a string is found.
In the Java class the value attribute is Object because it could be a String, Integer, Boolean, etc.
My question is, how can I generate a schema to support different data types for "value" attribute?
You can use the anyOf property of schema :
Try the below one :
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Form Element",
"type": "object",
"additionalProperties": false,
"properties": {
"fieldName": {
"type": "string"
},
"fieldType": {
"type": "string"
},
"value": {
"$ref": "#/definitions/Object"
}
},
"definitions": {
"Object": {
"format": "",
"anyOf": [
{
"type": "object"
},
{
"type": "string"
},
{
"type": "number"
},
{
"type": "integer"
},
{
"type": "boolean",
"x-enumFlags": true
},
{
"type": "null"
}
],
"additionalProperties": false,
"properties": {}
}
}
}
Or you could try the pipe separator in type.In the schema you provided just change the value of type to "type": "string|object|integer|number". This notation didn't work for me in swagger but you can check if it works for you.

How to define RequestBody in controller as list, I am getting 500 error

I want to pass search input as list, Refer the below code and payload which i tried, I am getting parser errror.
// code in searchinput
public class SearchInput {
private List<SearchCriteria> criterias;
}
// code in search criteria
public class SearchCriteria {
private String key;
private String operation;
private String value;
}
//code for controller
#PostMapping("/searchhh")
public List<Profile> findProfiles(#RequestBody SearchInput input) {
List<SearchCriteria> criterias = input.getCriterias();
System.out.println("criterias=" + criterias);
return null;
}
// payload which I tired
URL:
http://localhost:5555/matrimony/api/v1/profiles/searchhh
Request body:
[
{
"key": "g",
"operation": "eq",
"value": "m"
},
{
"key": "name",
"operation": "like",
"value": "Rani"
},
{
"key": "sh",
"operation": "eq",
"value": "Never"
}
]
Response:
{
"message": "JSON parse error: Cannot deserialize instance of `com.model.SearchInput` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `com.model.SearchInput` out of START_ARRAY token\n at [Source: (PushbackInputStream); line: 1, column: 1]",
"status": 500,
"timestamp": "2021-01-21T11:31:48.228796"
}
Have you tried this payload:
{
"criterias" : [
{
"key": "g",
"operation": "eq",
"value": "m"
},
{
"key": "name",
"operation": "like",
"value": "Rani"
},
{
"key": "sh",
"operation": "eq",
"value": "Never"
}
]
}
The above payload which you are passing as request body represents array of SearchCriteria objects, so you can parse that json directly into List<SearchCriteria> and no need of SearchInput class
#PostMapping("/searchhh")
public List<Profile> findProfiles(#RequestBody List<SearchCriteria> input) {
System.out.println("criterias=" + input);
return null;
}

How map List to an Object with list in mapstructs

How can I use MapStruct to create a mapper that maps a list (my source) to a object with a list (destination)?
My source classes looks like this:
class SourceB {
private String name;
private String lastname;
}
class SourceA {
private Integer id;
private List<SourceB> bs;
}
so I need to transform it to this:
class DestinationA {
private Integer id;
private DestinationAB bs;
}
class DestinationAB {
private List<DestinationB> b;
}
class DestinationB {
private String name;
private String lastname;
}
Expected sample json:
source:
{
"id": 1,
"bs": [
{
"name": "name1",
"lastname": "last1"
},
{
"name": "name2",
"lastname": "last2"
}
]
}
destination:
{
"id": 1,
"bs": {
"b": [
{
"name": "name1",
"lastname": "last1"
},
{
"name": "name2",
"lastname": "last2"
}
]
}
}
It's quite simple. Just put #Mapping annotation with specified source and destination on top of the mapping method.
#Mapper
public interface SourceMapper {
#Mapping(source = "bs", target = "bs.b")
DestinationA sourceAToDestinationA(SourceA sourceA);
}

Mapping an array of JSon string into Pojo

Everytime I map an array of JSON object into POJOs, I always get the last object.
The JSON is an array of objects, and I have a POJO associate with each object of JSON. But when I mapped into an array of POJO, I always get 1 object.
Here is the JSON :
[ {
"event" : {
"Id" : "123456789",
"Name" : "An event1 name"
},
"branch" : {
"Id" : "112233445566",
"Name" : "A branch1 name",
},
"user" : {
"Id" : "9988776655",
"FirstName" : "John",
"LastName" : "Doe",
},
"event" : {
"Id" : "abcdef",
"Name" : "An event2 name"
},
"branch" : {
"Id" : "885522",
"Name" : "A branch2 name",
},
"user" : {
"Id" : "996633",
"FirstName" : "Jane",
"LastName" : "Doe",
}
} ]
The POJOs:
public class RdV {
private Event event;
private Branch branch;
private User user;
public Event getEvent() {
return event;
}
public void setEvent(Event event) {
this.event = event;
}
public Branch getBranch() {
return branch;
}
public void setBranch(Branch branch) {
this.branch= branch;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
#Override
public String toString() {
return "RdV [\n"
+ event + "\n"
+ branch + "\n"
+ user + "\n"
+ "]";
}
}
public class Event {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name= name;
}
}
The other POJOS, Branch and User are similar to Event.
And when I use the following :
List<RdV> rdv = Arrays.asList(objectMapper.readValue(jsonString, RdV[].class));
all I got is just the last object ( the size of list is 1, instead of 2 ):
==> RdV [
Event {
id="abcdef",
name="An event2 name"
}
Branch {
id="885522",
name="A branch2 name"
}
User {
id="996633",
lastName="Doe",
firstName="Jane"
}
]
Any idea what went wrong the code ?
Thanks.
your JSON doesn't have two separate objects - just one with double properties of Branch, Event and User, you should change it to
[
{
"event": {
"Id": "123456789",
"Name": "An event1 name"
},
"branch": {
"Id": "112233445566",
"Name": "A branch1 name"
},
"user": {
"Id": "9988776655",
"FirstName": "John",
"LastName": "Doe"
}
},
{
"event": {
"Id": "abcdef",
"Name": "An event2 name"
},
"branch": {
"Id": "885522",
"Name": "A branch2 name"
},
"user": {
"Id": "996633",
"FirstName": "Jane",
"LastName": "Doe"
}
}
]

katharsis collection of non primitives serialization

Trying to serialize a collection of non-primitive types using katharsis, but getting an empty collection all the time.
Response example:
{
"data": {
"type": "products",
"id": "1",
"attributes": {
"simpleAttributes": [
{}
],
"variationGroup": "variationGroup"
},
"relationships": {},
"links": {
"self": "http://localhost:8080/api/products/1"
}
},
"included": []
}
Expected response:
{
"data": {
"type": "products",
"id": "1",
"attributes": {
"simpleAttributes": [
{
tittle: "some title",
value: "some value"
}
],
"variationGroup": "variationGroup"
},
"relationships": {},
"links": {
"self": "http://localhost:8080/api/products/1"
}
},
"included": []
}
Domain objects (getters, setters, constructor and other stuff omitted by using lombok #Data annotation):
#JsonApiResource(type = "products")
#Data
public class Product {
#JsonApiId
private Integer id;
private List<SimpleAttribute> simpleAttributes = new ArrayList<>();
private String variationGroup;
}
#Data
public class SimpleAttribute implements Serializable{
private String title;
private String value;
}
I do not want to use relationships in this case or to include attributes to "included" field. Is it possible in katharsis?
Not sure what actually was wrong, but the problem disappeared after I changed katharsis-spring version from 2.3.0 to 2.3.1.

Categories

Resources