How to create dynamically acceptable JSON in RESTful web services? - json

Below is my JSON file :
Input JSON:
{
"name": "Tamiliniyan",
"address": {
"street": "My street",
"city": "Texas"
}
}
Controller class:
#RestController
#RequestMapping(value = "/customer")
public class CustomerController {
#Autowired
private WelcomeService customerService;
#RequestMapping(method = RequestMethod.POST)
public void addCustomer(#RequestBody Customer customer) {
return customerService.addTranslation(customer);
}
}
POJO:
public class Customer
{
private Address address;
private String name;
public Address getAddress ()
{
return address;
}
public void setAddress (Address address)
{
this.address = address;
}
public String getName ()
{
return name;
}
public void setName (String name)
{
this.name = name;
}
}
public class Address
{
private String street;
private String city;
public String getStreet ()
{
return street;
}
public void setStreet (String street)
{
this.street = street;
}
public String getCity ()
{
return city;
}
public void setCity (String city)
{
this.city = city;
}
}
Now I have to dynamically add city or zipcode. How to do it? Basically Client system can pass any new additional JSON field with current structure (like city or zipcode). CustomerController class should able to parse it. What is better approach to handle dynamic JSON element in restful services?

In my opinion, the easiest and most performant way of handling JSON within Java using Spring when you don't know the final structure of your JSON is to use Map(s).
You could add something like this to your POJO:
public class Customer {
private Address address;
private String name;
private Map<String, ?> additionalFields;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, ?> getAdditionalFields() {
return additionalFields;
}
public void setAdditionalFields(Map<String, ?> additionalFields) {
this.additionalFields = additionalFields;
}
}
If you then post something like this:
{
"name": "Tamiliniyan",
"address": {
"street": "My street",
"city": "Texas"
},
"additionalFields": {
"nested1":{
"zip-code": "00055"
}
}
}
This is what you get when Spring processes it:
In order to retrieve data you could then use methods like:
customer.getAdditionalFields().containsKey("nested1")
customer.getAdditionalFields().get("nested1")
Another approach would be to add whatever fields you need to your Class and then ignore empty fields in you Jackson configuration

Related

Spring Feign Client returns null nested object

I have 2 services running(Frontend, Backend). Frontend service has Feign Client to connect to Backend API service. When a request hits Frontend, through Feign client it hits Backend API.
I have an API endpoint GET /api/v1/person which returns response like below format
{
"firstName": "stack"
"lastName": "overflow",
"address" : {
"address1" : "xyz",
"address2" : "abc street",
"postalcode": "123456"
}
}
The data for the address object is populated from external API as a JSON string. But the keys are in a different format, so I am using #JsonProperty annotation in setters and getters to convert them properly.
class Person {
private String firstName;
private String lastName;
private Address address;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setAddress(Address address) {
this.address= address;
}
public void getAddress() {
return this.address;
}
}
public class Address {
private String address1;
private String address2;
private String postalCode;
#JsonProperty("address1")
public String getAddress1() {
return address1;
}
#JsonProperty("ADD_ONE")
public void setAddress1(String address1) {
this.address1 = address1;
}
#JsonProperty("address2")
public String getAddress2() {
return address2;
}
#JsonProperty("ADD_TWO")
public void setAddress2(String address2) {
this.address2 = address2;
}
#JsonProperty("postalCode")
public String getPostalCode() {
return postalCode;
}
#JsonProperty("PST_CDE")
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
}
From the Backend API, the response looks good and as expected. But when it reached Frontend service, the address object returned as null/empty as below
{
"firstName": "stack"
"lastName": "overflow",
"address" : {}
}
Instead of using #JsonProperty in the Address class, if I rename the JSON keys and convert the JSON string to a java object, I am getting the expected response.
I am not sure why it returns empty or null when I use the #JsonProperty in the Address class and pass the response from the Backend to the Frontend service.
Note: Response object is common for both services.
Can someone please let me know, what I am missing here?
Thanks.
You should also add address attribute in your Person class, along with its getters and setters. I believe that you must be having an address class with the following attributes :
address1
address2
postalcode
Look at the code sample below.
class Person {
private String firstName;
private String lastName;
private Address address;
#JsonProperty("firstName")
public String getFirstName() {
return firstName;
}
#JsonProperty("FST_NME")
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#JsonProperty("lastName")
public String getLastName() {
return lastName;
}
#JsonProperty("LST_NME")
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setAddress(Address address) {
this.address= address;
}
public void getAddress() {
return this.address;
}
}
The issue is resolved when I added a new Address class for the Frontend service.
Frontend Service - with no annotations set.
public class Address {
private String address1;
private String address2;
private String postalCode;
public String getAddress1() {
return address1;
}
public void setAddress1(String address1) {
this.address1 = address1;
}
public String getAddress2() {
return address2;
}
public void setAddress2(String address2) {
this.address2 = address2;
}
public String getPostalCode() {
return postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
}
Backend Service - with #JsonProperty for setters and getters to convert the JSON keys.
public class Address {
private String address1;
private String address2;
private String postalCode;
#JsonProperty("address1")
public String getAddress1() {
return address1;
}
#JsonProperty("ADD_ONE")
public void setAddress1(String address1) {
this.address1 = address1;
}
#JsonProperty("address2")
public String getAddress2() {
return address2;
}
#JsonProperty("ADD_TWO")
public void setAddress2(String address2) {
this.address2 = address2;
}
#JsonProperty("postalCode")
public String getPostalCode() {
return postalCode;
}
#JsonProperty("PST_CDE")
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
}
Since the Address class was Common for both the services, the issue occurred, where the Frontend service was not able to convert the object since the Address class attribute names are different(used #JsonProperty for setter method).
Please comment if there is anything that I missed.
Thanks all for your proper responses.

JAX-RS Json response comes in one line

This is probably some basic question. I am using JAX-RS (jersey implementation) and my code is as follows.
#Path("/data")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Car handlerFn(#Context HttpServletResponse res)
{
res.setStatus(HttpServletResponse.SC_OK);
Car carObject = new Car(42,"Maruthi", "Alto");
return carObject;
}
Car Entity is as follows
public class Car {
int id;
String name;
String model;
public Car() {
}
public Car(int id, String name, String model)
{
this.id=id;
this.name = name;
this.model = model;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getModel() {
return model;
}
}
The output I am getting is in one line as follows
{"id":42,"model":"Alto","name":"Maruthi"}
In place of this I want the each member in different lines as follows
{
"id": 42,
"model": "Alto",
"name": "Maruthi"
}
How can I do that?

type parameter in the response json: REST

I sent a request JSON through Postmaster and got a response in which includes
a field "type": "subPOJO", which isn't part of either my sub class or super class. How is it been placed in the response, if it is implicitly done then how to exclude it in the response. Thank you!
Response JSON:
{
"type": "subPOJO",
"superid": "XYZ",
"name": "Rest Response",
"number": 1212
}
The Response POJOs:
Super class:
package org.javaprojects.webapp.services;
public class SuperPOJO {
private String superid;
public String getSuperid() {
return superid;
}
public void setSuperid(String superid) {
this.superid = superid;
}
}
Sub Class:
package org.javaprojects.webapp.services;
public class SubPOJO extends SuperPOJO {
private String name;
private int number;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
Check this out This may Help you

issue in JSON parsing by GSON

I have Issue in JSON Parsing by GSON
my JSONERESPONSE is
{"services":[{"service":{"name":"asd","id":"1"}},
{"service":{"name":"asdf","id":"2"}},
{"service":{"name":"asdfg","id":"3"}}]}
How to parse this response?
means I have issue in creating class of above response
I have created service class but i am confusing in how to create services class.
public class services {
#SerializedName("service")
ArrayList<service> list;
public services(){
System.out.println("services constructor stuff");
list= new ArrayList<service>();
}
/**
* #return the list
*/
public ArrayList<service> getList() {
return list;
}
/**
* #param list the list to set
*/
public void setList(ArrayList<service> list) {
this.list = list;
}
}
but getting 0 in getList();
Note: I can not change the response, so don't suggest it
Thank you
Ok, we need to create a middle layer class to make it right.
Services.java
public class Services {
private ArrayList<ServiceWrapper> services = new ArrayList<ServiceWrapper>();
public ArrayList<ServiceWrapper> getServices() {
return services;
}
public void setServices(ArrayList<ServiceWrapper> services) {
this.services = services;
}
}
ServiceWrapper.java
public class ServiceWrapper {
private Service service;
public Service getService() {
return service;
}
public void setService(Service service) {
this.service = service;
}
}
Service.java
public class Service {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The following is testing code
Gson gson = new Gson();
String s = "{\"services\":[{\"service\":{\"name\":\"asd\",\"id\":\"1\"}},{\"service\":{\"name\":\"asdf\",\"id\":\"2\"}},{\"service\":{\"name\":\"asdfg\",\"id\":\"3\"}}]}";
Services services = gson.fromJson(s, Services.class);
for(ServiceWrapper serviceWrapper : services.getServices()){
System.out.println(serviceWrapper.getService().getId());
System.out.println(serviceWrapper.getService().getName());
}
Services.java
public class Services {
private List<Service> services;
public List<Service> getServiceList() {
return services;
}
public void setServiceList(List<Service> services) {
this.services = services;
}
}
Service.java
public class Service {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
your json parsing logic goes here:
Gson gson = new Gson();
String s = "{\"services\":[{\"service\":{\"name\":\"asd\",\"id\":\"1\"}},{\"service\":{\"name\":\"asdf\",\"id\":\"2\"}},{\"service\":{\"name\":\"asdfg\",\"id\":\"3\"}}]}";
Services services = gson.fromJson(s, Services.class);
Basically, the json string is not a simple json array format, it is actually a json array inside a json object. So it implies that you need two Class, one represents each item inside json array - Service.java and another plays as a wrapper holding a list of items.

How can I deseralize json object in java pojo class?

I have a simple JSON statement which type is very per need. like this
{
actor:{name:"kumar",mbox:"kumar#gmail.com"}
verb :"completed"
}
or
{
actor:{name:["kumar","manish"],mbox:["kumar#gmail.com","manish#gmail.com"]}
verb :{
"id" : "http://adlnet.gov/expapi/verbs/completed",
"display" : {
"en-US" : "completed"
}
}
I am using using POJO class to map this json string and pojo class code is given bleow
#JsonProperty("actor")
Actor actor;
#JsonProperty("verb")
Verb objVerb;
#JsonProperty("verb")
String verb;
public Actor getActor() {
return actor;
}
public void setActor(Actor actor) {
this.actor = actor;
}
public Verb getObjVerb() {
return objVerb;
}
public void setObjVerb(Verb objVerb) {
this.objVerb = objVerb;
}
#JsonIgnore
public String getVerb() {
return verb;
}
#JsonIgnore
public void setVerb(String verb) {
this.verb = verb;
}
public static class Actor {
String objectType;
#JsonProperty("name")
ArrayList<String> listName;
#JsonProperty("name")
String name;
#JsonProperty("mbox")
ArrayList<String> listMbox;
#JsonProperty("mbox")
String mbox;
#JsonProperty("mbox_sha1sum")
ArrayList<String> Listmbox_sha1sum;
#JsonProperty("mbox_sha1sum")
String mbox_sha1sum;
#JsonProperty("openid")
String openid;
#JsonProperty("account")
Account account;
public String getObjectType() {
return objectType;
}
public void setObjectType(String objectType) {
this.objectType = objectType;
}
public ArrayList<String> getListName() {
return listName;
}
public void setListName(ArrayList<String> listName) {
this.listName = listName;
}
#JsonIgnore
public String getName() {
return name;
}
#JsonIgnore
public void setName(String name) {
this.name = name;
}
public ArrayList<String> getListMbox() {
return listMbox;
}
public void setListMbox(ArrayList<String> listMbox) {
this.listMbox = listMbox;
}
#JsonIgnore
public String getMbox() {
return mbox;
}
#JsonIgnore
public void setMbox(String mbox) {
this.mbox = mbox;
}
public ArrayList<String> getListmbox_sha1sum() {
return Listmbox_sha1sum;
}
public void setListmbox_sha1sum(ArrayList<String> listmbox_sha1sum) {
Listmbox_sha1sum = listmbox_sha1sum;
}
#JsonIgnore
public String getMbox_sha1sum() {
return mbox_sha1sum;
}
#JsonIgnore
public void setMbox_sha1sum(String mbox_sha1sum) {
this.mbox_sha1sum = mbox_sha1sum;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public static class Account {
#JsonProperty("homePage")
String homePage;
#JsonProperty("name")
String name;
public String getHomePage() {
return homePage;
}
public void setHomePage(String homePage) {
this.homePage = homePage;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
public static class Verb {
String id;
Map<String,String> display;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Map<String, String> getDisplay() {
return display;
}
public void setDisplay(Map<String, String> display) {
this.display = display;
}
}
I am using jaxb and jakson. I am implementing the webservice to handle the json statement
so I use the bean class to map with json. But when I use to map this json then it gives the following exceptions
org.codehaus.jackson.map.JsonMappingException : property with the name "mbox" have two entry.
Define a proper bean structure so it directly mapped to the beans class
Try to leave only #JsonProperty("mbox") ArrayList<String> listMbox; field (don't need #JsonProperty("mbox")
String mbox;)
and add Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY=true to Jackson object mapper config.
So in deserialization it will be able to get as both array and single element.
you can use gson.
class cls = gson.fromJson(jsonString, clazz);
here jsonString can be stringified java script object. gson.fromJson method can map your java script key to java property.