How to deserialize unwrapped json with Jackson? - java

I am using jackson for during JSON to java.It works fine normally.
However, I have a questions.
Most of my json will contain common fields like status and description along with few changing fields.
i was thinking of putting the common fields into a separate class and including its object into all classes but it does not work that way as Jackson was not able to understnad that these two fields need to be set in other object.
Class login {
private String name;
private Response response;
/* getters and setters*/
}
Class Response {
private String status;
private string description;
/* getters and setters*/
}
This will not work for json
{
"name": "",
"status": "",
"description": ""
}
Kindly suggest the best way to achieve it.I can think of only inheritance to acchieve it.

Change your json like the following:
{
"name": "",
"response": {
"status": "",
"description": ""
}
}
or if you cannot change JSON then change your class:
abstract class Response
{
private String status;
private String description;
}
class Login extends Response
{
private String name;
}
The code you have now will only work if you change the json to the one I wrote above.

Related

How to deserialize json to nested custom map via gson?

I have the following json
{
"id": "1111",
"match": {
"username1": {
"id": "1234",
"name": "alex"
},
"username2": {
"id": "5678",
"name": "munch"
}
}
}
To deserialize it, I have the following data model class.
class json{
String id;
Match match;
}
class Match {
private Map<String,Profile> profiles
}
class Profile{
private String id;
private String name;
}
I am not getting any deserialization error when I am using gson but the
profiles variable is coming as null.
This is how I am deserializing.
var json = gson.fromJson(data,json.class)
inside the match object there can be a dynamic number of usernames not just two . Why am I getting profile object as null and how can I correctly populate it?
Making changes to json is the last resort here. I can make any other required changes.
The issue is your model. You don't need Match because profiles does not really exist in your JSON. You just json (this one with small changes) and Profile:
class json{
String id;
Map<String,Profile> match;
}
This will work.

POJOs declaration for different api with common fields

I need to create response POJOs class for a couple of APIs i have to call in my microservice . The response has a base structure given below.
{
"requestId": "abcd-1234-3456",
"sourceSystem": "HOME",
"response": {
"statusCode": "200",
"statusMessage": "Successfully Received",
"statusType": "SUCCESS",
"details": [
{
"message" : "hi"
}
]
}
}
Here the object inside the "details" property array can vary and can have different class definitions. Can someone help whether how should i declare my POJOs so that there is a common class for the common fields and a different set of classes for object inside details property . I tried few ways using java generics and #JsonSubType but that is giving some error Unrecognized field "details" during deserialisation.
Why don't you try and define it as object instead :-
class Response{
private String requestId;
private String statusMessage;
private String statusType;
private List<Object> details;
}

How to map multiple JSON responses to a single Java POJO?

Need to map multiple types of JSON responses to a single POJO so that I can compare the different objects to provide insight about the differences.
I had tried mapping the first response to the POJO and parsed the second response to populate the defined POJO:
class XXX {
#JsonProperty("accountHolder")
private String accountHolder;
#JsonProperty("routingNumber")
private String routingNumber;
#JsonProperty("balance")
private List<Balance> balance;
#JsonProperty("accountName")
private String accountName;
#JsonProperty("bankTransferCodeType")
private String bankTransferCodeType;
#JsonProperty("individualInformation")
private IndividualInformation individualInformation;
#JsonProperty("acctType")
private String acctType;
#JsonProperty("transactionList")
private TransactionList transactionList;
#JsonProperty("accountNumber")
private String accountNumber;
#JsonProperty("uniqueId")
private String uniqueId;
#JsonProperty("bankNetID")
private String bankNetID;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
}
First response:
[
{
"ACCOUNT_NAME": "",
"ACCOUNT_NUMBER": "",
"AVAILABLE_BALANCE": null,
"CURRENT_BALANCE": "",
"FULL_ACCOUNT_NUMBER": null,
}
]
Second response:
"bankAccount": [
{
"accountName": "",
"accountNumber": "",
"routingNumber": "",
"fullAccountNumber": "",
"bankTransferCodeType": "",
"acctType": "",
"transactionList": {
"transaction": [
{
"amount": {
"curCode": "",
"content": ""
}
],
"oldestTxnDate": ""
},
"uniqueId":
}
}
Expecting a generic way to map the different structured JSON entities to single POJO.
How to map multiple JSON responses to a single Java POJO?
As both responses seem to be completely different from each other, with nothing in common, I would refrain from attempting to use a single class for reading both responses.
Expecting a generic way to map the different structured JSONs to single POJO.
You could parse both responses as a Map<String, Object> and then map the values to a common class.
You could create separated classes for mapping each response. It will allow you to decouple them and evolve them as you need. You also can use use mapping frameworks such as MapStruct for reducing the boilerplate code when mapping from one object to another.
It doesn’t seems to have any generic way. But you can do this:
Create multiple domain classes for each response type
Create a single standard domain class
Create mapper for each response class to map that to standard domain
class. You can use MapStruct reference here
I would suggest using Jackson Json Views. Here is an example for the same :
Example
public class Views {
public class Global {
}
public class Internal extends Global {
}
}
class XXX {
#JsonView(Views.Global.class)
#JsonProperty("accountHolder")
private String accountHolder;
#JsonView(Views.Internal.class)
#JsonProperty("routingNumber")
private String routingNumber;
}
Hope it helps.
What I did is I created a MyResponse model containing basically all response fields from the JSON response you expect to get.
MyResponse has c-tor or receiving these fields or setters allowing setting them.
Then I created some kind of service class MyService that can issue multiple requests and gets responses back.
Then you just do something like this in some kind of manager class or whatever you call it:
MyService mySer = new MyService();
MyResponse myRes = new MyResponse(
mySer.getDetails(),
mySer.getPicture(),
mySer.getSomethingElse()
);
These calls (getDetails, getPicture...) send requests to end point and return responses which are then just mapped into the the fields of MyResponse class constructor. This happens by the framework so MyResponse has annotations #XmlRootElement and #XmlAccessorType of type FIELD to ensure that happens.
If for whatever reason, you dont want to create response containing result of getPicture for example, you just assign null to that imput parameter.
I suggest to use #JsonProperty("") and #JsonAlias("").
class XXX {
#JsonAlias("accountName")
#JsonProperty("ACCOUNT_NAME")
private String name;
#JsonAlias("routingNumber")
#JsonProperty("ROUTING_NUMBER")
private String routing;}
I hope it helps.

How to post an json object correctly in Spring Boot Rest

I am new to Spring Boot Rest and trying to use post ab object as a rest request. But it is not working and I am getting null return:
This is my Object that I want to post:
public class Flight {
private String code;
private Route route;
private LocalDateTime departure;
private LocalDateTime arrival;
//Constructor
//Getters and Setters
}
This is Route class:
public class Route {
private final Airport from;
private final Airport to;
//Constructor
//Getters
}
This is my Airport class:
public class Airport {
private final String code;
private final String name;
//Constructor
//Getters
}
This is my controller:
#RequestMapping(value = "/testflight", method = RequestMethod.POST)
public Flight createFlight(#RequestBody Flight inputPayload) {
Flight response = inputPayload;
response.setCode(inputPayload.getCode());
response.setRoute(inputPayload.getRoute());
response.setDeparture(inputPayload.getDeparture());
response.setArrival(inputPayload.getArrival());
System.out.println("Flight details are:" + "\n" + inputPayload.getCode() + "\n" + inputPayload.getRoute() + "\n" + inputPayload.getDeparture() + "\n" + inputPayload.getArrival());
return response;
}
And this is my JSON:
{ "flight": {
"code" : "THY1770",
"route": {
"airport": [
{ "code": 1, "name": "IST" },
{ "code": 2, "name": "STG" }
],
"departure" : "2014-01-01",
"arrival" : "2014-01-01"
}
}
}
When I post this JSON then I just get this:
Flight details are:
null
null
null
null
As the controller is posted only partially (that is: only the method, not the full class), I will assume that it's as simple as it gets and that it has been annotated as a #RestController.
It would appear that you have several discrepancies between the objects and the JSON payload you're passing.
An easy way to generate a JSON that your controller will accept is to expose a method in the controller that takes no parameter as input and generates a Flight as output. That output you can then use as a template to build your subsequent JSON requests.
Try posting the following JSON:
{
"code" : "THY1770",
"route": {
"from": {
"code": "ABC",
"name": "My Airport 1"
},
"to": {
"code": "DEF",
"name": "My Airport 2"
}
}
"departure" : null,
"arrival" : null
}
Note that in my answer I've set the dates to null. For those you'll have to make sure that the format you provided is accepted. Use the trick I explained at the beginning to try and figure out one of the possible date formats.
Also, remember that dates are a very difficult problem to tackle. In your specific case, you'll probably want to make sure that dates are sent along with their time and timezone.
Also, help yourself with Project Lombok for the getters and setters when you get the time. It will save you lots of boilerplate code, which in the case of getters and setters is all too often the source of unexpected problems.
The code inside the controller itself is probably wrong:
It doesn't make sense to copy the reference of inputPayload and then call the setter on the same object:
I think, given the toString implemented in Flight class you can:
#PostMapping("/testflight") // this is just a better syntax than #RequestMapping
public Flight createFlight(#RequestBody Flight inputPayload) {
System.out.println(inputPayload); // just to test yourself
return inputPayload;
}
Now having said that, all the mappings are done correctly and the annotations are also put as required so if it doesn't work, the error might be somewhere else (not posted in the question).

How to map json response object to a preferred format using Jackson / other library?

I am getting the below JSON response format from a third party web service:
{
"meta": {
"code": 200,
"requestId": "1"
},
"response": {
"locations": [
{
"id": "1",
"name": "XXX",
"contact": {
phone: '123',
email: 'abc'
},
"location": {
"address": [
"Finland"
]
}
},
{
// another location
}
]
}
}
And here is what I should return as a response from my own web service:
[
{
"id": "1",
"name": "XXX",
"phone": '123',
"address": "Finland"
},
{
// another location
}
]
What should I do? I've read some good stuff about Jackson but there are only a few simple examples where you map some simple JSON obj as is to POJO. In my case, I need to remove a few nodes, and also traverse deeper down the hierarchy to get the nested value. This is my baby step so far in my spring boot app:
#GET
#Path("{query}")
#Produces("application/json")
public String getVenues(#PathParam("query") String query){
return client.target(url).queryParam("query",query).request(...).get(String.class)
}
Any helps, pointers, recommendations are welcomed!
You are using JAX-RS annotations instead of the Spring web service annotations. You can make this work, but I would recommend going with the default Spring annotations because those are all autoconfigured for you if you're using the spring boot starter dependencies.
First thing - you need to create classes that are set up like the request and response. Something like this:
public class ThirdPartyResponse {
MetaData meta;
Response response;
}
public class Response {
List<Location> locations;
}
public class MetaData {
String code;
String requestId;
}
public class Location {
String id;
String name;
Contact contact;
LocationDetails location;
}
public class Contact {
String phone;
String email;
}
public class LocationDetails {
List<String> address;
}
You can use Jackson annotations to customize the deserialization, but by default it maps pretty logically to fields by name and the types you might expect (a JSON list named "locations" gets mapped to a List in your object named "locations", etc).
Next you'll want to use a #RestController annotated class for your service, which makes the service call to the third party service using RestTemplate, something like:
#RestController
public class Controller {
#Value("${url}")
String url;
#RequestMapping("/path"
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public List<Location> locations(#RequestParam String query) {
// RestTemplate will make the service call and handle the
// mapping from JSON to Java object
RestTemplate restTemplate = new RestTemplate();
ThirdPartyResponse response = restTemplate.getForObject(url, ThirdPartyResponse.class);
List<Location> myResponse = new List<>();
// ... do whatever processing you need here ...
// this response will be serialized as JSON "automatically"
return myResponse;
}
}
As you can see, Spring Boot abstracts away a lot of the JSON processing and makes it pretty painless.
Take a look at Spring's guides which are pretty helpful:
Consuming a service with RestTemplate
http://spring.io/guides/gs/consuming-rest/
Creating a web service using #RestController
https://spring.io/guides/gs/rest-service/
This can be done using google api JacksonFactory.
Below is my suggested solution for this.
First you should create a pojo class corrosponding to the json data you are recieving and the json data to which you are trying to convert.
Use google api client to map the keys to the pojo.
Below is the pojo classes corrosponding to the json data you are recieving.
import com.google.api.client.util.Key;
Class Response{
#Key("locations")
List<FromLocations> fromLocations;
}
import com.google.api.client.util.Key;
Class FromLocations
{
#Key("id")
String id;
#Key("name")
String name;
#Key("contact")
Contact contact;
#Key("location")
Location location;
}
Here Contact and Loaction will be a another classes using the same strategy;
Below is the pojo corrosponding to the json to which you want to convert.
Class ToLocations{
String id;
String name;
String phone;
String address;
}
Now you can parse the requset containing the json objec to the fromLocations class as below.
String responseMeta = response.parseAsString();
JSONObject queryJsonObject = new JSONObject(responseMeta);
if(queryJsonObject.has("locations")){
Response response = JacksonFactory.getDefaultInstance().fromString(responseMeta,Response.class);
List<FromLocations> fromLocationsList = response.getFromLocations();
}
Next step is to iterate the list fromLocationsList and get the desired values from each FromLocations object and add it to the ToLocations object.
Next the ToLocations object can be add it to a list and convert it to json.

Categories

Resources