I have a use case where we have to send different JSONs to different servers.
The difference is only between JSON keys, the meaning the keys carry is same and so is the data.
For example server XYZ wants JSON data to be sent in this format:
{ "firstName":"Sam", "lastName":"Jones"}
Now server ABC wants JSON data to be sent in this format:
{ "fName":"Sam", "lName":"Jones"}
And firstName and lastName data is populated via a POJO.
So, How do I achieve this? I do not want to clutter the code with if-else conditions.
But wnat to have something which would work like a template loaded dynamically and create the JSON data and also retrieve it back to the POJO.
You should create two POJOs. One for each server. Each POJO can have different property names to satisfy each of the server's requirements.
Or the POJOs can have the same property names, but be annotated to generate different JSON properties. A JSON library like Jackson can do this using the JsonProperty annotation.
How about this strategy?
1. Defines the interface to be used as a common..
interface People{
public String getRegularFirstName();
public String getRegularLastName();
}
2. Define each POJO with implemented interface
//class for "{ "firstName":"Sam", "lastName":"Jones"}"
class PeopleData2 implements People{
private String firstName;
private String lastName;
public String getRegularFirstName(){
return firstName;
}
public String getRegularLastName(){
return lastName;
}
//getter setter here..
}
//class for "{ "fName":"Sam", "lName":"Jones"}"
class PeopleData1 implements People{
private String fName;
private String lName;
public String getRegularFirstName(){
return fName;
}
public String getRegularLastName(){
return lName;
}
//getter setter here..
}
3. Make each json format deserved each POJO classes..
It is not dinamically strategy because it need to add class whe new format comes up.
but it will help system scalability
Related
Need some help here! I have a Java Rest API which is getting data from a .net endpoint and passing it on to the UI. The JSON properties are in capital case and I want to convert them in JAVA before sending it to the UI. Any pointers on this?
In java, I have a class like below:
public class Person {
#JsonProperty("Name")
private String name;
#JsonProperty("Age")
private int age;
}
I am using #JsonProperty as keys in .net are starting with capitalCase. How can I convert this back before sending it to the UI in Java?
Thanks for the help!
Create another class with the same structure and use there other names that you want. Something like this:
// Class to read .NET object
public class Person {
#JsonProperty("Name")
private String name;
#JsonProperty("Age")
private int age;
}
// Class to represent the object in Java REST API
public class Person {
#JsonProperty("name")
private String name;
#JsonProperty("age")
private int age;
}
// Class to represent the object in Java REST API,
// in case you use some standard library that
// uses property names for JSON as is
public class Person {
private String name;
private int age;
}
Of course you should put these classes into different packages.
Your code can look as follows:
xxx.dotnet.Person dotnetPerson = doSomethingViaDotNet(...);
yyy.rest.Person restPerson = new yyy.rest.Person();
restPerson.setName(dotnetPerson.getName());
restPerson.setAge(dotnetPerson.getAge());
...
return restPerson;
If you decide to use MapStruct, your code may looks as follows:
#Mapper
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper( PersonMapper.class );
yyy.rest.Person dotnetToRest(xxx.dotnet.Person dotnetPerson);
}
Since all attributes have the same names and types you don't need anything else in your mapper.
MapStruct will generate a class that implements this interface. Usage will be as follows:
restPerson = PersonMapper.INSTANCE.dotnetToRest(dotnetPerson);
I've got MultivaluedMap of custom object types which I am serializing using Gson. One of my requirement is to change the name of one of the object based on the length of the string to some other name.
I know that we can use annotations #SerializedName but it provides option for only one name alternative whereas I'm looking for two names for the same attribute and use it dynamically when serializing based on the string length.
How can I accomplish this?
Here's the outline of my custom object types:
Toplevel Class:
public class CompleteData{
private String country,
private String appId,
Private String userId,
private List<RecipientInfo> recipients;
private CustomDocument document;
<<setters//getters>>
public CompleteData(String country, String appId, String userId, List<RecipientInfo> recipients, CustomDocument document){
this.country=country..
..
..
}
CustomDocument Class:
public class CustomDocument{
String name;
String pageCount;
public CustomDocument(String name, int pageCount){
this.name = name;
this.pageCount = pageCount;
}
RecipientInfo Class:
public class RecipientInfo{
#serializedName("fullName")
String name;
String phoneNum;
public RecipientInfo(String name, String phoneNum){
this.name = name;
this.phoneNum = phoneNum;
}
}
Now I create List<CompleteData> completeData = new ArrayList<>();
Gather all the necessary information and add it to a MultivaluedMap as there are duplicate keys involved:
MultiValuedMap(<String, List<CompleteData>)
Now while using Gson to serialize this object, I want to change the "name" attribute in RecipientInfo class to be able to change dynamically based on the string length as fullname if the length is (>10 and <15) and fullNamewithSalu if the length is >20
Should I create a new class all together for this small change or is there a way I can serialize this object using Gson dynamically ?
Please help!
Thank you!
I have to generate strange json from object(with jackson ObjectMapper), something like:
{
"data":{
"id":"1",
"name":"Json"
},
"userType":"MD"
}
But, with jackson data-bind i can do only:
{
"id":"1",
"name":"Json",
"userType":"MD"
}
With User.class:
public class User {
private String id;
private String name;
private String userType;
//Getters Setters Constructor
I found two ways of bypassing. First one - to use another "superclass":
public class Data {
#JsonProperty("data")
private User user;
private String userType;
//Getters Setters Constructor
Second way - to use Map:
Map<String, Object> map = new HashMap<>();
map.put("data", user);
map.put("userType", "MD");
String json = objMapper.writeValueAsString(map);
But i think, that it's not idea to use this ways if i have about 8 different objects with such structure. So, what's best pratice? Or maybe there are another built in ways?
I want to find the best one
The first approach you mentioned is the best practice, but it is called Composition (HAS-A relationship) rather 'superclass' and just to add readability, you can refactor your classes like this:
public class User {
private Data data;
private String userType;
//Getters Setters Constructor
}
public class Data {
private String id;
private String name;
// getters and setters
}
So, when you marshal your pojo to json, structure will be:
{
"data":{
"id":"1",
"name":"Json"
},
"userType":"MD"
}
which is what you want! Happy coding :)
Update: If you are generating your API documentation with Swagger or Open API Spec, then there is no way to have a representation of your model if you use Map or HashMap. So, obviously, the first approach is the one you should consider!
I am using Gson for converting between json and java object.
Let's say the json is like this:
{
"name": "John",
"age": 12,
"adult": false
}
The class for the json is:
public class Student {
#Expose
#SerializedName("name")
private String name;
private int age;
private boolean adult;
// setters for all fields above
public void setName(String name) {
this.name = name;
}
...
// getters for all fields above
public String getName() {
return name;
}
...
}
My questions are:
Is it so that all fields showing in json should have #Expose annotation? Does that also mean we can have other fields which are not part of the json string?
Is it so that only if the field name in json and the variable name in java class is different, then use #SerializedName annotation is needed, otherwise it is optional?
Are setter functions necessary in java class for the fields?
The short answers to your questions are 1. yes, 2. yes, 3. no.
Gson has a lot going on under the hood - your Student class needs very little for it to do its work:
data members which match the key values in the JSON (case-sensitive!)
public getter methods
You can have more data members that don't necessarily match the key names in the JSON, they'll just end up getting set to null when Gson processes the data. Gson also does not require any annotations so long as the variable names match the key names in the JSON. You are allowed to have any kind of setter methods if you need them for other functionality (Gson does not). Basically, the only thing that Gson is looking for is data members that match the keys, and the getter methods. Whether your class is more complex is up to you and what your application needs.
edit: All of the values that Gson processes will be of the String type. If you have int and boolean types you will need to process the input as a String and operate on it to convert it to what you are looking for.
I'm trying to use jcouchdb (https://code.google.com/p/jcouchdb/) for accessing my CouchDB instance from Java. I have some JSon documents that I'd like to parse into Java classes - with Svenson, used in jcouchdb, and then put those parsed objects into DB. I generate this JSON objects with AVRO (http://avro.apache.org) JSon Encoder, they seem to be ok, but apparently other parsers have problems with them.
My JSon strings look like this:
{
"id":40,
"event_id":"48764322212",
"note":{
"string":"ABC note"
},
"created_date":null,
"event_category":null,
"city":null,
"address":null
}
Which seems valid JSON - validated with http://jsonformatter.curiousconcept.com/
However my Svenson object defined like this:
public class Note {
Long id;
String eventId;
String note;
String createdDate;
String eventCategory;
String city;
String address;
#JSONProperty()
public Long getId() {
#JSONProperty("event_id")
public String getEventId() {
#JSONProperty("note")
public String getNote() {
#JSONProperty("created_date")
public String getCreatedDate() {
#JSONProperty("event_category")
public String getEventCategory() {
#JSONProperty("city")
public String getCity() {
#JSONProperty("address")
public String getAddress() {
}
(setters and getters' bodies intentionally removed)
The error when parsing is:
Cannot set property string on class java.lang.String
It seems that this JSON is parsed correctly (there is a difference in note field):
{
"id":40,
"event_case_id":"000-123123123",
"event_msisdn":"48764322212",
"note":"Planowana data portacji: 2011/01/27 11:42:49",
"created_date":null,
"event_category":null,
"city":null,
"address":null
}
How can I work this out? Perhaps there is another json library that would work for me?
You declare note as a java.lang.String:
public String getNote()
but in the JSON you declare it as an Object with a property named "string":
"note":{
"string":"ABC note"
}
You need to change the JSON or the Bean to match each other. For example, in the second functioning JSON, you declared the JSON note as a string. This is why it works.