Is it possible with Dozer to map from Java Object to xml? - java

What i want is:
I have a java DTO object...simple getters setters (dates,string, int..so on) and i want to generate from the jva object to a xml string..so for example:
DTOclass{
int id;
String name;
//Getters-settters
}
and i want to create like:
<id>dto.getId()</id> <!--With dozer of course...just call a map method and somehow i create a string from that-->
<name>dto.getName()</name>
Thanks a lot!

It's not possible with Dozer. The very first line of the About page states it's meant for mapping Java Beans to each other (and nothing else).
Maybe you could get creative and find another library to use in conjunction with Dozer.

Related

Modeling JSON in Java

The few times I've worked with Java/Rest/JSon, JSON elements have always been built in camelCase format.
For example:
"someField": {
"someSonField1": "20191106",
"someSonField2": "20201119",
...
}
However, in a functional document they have passed me to build a Rest JSon client, they use this notation:
"some_field": {
"some_son_field_1": "20191106",
"some_son_field_2": "20201119",
...
}
Is it expressed somewhere that Java has to use the notation 1?.
It seems to me that if it is done this way, everything goes much more smoothly when modeling the objects:
#XmlRootElement(name = "someField")
#XmlType(propOrder = {"someSonField1", "someSonField2"})
public class someField {
private String someSonField1;
private String someSonField2;
//...
}
Thanks!
Q: Is it expressed somewhere that Java has to use the notation?
A: No: it's 100% "convention", not mandatory.
As it happens, the standard convention for both JSON (a creature of Javascript) and Java is camelcase. For example: Java Naming Conventions.
some_son_field_1 is an example of snake case. It's associated with classic "C" programs. It's also common (but NOT universal) with XML. It, too, is a "convention" - not a requirement.
I'm curious why you're choosing XML bindings for JSON data. Have you considered using Jackson?
Finally, this article might be of interest to you:
5 Basic REST API Design Guidelines
I see you're using javax.xml.bind package? Have you tried #XmlElement?
#XmlRootElement(name = "someField")
#XmlType(propOrder = {"some_son_field_1", "some_son_field_2"})
public class someField {
#XmlElement(name="some_son_field_1")
private String someSonField1;
#XmlElement(name="some_son_field_2")
private String someSonField2;
//...
}
Not sure, probably you should try putting them on getters, as your fields are private.
Or you could use unify-jdocs, a library which I created to read and write JSON documents without using any POJO objects. Rather than defining POJO objects, which we know can be difficult to manage in case of complex documents and changes to the JSON document, just don't use them at all. Directly read and write paths in the JSON document. For example, in your snippet, you could read and write the fields as:
Document d = new JDocument(s); // where s is a JSON string
String s1 = d.getString("$.some_field.some_son_field_1");
String s2 = d.getString("$.some_field.some_son_field_2");
You could use a similar way to write to these paths as so:
d.setString("$.some_field.some_son_field_1", "val1");
d.setString("$.some_field.some_son_field_2", "val2");
This library offers a whole lot of other features which can be used to manipulate JSON documents. Features like model documents which lock the structure of documents to a template, field level validations, comparisons, merging documents etc.
Obviously, you would consider it only if you wanted to work without POJO objects. Alternatively, you could use it to read and write a POJO object using your own method.
Check it out on https://github.com/americanexpress/unify-jdocs.

Good practices in REST / Java

I'm currently trying to acquire skills in REST, and specifically in "good" Rest, hypermedia and all the good practices that comes with it.
In order to do so, I was asked to develop a prototype REST server containing data of my choice and implementing everything I'll have to use in a real project coming after that.
So I made a server using Spring boot and Jackson for json handling.
My data architecture is close to this : I have a collection of LaunchVehicle (I like space =D) like Ariane V, Falcon 9, etc. I can retrieve the JSON object flawlessly
{ "name":"Ariane V","country":"Europe","firstFlight":null,"GTO_Payload":1.0,"LEO_Payload":2.3,"weight":136.0 }
The thing is, I'd like to add a "space agency" field which would be an object containing some Strings and Floats, inside my LaunchVehicle. However, when the client retrieve a LaunchVehicle, I don't want it to retrieve the full SpaceAgency object, just the name for exemple. From here, he would be able to follow the link to the space agency via an hypermedia link included in the response it would have received.
How can I do this ? Right now I'm only able to send to the client my full LaunchVehicle object with the SpaceAgency object and all his fields. Is there any annotations doing what I want ? Thanks ;)
public class LaunchVehicle {
private String name;
private String country;
private Date firstFlight;
private Map<String, Float> characteristics;
private SpaceAgency spaceAgency;
#JsonCreator
constructor...
#JsonProperty(required=false)
getters and setters...
}
Thanks a lot, don't hesitate if I'm not precise or understandable enough.
Try #JsonIgnoreProperties annotation at the class level. That should provide you the feature that you want.
Otherwise, you could always use some kind of DTO object to create your response model, and there just have the fields that are going to be used at the API layer.
I would rather prefer to use an appropiate DTO/ApiModel for your API layer than having a full domain object with JSON annotations in it.
If your SpaceAgency class only defines the properties that you need to deserialize, Jackson will only deserialize those. It will forget the unmapped properties.
Try jax-ws-rs!
It's a standart REST implementation in Java.
Oracle docs
Very good tutorial by Mkyong
You can use the Gson API for this
JsonParser parser = new JsonParser();
JsonObject obj = parser.parse(spaceAgency).getAsJsonObject();
String agencyName = obj.get("agencyName").getAsString();
I think you should reference the space agency as a hyperlink.
So the JSON will look like:
{ "name":"Ariane V",
"country":"Europe",
< other fields omitted >
"_links": {
"agency": { "href": "agencies/ESA" },
< other links omitted >
}
}
To achieve this you need to specify the link in your data transfer object. Don't make this a reference to an actual object of that type -- to do so would mean populating that object, even when the client doesn't ask for it.
How you achieve this depends on what technology you're using. In Jersey it's
public class LaunchVehicle {
...
#InjectLink(resource=AgencyResource.class)
URI agencyLink;
...
}
https://jersey.java.net/documentation/latest/declarative-linking.html
Linking like this is what "real" REST is all about. However note that plenty of real-world solutions claim to be doing REST without actually using hyperlinks. A more hacky solution would be to have a String agencyId field in your JSON, which could be put into a URL template to get agency details.

Limiting Fields in JSON Response for REST API?

I am using Spring and Java and implementing REST Based services. I have a set of developers who develop for mobile,iPad and Web too. Consider I have a bean
Class User{
private String Name;
private Integer id;
private String photoURL;
private ArrayList<String> ProjectName;
private ArrayList<String> TechnologyList;
private ArrayList<String> InterestList;
//Getters and setters
}
While the Web Developers need the entire fields and mobile developers just require two fields from it whereas the iPad requires something in between mobile and web.
Since I am using jackson as a parser, is there a way where while requesting to the controller I can specify which all data I require and avoid the others. For example consider I do a GET request like
GET>http://somedomain.com/users?filter=name,id,photoUrl
Which returns me a JSON structure something like
{
"name":"My Name",
"id":32434,
"photoUrl":"/sss/photo.jpg"
}
Sameway if someone asks for some more fields, they could be filtered. Please let me know how this can be done so that my API remains generic and useable for all.
You can achieve what you want but some extra work is necessary. I can offer you two solutions.
1. Return a Map
Simply put every property that is requested into the map.
2. Use Jacksons Object Mapper directly
Jackson lets you set filters that specify which properties are serialized or ignored.
FilterProvider filter = new SimpleFilterProvider().addFilter("myFilter",
SimpleBeanPropertyFilter.filterOutAllExcept(requestedProperties));
String json = objectMapper.writer(filter).writeValueAsString(value);
You can then return the JSON string directly instead of an object.
For both solutions you would ideally write a class that does the job. But if you do that you could as well write your own message converter. You could extend the MappingJackson2HttpMessageConverter, for instance, and overwrite the writeInternal method to suit your needs. That has the big advantage that you don't need to change your controllers.
The straightforward solution is to implement custom Jackson JSON serializer that will get field names that should be serialized from thread local storage and then serialize only fields which names are presented in that context. For other hand, in controller you can grab all allowed fields names from url and store them into thread local context. Hope this helps.

Simple object-to-object mapper without xml?

I'm looking for an object-to-object mapper that works without XML configurations. It should be possible to transform any simple type as well as nested lists from one object to a completely different object.
Like:
class IncomingDTO {
String firstname;
String lastname;
List<Customer> customers;
}
class Customer {
Address address;
}
class ResultDTO {
String name; //should be a combination of firstname+lastname
List<Address> addresses; //which might come from
}
I'm looking for a way to not having iterate through each of the objects and copy every single entry manually. Maybe there is a library that I can give some kind of mapping configuration that does the rest for me?
I'd prefer to do this in your Java code if possible. I'm not sure why there's a benefit to having some declaration-based solution when a code-based solution is more likely easier to read and more extensible.
If you need a framework to do this, perhaps Dozer is of use. It provides a means of identifying mappings using annotations (as well as XML)
You should have a look at apache commons beanutils http://commons.apache.org/proper/commons-beanutils/
org.apache.commons.beanutils.BeanUtils
has methods to help you like
public static void copyProperties(Object dest, Object orig)
which
Copy property values from the origin bean to the destination bean for
all cases where the property names are the same.
Take a look at Orika,
Orika is a Java Bean mapping framework that recursively copies (among other capabilities) data from one object to another. It can be very useful when developing multi-layered applications.
Orika on GitHub

Dozer deep mapping not working

I am trying to use dozer 4.1 to map between classes. I have a source class that looks like this:
public class initRequest{
protected String id;
protected String[] details
}
I have a destination class that looks like this:
public class initResponse{
protected String id;
protected DetailsObject detObj;
}
public class DetailsObject{
protected List<String> details;
}
So essentially i want the string in the details array to be populated into the List in the Details object.
I have tried a mapping like this:
<mapping wildcard="true" >
<class-a>initRequest</class-a>
<class-b>initResponse</class-b>
<field>
<a is-accessible="true">details</a>
<b is-accessible="true">detObj.details</b>
</field>
</mapping>
But I get this error:
Exception in thread "main" net.sf.dozer.util.mapping.MappingException: java.lang.NoSuchFieldException: detObj.details
at net.sf.dozer.util.mapping.util.MappingUtils.throwMappingException(MappingUtils.java:91)
at net.sf.dozer.util.mapping.propertydescriptor.FieldPropertyDescriptor.<init>(FieldPropertyDescriptor.java:43)
at net.sf.dozer.util.mapping.propertydescriptor.PropertyDescriptorFactory.getPropertyDescriptor(PropertyDescriptorFactory.java:53)
at net.sf.dozer.util.mapping.fieldmap.FieldMap.getDestPropertyDescriptor(FieldMap.java:370)
at net.sf.dozer.util.mapping.fieldmap.FieldMap.getDestFieldType(FieldMap.java:103)
at net.sf.dozer.util.mapping.util.MappingsParser.processMappings(MappingsParser.java:95)
at net.sf.dozer.util.mapping.util.CustomMappingsLoader.load(CustomMappingsLoader.java:77)
at net.sf.dozer.util.mapping.DozerBeanMapper.loadCustomMappings(DozerBeanMapper.java:149)
at net.sf.dozer.util.mapping.DozerBeanMapper.getMappingProcessor(DozerBeanMapper.java:132)
at net.sf.dozer.util.mapping.DozerBeanMapper.map(DozerBeanMapper.java:94)
How can i map this so that it works?
This works for me. I am using 5.2.1 version
<mapping wildcard="true" >
<class-a>initRequest</class-a>
<class-b>initResponse</class-b>
<field>
<a>details</a>
<b is-accessible="true">detObj.details</b>
</field>
</mapping>
Note that "is-accessable" is not required for . Hope it helps
Problem solved...
is-accesible allows an object to be updated regardless of access modifier and presence of getters/setters (essential for objects generated using JAXB)
"dot" notation for deep mapping works to access nested objects
Combining the two is a feature that does not work in Dozer (maybe it does in a newer version)
solution...
modify the xsd such that the deep mapping is not required. This is not my ideal solution but its better than writing a custom converter for every object
In case of JaxB, use can download and use the plugin for generating the setters. Refer to this link for more details, https://jaxb2-commons.dev.java.net/collection-setter-injector/
I would guess that accessors (getter / setter) are missing.
By the way I think that you'll also need to provide an empty constructor for DetailsObject so dozer can instanciate it.
<b is-accessible="true">detObj.details</b>
Should be replaced with
<b is-accessible="true">DetailsObject.details</b>
While it does seem you cannnot use the "is-accessible" and dot notation together another approach is to break your deep mapping into smaller mappings.
We ran into this situation with JAX-WS generated code. You have lists that have no setter methods and in our case were deeply nested. We found our solution by simply breaking the large deep mapping into smaller mappings that "walked" our way to what we wanted. I tried to explain this in my blog here:
http://btarlton.blogspot.com/2014/08/dozer-deep-nestinga-different-approach.html
But the trick is just walking the object tree by smaller mappings and using is-accessible="true" when necessary to access the list with no setter and using "this" as the property name to keep passing the source along.
Hope this helps!
To summarize there are following options for this issue
1) Use JaxB pluggin to enable setters as discussed by Naveen
2) Use is-accessible for such properties
I believe using first approach unnecessarily exposes setters for collections/lists as you can risk of setting them with null.
We decided to enable is-accessible for such fields (and not to entire class) to avoid any side effects.
I have discussed the solution at Dozer Mapping Class level is-accessible

Categories

Resources