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
Related
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.
I'm trying to use DynamicEntity to unmarshal some simple JSON, and it's totally bombing on me. Docs are rather sparse, is it even possible to do this? I'm basically doing this;
JAXBContext jaxbContext = JAXBContext.newInstance(DynamicEntity.class);
DynamicEntity entity = (DynamicEntity) jaxbContext.createUnmarshaller().unmarshal(entityStream);
This is straight from the XML docs here: https://wiki.eclipse.org/EclipseLink/Examples/MOXy/Dynamic/XmlToDynamicEntity
And I get;
Caused by:
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
org.eclipse.persistence.dynamic.DynamicEntity is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
at org.eclipse.persistence.dynamic.DynamicEntity
Has anyone managed to get this to work? I'm basically trying to avoid building POJOs since my backend store doesnt care about them anyway, I just want to deserialize to a generic object and pass it along. In .NET I'd just use dynamic but I'm pretty stumped on how to do this with Moxy.
In order to get DynamicEntity, it is neccessary to use DynamicJAXBContext. It can be configured using the following in jaxb.properties file:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory
or you can use DynamicJAXBContextFactory directly.
Although Dynamic MOXY does not require any java classes for the bindings (the POJOs), you need to provide binding metadata when creating the context. It can be XSD or binding.xml that describes the mapping. So instead of creating the context using JAXBContext.newInstance(DynamicEntity.class), you would need to use alternative methods - see links below.
See example here (using XSD):
https://wiki.eclipse.org/EclipseLink/Examples/MOXy/Dynamic/JAXBContextFromXMLSchema
or more complex example using binding.xml and also JSON:
https://wiki.eclipse.org/EclipseLink/Examples/MOXy/Dynamic/Flickr
Does Dozer could call custom converter after default?
I want to create something like chain. At first I want to call default converter to make most of convertion work and only after that call custom converter to populate complex fields?
EDIT
by default when I create custom converter I need to override two methods. Each of this method has 2 arguments source object and target object. But when we call convertTo method second argument(target object) equals to null. So may be I need to specify something in mapping file to make dozer process default converter before custom?
Sorry for bad english
After look into source code I understand that this probably imposible. Instead of this dozer library propose using custom-converters at field level like this:
<mapping wildcard="false" >
<class-a>package.A</class-a>
<class-b>package.B</class-b>
<field>
<a>id</a>
<b>id</b>
</field>
<field custom-converter="test.AtoBNameFieldCustomConverter">
<a>name</a>
<b>name</b>
</field>
</mapping>
May be this help someone.
I am using hibernate reverse engineering and trying to get my Timestamps to map to a JodaTime type.
I have setup my hibernate.reveng.xml file properly
<sql-type jdbc-type="TIMESTAMP" hibernate-type="org.joda.time.contrib.hibernate.PersistentDateTime" not-null="true"></sql-type>
The issue is that when i run the rev-eng process my Java classes also get the members created as PersistentDateTime objects, but I don't want that because they are not usable. I need the java objects to be org.joda.time.DateTime
So I tried creating a custom engineering strategy
public class C3CustomRevEngStrategy extends DelegatingReverseEngineeringStrategy {
public C3CustomRevEngStrategy(ReverseEngineeringStrategy res) {
super(res);
}
public String columnToHibernateTypeName(TableIdentifier table, String columnName, int sqlType, int length, int precision, int scale, boolean nullable, boolean generatedIdentifier) {
if(sqlType==Types.TIMESTAMP) {
return "org.joda.time.DateTime";
} else {
return super.columnToHibernateTypeName(table, columnName, sqlType, length, precision, scale, nullable, generatedIdentifier);
}
}
}
My thought was that the hibernate mapping files would get the hibernate.reveng.xml file settings and the java objects would get the settings from the custom strategy file...but that was not the case. Both the mapping file and Object are of type "org.joda.time.DateTime" which is not what I want.
How can I achieve my goal? Also, I am NOT using annotations.
Hibernate 3.6
JodaTime 2.3
JodaTime-Hibernate 1.3
Thanks
EDIT: To clarify exactly what the issue is
After reverse engineering this is what I get in my mapping file and POJO class
<property name="timestamp" type="org.joda.time.contrib.hibernate.PersistentDateTime">
private PersistentDateTime timestamp;
As a POJO property, PersistentDateTime is useless to me as I cannot do anything with it such as time manipulations or anything. So this is what I want after my reverse engineering
<property name="timestamp" type="org.joda.time.contrib.hibernate.PersistentDateTime">
private org.joda.time.DateTime timestamp;
Using the Jidira library as suggested below gives me the same result, a POJO that I cannot use.
The JodaTime-Hibernate library is deprecated, and is probably the source of your problem. Don't dispair however as there is a (better) alternative.
You will need to use the JadiraTypes library to create the correct JodaTime objects from Hibernate. Add the library which can be found here to your project classpath and then change your type to org.jadira.usertype.dateandtime.joda.PersistantDateTime. All of the JodaTime objects have a corresponding mapping in that package, so if you decide to change to another object then just update your type.
This should ensure that your objects get created correctly.
I should add a caveat to my answer, which is that I have never used the JadiraTypes library with Hibernate 3. If it only supports Hibernate 4 (I don't see why it would, but...) let me know and I'll delete my answer.
The Hibernate Tools don't seem to separate Hibernate Types from the Java types. If you would be using annotations, this would be more clear as in that case you'd need an #Type annotation, which Hibernate will not generate at all. So using the exposed APIs won't help here.
Fortunately, Hibernate lets you plug into the actual code (or XML) generation after it does its processing. You can do that by replacing the Freemarker templates it uses to generate both XML and Java code. You'll need to use Ant for reverse engineering, however.
To start using Ant for this purpose (if you're not doing so already), you can either pull Hibernate Tools in as a build-time dependency using your dependency manager or download a JAR. Put the jar in Ant's classpath, but also extract the template files from it: since you're using XML configuration, you'll be interested in the /hbm directory. Then add the task using <taskdef> and, assuming that you extracted the templates to TPL_PATH/hbm/*.ftl, call it using <hibernatetool templatepath="TPL_PATH" ...>. (For more info, see below for a link to the docs). Using Ant also helps with automation, for example on CI servers where you won't have Eclipse.
You'll want to keep hibernate-type="org.joda.time.DateTime" in your hibernate.reveng.xml so that the Java files get generated correctly, but replace it with org.joda.time.contrib.hibernate.PersistentDateTime in the generated XML. To do that, edit TPL_PATH/hbm/property.hbm.ftl, replace ${property.value.typeName} with ${javaType}, and assign javaType to the right value before it's used:
<#assign javaType=property.value.typeName>
<#if javaType.equals("DateTime")>
<#assign javaType="org.jadira.usertype.dateandtime.joda.PersistentDateTime">
</#if>
<property
name="${property.name}"
type="${javaType}"
...
You might want to remove newlines to keep the generated XML clean.
This is all described in the Hibernate Tools documentation at http://docs.jboss.org/tools/archive/3.2.1.GA/en/hibernatetools/html/codegen.html#d0e6349 - except that the documentation doesn't tell you exactly which templates you need to modify, you need to figure that out by reading the templates.
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