.net json property conversion in java - #JsonProperty - java

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);

Related

Create class with same fields as another class with few exceptions

Suppose I have class A like this
class A {
private String Id;
private String name;
private String age;
//... some other hundres of feilds
}
How can I create another DTO named CreateA which contains all fields for A except the one I mention like id ?
something like this
#sameAs("A")
#skip("Id")
class CreateA {}
is there any java library for this ?

QUARKUS - MicroProfile REST Client: add a custom, not mapped field

I am following this article https://quarkus.io/guides/rest-client to build a REST Client to parse the output from the restcountries.eu service.
Here the class holding the model:
public class Country {
public String name;
public String alpha2Code;
public String capital;
public List<Currency> currencies;
public static class Currency {
public String code;
public String name;
public String symbol;
}
}
Now, suppose I would like to add a custom fields such as timestamp, to record the instant when this object has been created. I imagine, I would go ahead and add another field like below:
public class Country {
public String name;
public String alpha2Code;
public String capital;
public List<Currency> currencies;
public Instant timestamp; //<--------- added attribute
[....]
My question is: how do I tell the client to populate that field? Normally, I would have done it in the constructor. However, I could not find docs that explain this part.
Thanks for your help
Simone
You can actually do this in the default constructor. Frameworks like JSONB or Jackson expect POJOs to have a default constructor. They will call it when they create an instance of Country.
Use the #JsonbTransient or #JsonIgnore annotations to mark that attribute of your POJO as ignorable in order to avoid the unmarshaller complaining about attributes that cannot be found in the response.
#Data
public class Country {
private String name;
private String alpha2Code;
private String capital;
private List<Currency> currencies;
#JsonbTransient // if you're using JSONB (default in Quarkus)
#JsonIgnore // if you're using Jackson
private Instant timestamp;
public Country() {
this.timestamp = Instant.now();
}
PS The #Data annotation is something you should consider using. Encapsulation is not a bad thing but creating getters/setters is tedious. But Project Lombok certainly helps here.

Java Gson ClassCastException

I am building a Java Servlets 3.0 REST API and using Gson to serialize some data to json.
I get this error, though:
java.lang.ClassCastException: za.co.a.models.tables.sybase.Family cannot be cast to java.util.Map
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:145)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:97)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:61)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245)
at com.google.gson.Gson.toJson(Gson.java:704)
at com.google.gson.Gson.toJson(Gson.java:683)
at com.google.gson.Gson.toJson(Gson.java:638)
at com.google.gson.Gson.toJson(Gson.java:618)
at za.co.a.helpers.JsonHelper.toJson(JsonHelper.java:33)
at za.co.a.models.tables.sybase.ActiveProcesses.saveProcess(ActiveProcesses.java:57)
My code is as follows:
#Table(name = "E_FAMILY")
public class Family extends IGenericModel <Family>
{
#Id
public BigDecimal EMPLOYEE_ID;
#Id
public BigDecimal FAMILY_ID;
#Id
public BigDecimal COMPANY_ID;
public String FIRSTNAME;
public String SECONDNAME;
public String SURNAME;
public String RELATION;
public int RELATION_ID;
public String MED_DEPENDENT_YN;
public String TAX_DEPENDENT_YN;
public String GENDER;
public Date BIRTHDATE;
public String TEL_HOME;
public String TEL_WORK;
public String TEL_CELL;
public String E_MAIL;
...
}
The calling code:
public String toJson(Object obj)
{
return gson.toJson(obj);
}
Family, in this case is field in a larger class, however, I'm not having any problems with any other fields or any other classes that are similar. This is the first time, in the year I've been developing this, that this error comes up. Is there a limit to the size or complexity of class Gson can serialize? Or what can I check to see what's causing the error? Or is there a way change this specific mapping, (though I don't understand why Google is trying to map this class to Map)?
Thanks
Sethmo
Edit Including class hierachy
IGenericModel and IGenericReadOnlyModel only contain functions. IModel has 2 members, but I've added it as part of an ExclusionStrategy so that those members don't get serialized.
public class IGenericModel<T> extends IGenericReadOnlyModel
{
}
public class IGenericReadOnlyModel<T> extends IModel
{
}
public class IModel
{
protected String dbEngine;
protected IDatabase db;
}
Edit rest of the code
Ok, the class that holds Family is quite large and mostly full of Strings, Dates and Booleans and ints. Where Family comes in is here, the two objects are passed from the front-end and represent the old and new values (users can edit, add and delete family members in the UI, then submit those lists).
public abstract class IWebProcess extends IModel
{
protected Object _OldValue;
protected Object _NewValue;
}
Once submitted (as JSON from the UI), it's serialized:
Type familyType = new TypeToken<LinkedList<Family>>(){}.getType();
LinkedList<Family> oldFamily = gson.fromJson(oldFamilyJson, familyType);
LinkedList<Family> newFamily = gson.fromJson(newFamilyJson, familyType);
Then, the concrete class is then initialized:
IWebProcess family = WebProcess_FamilyRequisition(oldFamily,newFamily,...,...,...)
then, in the constructor of WebProcess_FamilyRequisition, I call super(oldFamily, newFamily) and then in the constructor of IWebProcess:
this._OldValue = oldFamily
this._NewValue = newFamily
I do all this casting because I save the new values to the DB first, before serializing the entire WebProcess to the DB. I've made _OldValue and _NewValue Objects because this is a base class for 8 other classes that work the same and they serialize just fine.

To define an object in a constructor in Serializable class

I have a JSON response like below image, and I have made a serializable class named as Project
In the image, I have two objects (emergency_contact, and secondary_owner) inside my an array of one object. I'm trying to figure out whether what to do in order to define the object, since I want that details to be present inside my constructor.
I have done this so far:
public class Project implements Serializable {
public int id;
public String name;
public String additional_information;
//Now what to do Emergency contact
public Project(int id, String name, String additional_information){
}
}
I have thought of doing this, public EmergencyContact emergency = new EmergencyContact(param1, param2).
And make a new class named as EmergencyContact, and do a getter and setter for the params. But after doing this, I'm still confused, how would I define it my constructor?
I know I'm close, but I need some help on that.
Sure. You need to have a:
public class EmergencyContact implements Serializable {
public String name;
public String number;
public EmergencyContact(String name, String number){
// assign fields
}
}
and one for the owner:
public class EmergencyOwner implements Serializable {
public String name;
public String number;
public EmergencyOwner(String name, String number){
// assign the fields
}
}
then in your Project class you can add fields of these classes:
public class Project implements Serializable {
public int id;
public String name;
public String additional_information;
public EmergencyContact emergency_contact;
public EmergencyOwner emergency_owner;
public Project(int id, String name, String additional_information, EmergencyContact emergency_contact, EmergencyOwner emergency_owner){
// assign the fields here as well
}
}
that's it. If that's an answer to the question consider to delete this question as it is a duplicated on a 100% :)
As a note, to be correctly from the point of clean code parameters, the fields should be private in a class, and use setters / getters to set/retrieve values from/to those fields.
public class Project implements Serializable {
private int id;
private String name;
private String additional_information;
private EmergencyContact emergency_contact;
private SecondaryOwner secondary_owner;
public Project(int id, String name, String additional_information, EmergencyContact emergencyContact, SecondaryOwner secondaryOwner){
this.id = id;
this.name = name;
this.additional_information = additional_information;
this.emergency_contact = emergencyContact;
this.secondary_owner = secondaryOwner;
}
}
You will define the other two classes the same way. Now, you are probably confused about the constructor of EmergencyContact & SecondaryOwner classes.. You can device both default constructors (without parameters) and a custom one(with parameters to it, just as the one above). If you use the default constructor, make sure to set values to the fields in the object, as following :
EmergencyContact emergencyContact = new EmergencyContact();
emergencyContact.setName("the name");
emergencyContact.setNumber("a number");
then you can use this object in the constructor of Project class
I hope it was clear enough, for any other clarifications feel free to ask.
Happy coding <3

Jackson: remove some values from json and keep some null values

I have a model like this:
public class Employee {
#JsonProperty("emplyee_id")
private Integer id;
#JsonProperty("emplyee_first_name")
private String firstName;
#JsonProperty("emplyee_last_name")
private String lastName;
#JsonProperty("emplyee_address")
private String address;
#JsonProperty("emplyee_age")
private Byte age;
#JsonProperty("emplyee_level")
private Byte level;
//getters and setters
}
now I need to create two JSONs using this (only) model.
the first one must like this for example:
{
"employee_id":101,
"employee_first_name":"Alex",
"employee_last_name":"Light",
"employee_age":null,
"employee_address":null
}
and the second one must like this for example:
{
"employee_id":101,
"employee_level":5
}
by the way, I already tested #JsonIgnore and #JsonInclude(JsonInclude.Include.NON_NULL).
the problem of the first one (as much as I know) is, those fields can't be included in other JSONs (for example if level get this annotation, it won't be included in the second JSON)
and the problem of the second one is, null values can't be included in JSON.
so can I keep null values and prevent some other property to be included in JSON without creating extra models? if the answer is yes, so how can I do it? if it's not I really appreciate if anyone gives me the best solution for this state.
thanks very much.
it could be useful for you using #JsonView annotation
public class Views {
public static class Public {
}
public static class Base {
}
}
public class Employee {
#JsonProperty("emplyee_id")
#JsonView({View.Public.class,View.Base.class})
private Integer id;
#JsonProperty("emplyee_first_name")
#JsonView(View.Public.class)
private String firstName;
#JsonProperty("emplyee_last_name")
#JsonView(View.Public.class)
private String lastName;
#JsonProperty("emplyee_address")
private String address;
#JsonProperty("emplyee_age")
private Byte age;
#JsonProperty("emplyee_level")
#JsonView(View.Base.class)
private Byte level;
//getters and setters
}
in your json response add #JsonView(Public/Base.class) it will return based on jsonview annotations
//requestmapping
#JsonView(View.Public.class)
public ResponseEntity<Employee> getEmployeeWithPublicView(){
//do something
}
response:
{
"employee_id":101,
"employee_first_name":"Alex",
"employee_last_name":"Light",
"employee_age":null,
"employee_address":null
}
for the second one
//requestmapping
#JsonView(View.Base.class)
public ResponseEntity<Employee> getEmployeeWithBaseView(){
//do something
}
response
{
"employee_id":101,
"employee_level":5
}

Categories