Complex POJO mapping using Dozer - java

I am new to Dozer, and have done flat mapping from one POJO to another using Dozer xml mapping.But now I want to map complex POJO which is given below and I am stucked how to do it.
// -----------------------Source Classes-----------------------------
public class Source{
public String sourceId;
public Product product;
public List<Item> items;
}
public class Product{
public Integer productId;
public String productName;
}
public class Item{
public Integer id;
public Integer qty;
public String desc;
}
// -----------------------Destination Classes-------------------
public class Destination{
public String destId;
public DestProduct destProduct;
public List<DestItem> destItems;
}
public class DestProduct{
public Integer nProductId;
public String sProductName;
}
public class DestItem{
public Integer nId;
public Integer nQty;
public String sDesc;
}
How do I tell Dozer to map Source to Destination?

You should check Dozer documentation. It has everything you need to map your classes.
I think you are worried mainly for below mappings:
1. Map custom object fields and wrapper classes fields:
Check the Basic property mapping in dozer documentation. Many data type coversions are performed automatically by the Dozer mapping engine. Check the below link for more info.
http://dozer.sourceforge.net/documentation/simpleproperty.html
2. List fields containing custom object mappings:
This is explained at the below link:
http://dozer.sourceforge.net/documentation/collectionandarraymapping.html#
For cases where a feature isn't supported out of the box, you can also write a custom converter:
http://dozer.sourceforge.net/documentation/customconverter.html
Also, It will help to first write simple standalone programs to understand/test a particular mapping before jumping with implementation in your project.

Related

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.

.net json property conversion in java - #JsonProperty

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

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.

How to cancel #jsonIgnore in specific method

I have a domain javabean, some bean hvae a lot of information with password
and login Ip, I use the #jsonIgnore to filter that property which I dont
want the end user know.
But there has a problem,In other method
I use the same javabean to send back
to front side,but now I need some property from this domain
has anyway can cancel this #jsonIgnore in some specific method?
#JsonIgnore
private String address;
private Integer drawnum;
but now I need address , I cant do this.....
I dont want to use the for loop to add in other object.
I think that what you are looking for is the concept of JsonView : in some cases you want a set of attributes to be serialized, and in some other cases you want a (slightly) different set of attributes to be serialized.
Check this excellent tutorial, it explains evrything, even the use with Spring MVC.
Create classes to annotate the fields :
public class Views {
public static class Public {
}
public static class Internal extends Public {
}
}
Annotate the fields :
public class Item {
#JsonView(Views.Public.class)
public int id;
#JsonView(Views.Public.class)
public int drawnum;
#JsonView(Views.Internal.class)
public String address;
}
In the controller, if you want only "public" properties to be serialized ;
#JsonView(Views.Public.class)
#RequestMapping("/items/{id}")
public Item publicItem(#PathVariable int id) {
Result : {"id":2,"drawnum":5}
In another controller, if you want all properties to be serialized ;
#JsonView(Views.Internal.class)
#RequestMapping("/items/{id}")
public Item internalItem(#PathVariable int id) {
Result : {"id":2,"drawnum":5,"address":"My address"}

Jackson ignore all properties of superclass from external library

I am developing using an ORM where I extend a base orm class to create tables.
For example:
public class Person extends DbItem {
#JsonIgnore
private String index;
private String firstName;
private String lastName;
}
Problem is that when I use ObjectMapper to serialize, it tries to serialize the members of the DbItem class. Is there any simple way to prevent this? For example with an annotation.
I had a look at a similar problem Jackson serialization: how to ignore superclass properties but I was hoping it could be done simpler, and I'm not sure if I could do it as I can't change the superclass since it is in an external library.
You can use a Mix-in or #JsonIgnoreProperties
For the purposes of these examples, the base ORM class and extension are assumed to be:
public class DbItem {
public String dbPropertyA;
public String dbPropertyB;
}
and
public class Person extends DbItem {
public String index;
public String firstName;
public String lastName;
}
respectively.
Using a Mix-in
A Mix-in is an abstraction of the de/serialization instructions that Jackson understands from an object itself. It is a way to customize de/serialization of 3rd party classes. In order to define a Mix-in, an abstract class must be created and registered with the ObjectMapper.
Example Mix-in Definition
public abstract class PersonMixIn {
#JsonIgnore public String dbPropertyA;
#JsonIgnore public String dbPropertyB;
#JsonIgnore public String index;
}
Registering the Mix-in
#Test
public void serializePersonWithMixIn() throws JsonProcessingException {
// set up test data including parent properties
Person person = makeFakePerson();
// register the mix in
ObjectMapper om = new ObjectMapper()
.addMixIn(Person.class, PersonMixIn.class);
// translate object to JSON string using Jackson
String json = om.writeValueAsString(person);
assertFalse(json.contains("dbPropertyA"));
assertFalse(json.contains("dbPropertyB"));
assertFalse(json.contains("index"));
System.out.println(json);
}
#JsonIgnoreProperties
If you want to avoid creating a class and configuring the ObjectMapper, the #JsonIgnoreProperties annotation can be utilized. Simply annotate the class you are serializing and list the properties to exclude.
Example Serializable Object
#JsonIgnoreProperties({"index", "dbPropertyA", "dbPropertyB"})
public class Person extends DbItem {
public String index;
public String firstName;
public String lastName;
}
See It In Action
#Test
public void serializePersonWithIgnorePropertiesAnnotation() throws JsonProcessingException {
// set up test data including parent properties
Person person = makeFakePerson();
ObjectMapper om = new ObjectMapper();
// translate object to JSON string using Jackson
String json = om.writeValueAsString(person);
assertFalse(json.contains("dbPropertyA"));
assertFalse(json.contains("dbPropertyB"));
assertFalse(json.contains("index"));
System.out.println(json);
}
You want to do custom field level serialization. This will be a bit more work to maintain your code base, but is by far the simplest solution. See Jackson JSON custom serialization for certain fields for implementation details.

Categories