dozer
Dozer is a Java Bean to Java Bean mapper that recursively copies data from one object to another.
Dozer -
Dozer
I am trying to figure out an easy way to map DTOs to entities without the boiler-plate code. While I was thinking of using dozer it appears to require a lot of xml configuration. Has anybody seen a dozer alternative that uses a DSL to configure the bean mapping in pure Java?
Ideally I am hoping to find a bean mapper that is inspired by the way Guice does things.
Source: (StackOverflow)
I'm currently using Dozer for mapping Entity
objects to Dto
objects in my project.
My question is how to limit the levels or the depth of internal mappings?
For example I have a AccountProfile
entity which has a List<AccountProfileDetail>
entity as a member. Moreover AccountProfileDetail
itself has a FinancialTransLimit
entity as a member.
Now I want to tell the mapper that for example do the mappings only with depth = 2
. So the FinancialTransLimit
member doesn't get copied to the AccountProfileDetail
member of destination object.
I need to specify the depth using Programming API not in xml. However, I didn't find it in the xml configurations, too.
I've tried Orika too, but I couldn't find such feature in Orika too!
Both of the following codes (for testing with Dozer and Orika as an alternative) work fine and do a deep copy. I need to limit the depth for at least one of them.
Could anyone help me with this, please?
Many thanks!
Sample Code:
AccountProfile
//My Entities:
import java.util.List;
public class AccountProfile{
private Long id;
private String name;
private List<AccountProfileDetail> accountProfileDetails;
public AccountProfile() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public List<AccountProfileDetail> getAccountProfileDetails() {
return this.accountProfileDetails;
}
public void setAccountProfileDetails(List<AccountProfileDetail> accountProfileDetails) {
this.accountProfileDetails = accountProfileDetails;
}
}
AccountProfileDetail
import java.math.BigDecimal;
public class AccountProfileDetail {
private Long id;
private BigDecimal accountMinBalance;
private AccountProfile accountProfile;
private FinancialTransLimit financialTransLimit;
public AccountProfileDetail() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public BigDecimal getAccountMinBalance() {
return this.accountMinBalance;
}
public void setAccountMinBalance(BigDecimal accountMinBalance) {
this.accountMinBalance = accountMinBalance;
}
public AccountProfile getAccountProfile() {
return this.accountProfile;
}
public void setAccountProfile(AccountProfile accountProfile) {
this.accountProfile = accountProfile;
}
public FinancialTransLimit getFinancialTransLimit() {
return this.financialTransLimit;
}
public void setFinancialTransLimit(FinancialTransLimit financialTransLimit) {
this.financialTransLimit = financialTransLimit;
}
}
FinancialTransLimit
public class FinancialTransLimit{
private Long id;
private String limitCode;
public FinancialTransLimit() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getLimitCode() {
return this.limitCode;
}
public void setLimitCode(String limitCode) {
this.limitCode = limitCode;
}
}
AccountProfileDto
// My Dtos:
import java.util.List;
public class AccountProfileDto{
private Long id;
private String name;
private List<AccountProfileDetailDto> accountProfileDetails;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<AccountProfileDetailDto> getAccountProfileDetails() {
return accountProfileDetails;
}
public void setAccountProfileDetails(List<AccountProfileDetailDto> accountProfileDetails) {
this.accountProfileDetails = accountProfileDetails;
}
}
AccountProfileDetailDto
import java.math.BigDecimal;
public class AccountProfileDetailDto {
private Long id;
private BigDecimal accountMinBalance;
private AccountProfileDto accountProfile;
private FinancialTransLimitDto financialTransLimit;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public BigDecimal getAccountMinBalance() {
return accountMinBalance;
}
public void setAccountMinBalance(BigDecimal accountMinBalance) {
this.accountMinBalance = accountMinBalance;
}
public AccountProfileDto getAccountProfile() {
return accountProfile;
}
public void setAccountProfile(AccountProfileDto accountProfile) {
this.accountProfile = accountProfile;
}
public FinancialTransLimitDto getFinancialTransLimit() {
return financialTransLimit;
}
public void setFinancialTransLimit(FinancialTransLimitDto financialTransLimit) {
this.financialTransLimit = financialTransLimit;
}
}
FinancialTransLimitDto
public class FinancialTransLimitDto {
private Long id;
private String limitCode;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getLimitCode() {
return limitCode;
}
public void setLimitCode(String limitCode) {
this.limitCode = limitCode;
}
}
And now the test case code with Dozer:
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;
public class TestDozer {
public static void main(String[] args) {
List<AccountProfile> profiles = createList();
Mapper mapper = new DozerBeanMapper();
List<AccountProfileDto> profileDtos = new ArrayList<AccountProfileDto>();
for (AccountProfile entity: profiles) {
AccountProfileDto dto = new AccountProfileDto();
mapper.map(entity, dto);
profileDtos.add(dto);
}
System.out.println(Arrays.deepToString(profileDtos.toArray()));
}
private static List<AccountProfile> createList(){
List<AccountProfile> accountProfiles = new ArrayList<AccountProfile>();
AccountProfile ap1 = new AccountProfile();
ap1.setId(new Long(1000));
ap1.setName("profile1");
FinancialTransLimit ftlt1 = new FinancialTransLimit();
ftlt1.setId(new Long(3000));
ftlt1.setLimitCode("L1");
AccountProfileDetail apd1 = new AccountProfileDetail();
apd1.setId(new Long(2000));
apd1.setAccountProfile(ap1);
apd1.setAccountMinBalance(new BigDecimal(100000));
apd1.setFinancialTransLimit(ftlt1);
List<AccountProfileDetail> apds1 = new ArrayList<AccountProfileDetail>();
apds1.add(apd1);
ap1.setAccountProfileDetails(apds1);
accountProfiles.add(ap1);
//
AccountProfile ap2 = new AccountProfile();
ap2.setId(new Long(1001));
ap2.setName("profile2");
FinancialTransLimit ftlt2 = new FinancialTransLimit();
ftlt2.setId(new Long(3001));
ftlt2.setLimitCode("L2");
AccountProfileDetail apd2 = new AccountProfileDetail();
apd2.setId(new Long(2001));
apd2.setAccountProfile(ap2);
apd2.setAccountMinBalance(new BigDecimal(200000));
apd2.setFinancialTransLimit(ftlt2);
List<AccountProfileDetail> apds2 = new ArrayList<AccountProfileDetail>();
apds2.add(apd2);
ap2.setAccountProfileDetails(apds2);
accountProfiles.add(ap2);
//
return accountProfiles;
}
}
Test code with Orika:
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import ma.glasnost.orika.BoundMapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
public class TestOrika {
public static void main(String[] args) {
List<AccountProfile> profiles = createList();
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
BoundMapperFacade<AccountProfile, AccountProfileDto> mapper = mapperFactory.getMapperFacade(AccountProfile.class, AccountProfileDto.class);
List<AccountProfileDto> profileDtos = new ArrayList<AccountProfileDto>();
for (AccountProfile entity: profiles) {
AccountProfileDto dto = new AccountProfileDto();
mapper.map(entity, dto);
profileDtos.add(dto);
}
System.out.println(Arrays.deepToString(profileDtos.toArray()));
}
private static List<AccountProfile> createList(){
List<AccountProfile> accountProfiles = new ArrayList<AccountProfile>();
AccountProfile ap1 = new AccountProfile();
ap1.setId(new Long(1000));
ap1.setName("profile1");
FinancialTransLimit ftlt1 = new FinancialTransLimit();
ftlt1.setId(new Long(3000));
ftlt1.setLimitCode("L1");
AccountProfileDetail apd1 = new AccountProfileDetail();
apd1.setId(new Long(2000));
apd1.setAccountProfile(ap1);
apd1.setAccountMinBalance(new BigDecimal(100000));
apd1.setFinancialTransLimit(ftlt1);
List<AccountProfileDetail> apds1 = new ArrayList<AccountProfileDetail>();
apds1.add(apd1);
ap1.setAccountProfileDetails(apds1);
accountProfiles.add(ap1);
//
AccountProfile ap2 = new AccountProfile();
ap2.setId(new Long(1001));
ap2.setName("profile2");
FinancialTransLimit ftlt2 = new FinancialTransLimit();
ftlt2.setId(new Long(3001));
ftlt2.setLimitCode("L2");
AccountProfileDetail apd2 = new AccountProfileDetail();
apd2.setId(new Long(2001));
apd2.setAccountProfile(ap2);
apd2.setAccountMinBalance(new BigDecimal(200000));
apd2.setFinancialTransLimit(ftlt2);
List<AccountProfileDetail> apds2 = new ArrayList<AccountProfileDetail>();
apds2.add(apd2);
ap2.setAccountProfileDetails(apds2);
accountProfiles.add(ap2);
//
return accountProfiles;
}
}
Source: (StackOverflow)
I'd like to do something like:
ArrayList<CustomObject> objects = new ArrayList<CustomObject>();
...
DozerBeanMapper MAPPER = new DozerBeanMapper();
...
ArrayList<NewObject> newObjects = MAPPER.map(objects, ...);
Assuming:
<mapping>
<class-a>com.me.CustomObject</class-a>
<class-b>com.me.NewObject</class-b>
<field>
<a>id</a>
<b>id2</b>
</field>
</mapping>
I tried :
ArrayList<NewObject> holder = new ArrayList<NewObject>();
MAPPER.map(objects, holder);
but the holder object is empty. I also played with changing the second argument without any luck...
Source: (StackOverflow)
I have such enum:
public enum PartnershipIndicator {
VENDOR("VENDOR"), COPARTNER("COPARTNER"), BUYER("BUYER");
String code;
private PartnershipIndicator(String code) {
this.code = code;
}
public String getCode() {
return code;
}
public static PartnershipIndicator valueOfCode(String code) {
for (PartnershipIndicator status : values()) {
if (status.getCode().equals(code)) {
return status;
}
}
throw new IllegalArgumentException(
"Partnership status cannot be resolved for code " + code);
}
@Override
public String toString() {
return code;
}
}
I need to convert it to String and vice versa. Now, it is done by custom converter. But i want to do it via dozer mappings (if it is possible). If i do not write any mappings to the dozer confing, i get
org.dozer.MappingException: java.lang.NoSuchMethodException: by.dev.madhead.demo.test_java.model.PartnershipIndicator.<init>()
exception. I cannot add default public constructor to enum, as it is not possible. So, i wrote a trick with internal code and valueOfCode() / toString(). It does not work. Then, i've mapped it in dozer config:
<mapping>
<class-a>java.lang.String</class-a>
<class-b create-method="valueOfCode">by.dev.madhead.demo.test_java.model.PartnershipIndicator</class-b>
</mapping>
It does not work. I tried valueOfCode(), one-way mappings. Nothing works. Enum to String conversion does not work too, i get empty Strings.
Any ideas?
Source: (StackOverflow)
I am using Spring transactions so the transaction is still active when POJO to DTO conversion occurs.
I would like to prevent Dozer from triggering lazy loading, so that hidden sql queries never occur : all fetching has to be done explicitly via HQL (to get the best control on performances).
Is it a good practice (I can't find it documented anywhere) ?
How to do it safely ?
I tried this before DTO conversion :
PlatformTransactionManager tm = (PlatformTransactionManager) SingletonFactoryProvider.getSingletonFactory().getSingleton("transactionManager");
tm.commit(tm.getTransaction(new DefaultTransactionDefinition()));
I don't know what happens to the transaction, but the Hibernate session doesn't get closed, and the lazy loading still occurs.
I tried this :
SessionFactory sf = (SessionFactory) SingletonFactoryProvider.getSingletonFactory().getSingleton("sessionFactory");
sf.getCurrentSession().clear();
sf.getCurrentSession().close();
And it prevents lazy loading, but is it a good practice to manipulate session directly in the application layer (which is called "facade" in my project) ? Which negative side effects should I fear ? (I've already seen that tests involving POJO -> DTO conversions could no more be launched through AbstractTransactionnalDatasource Spring test classes, because this classes try to trigger a rollback on a transaction which is no more linked to an active session).
I've also tried to set propagation to NOT_SUPPORTED or REQUIRES_NEW, but it reuse the current Hibernate session, and doesn't prevent lazy loading.
Source: (StackOverflow)
I created a dozer mapping for ClassA to ClassB.
Now I want to map a List<ClassA>
to a List<ClassB>
.
Is it possible to just
mapper.map(variableListClassA, variableListClassB)
or do I have to go over a loop, e.g.
for (ClassA classA : variableListClassA) {
variableListClassB.add(mapper.map(classA, ClassB.class))
}
Source: (StackOverflow)
I have to map a complex structure of Java classes which don't expose their fields through set-/get-methods in general (this is given and can't be changed).
So mapping can only be performed on a direct field access. Dozer allows individual fields to be made accessible but I haven't found a setting to make this the general behaviour. As a result I wouldn't have to map each field explicitly just for making it accessible!
Does this option exist?
- On a class level?
- On a global level?
Source: (StackOverflow)
does anybody know how to put a constant value into an attribute with dozer? I haven't seen anything about that in the dozer's documentation
Source: (StackOverflow)
I am using Dozer to map between a Document class to DocumentManagementBean class, both of my own making. Both have a property, with getters and setters, of Joda DateTime type, called dateAdded.
When Document object d
has property dateAdded
=x, calling mapper.map(d, DocumentManagementBean.class)
all fields get auto-mapped correctly (since I have full control over code base I am able to get away with no dozer-config and rely simply on matching property names), EXCEPT the dateAdded
field, where the new DocumentManagementBean dmb
ends up with the current DateTime in its dateAdded
property, instead of x from the d
object.
I am expecting Dozer to try to call
dmb.setDateAdded(d.getDateAdded());
and just bring the value of dateAdded from source to target, but it seems to be creating new DateTime for dmb object an then leaving it alone.
Can anyone shed some light on this for me please?
Source: (StackOverflow)
It appears that Dozer will not map a Boolean property if the accessor of that property is defined as isProperty()
rather than getProperty()
.
The following groovy script illustrates the problem:
import org.dozer.*
class ProductCommand {
Boolean foo
}
public class ProductDto {
private Boolean foo;
public Boolean isFoo() { this.foo }
public void setFoo(Boolean p0) { this.foo = p0 }
}
def mapper = new DozerBeanMapper()
dto = new ProductDto(foo: true)
assert dto.isFoo()
ProductCommand mappedCmd = mapper.map(dto, ProductCommand)
assert mappedCmd.foo
The assertion on the final line fails. However, if I rename ProductDto.isFoo()
to ProductDto.getFoo()
it passes.
Is there a flag/option I can set in the Dozer mapping file that will instruct it to use either an is
or get
accessor for boolean properties? Alternatively, I could add a custom rule for every boolean property, but this is not very appealing.
Although the example above is written in Groovy, I've no reason to believe the same behaviour wouldn't be exhibited by the equivalent Java code.
These DTOs are generated by JAXB (which generates an "is" accessor, rather than a "get" accessor for booleans), so I can't rename the accessors. I'm using Dozer 5.3.2.
Source: (StackOverflow)
I am getting the following error, while running my following code:
java.lang.ClassNotFoundException: org.apache.commons.lang.StringUtils from BaseClassLoader
at org.jboss.classloader.spi.base.BaseClassLoader.loadClass(BaseClassLoader.java:448)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at org.dozer.util.ResourceLoader.getResource(ResourceLoader.java:53)
at org.dozer.util.DefaultClassLoader.loadResource(DefaultClassLoader.java:44)
at org.dozer.config.GlobalSettings.loadGlobalSettings(GlobalSettings.java:116)
at org.dozer.config.GlobalSettings.<init>(GlobalSettings.java:67)
at org.dozer.config.GlobalSettings.<clinit>(GlobalSettings.java:46)
at org.dozer.stats.StatisticsManagerImpl.<init>(StatisticsManagerImpl.java:39)
at org.dozer.stats.GlobalStatistics.<init>(GlobalStatistics.java:29)
at org.dozer.stats.GlobalStatistics.<clinit>(GlobalStatistics.java:24)
at org.dozer.DozerBeanMapper.<clinit>(DozerBeanMapper.java:59)
Kindly, guide me to fix the problems.
Regards.
Source: (StackOverflow)
With my data model, which is basically a tree with parents children, Dozer is having issues successfully mapping them as it interprets a field (which uses an interface-type as a parameter) as being a class, and trying to instantiate it with a constructor. This results in the following exception;
ERROR [MappingProcessor] - Field mapping error -->
MapId: null
Type: null
Source parent class: com.*.shared.model.Module
Source field name: parent
Source field type: class com.*.shared.model.Datawarehouse
Source field value: com.*.shared.model.Datawarehouse@706ce458
Dest parent class: com.*.shared.model.Module
Dest field name: parent
Dest field type: com.*.shared.model.Model
org.dozer.MappingException: java.lang.NoSuchMethodException: com.*.shared.model.Model.<init>()
This is a same-class mapping, and Whilst Dozer correctly identifies the parent field on the source class as being of type Datawarehouse, because the set method on the Module class for its parent uses the Model interface as its parameter, it seems to be attempting to instantiate the type of Model, which of course fails as Model is an interface with no constructor, rather than Datawarehouse, as the source class field indicates.
I know about using bean-factories to alter the standard mapping behaviour, but I'm surprised that this would be the only way to resolve this issue. It seems to me that Dozer already has the information it needs since it identifies the source class type, and unusual to me that it would try to instantiate the interface specified by the setter's signature rather than the type it is attempting to map over.
Any suggestions?
Source: (StackOverflow)
I need to map class A into class C using dozer framework.
public class A {
private String fielda1;
private String fielda2;
public String getFielda1() {
return fielda1;
}
public void setFielda1(String fielda1) {
this.fielda1 = fielda1;
}
public String getFielda2() {
return fielda2;
}
public void setFielda2(String fielda2) {
this.fielda2 = fielda2;
}
}
public class B {
private List<C> cList;
public List<C> getcList() {
return cList;
}
public void setcList(List<C> cList) {
this.cList = cList;
}
public static class C {
private String fieldc1;
private String fieldc2;
public String getFieldc1() {
return fieldc1;
}
public void setFieldc1(String fieldc1) {
this.fieldc1 = fieldc1;
}
public String getFieldc2() {
return fieldc2;
}
public void setFieldc2(String fieldc2) {
this.fieldc2 = fieldc2;
}
}
}
XML mapping file:
<mapping wildcard="false" map-null="false" map-id="test">
<class-a>test.A</class-a>
<class-b>test.B.C</class-b>
<field>
<a>fielda1</a>
<b>fieldc1</b>
</field>
<field>
<a>fielda1</a>
<b>fieldc2</b>
</field>
</mapping>
When i try to map these classes i got following exception:
org.dozer.MappingException: java.lang.ClassNotFoundException: test.B.C
at org.dozer.util.MappingUtils.throwMappingException(MappingUtils.java:88)
at org.dozer.util.DefaultClassLoader.loadClass(DefaultClassLoader.java:33)
It seams that dozer is not capable to handle this situation and uses class B as a package name. This issue can be resolved using custom converters. I just want to know is there any trick that could be used to convert these classes using just XML configuration ?
Source: (StackOverflow)
I have this question. But it will be difficult for me to explain as I don't know exact terms to use. Hope someone will understand. I'll try to discribe to the best i can. I feel like this is much related to parsing
Say there are two classes. And in both classes I have some variables, say strings (just for simplicity, variable type can be any), which have similar names.
Eg:
class ClassA{
String x,y,z;
}
class ClassB{
String x,y,z;
}
Now, what i need is, i need to copy the value of one class's variable values to other classes corresponding variable.
Eg:
ClassA aa=new ClassA();
ClassB bb=new ClassB();
//set bb's variables
aa.x=bb.x;
aa.y=bb.y;
aa.z=bb.z;
like that.
But please note that what i need is not the above method. I hope there will be a way to write a simple method, so that it will identify the relevent variable by the name passed to it. Then it will do the value assignment accordingly.
My imagined method is like this,
void assign(String val){
// aa.<val>=val
}
For example if you pass bb.x
to assign(...)
method, then it will do aa.x=bb.x
assignment.
Hope this is clear enough. There must be a better way to explain this. If someone know it please edit the post(+title) to make it more clear (But save my idea)..
Please let me know if there's a way to achieve this.
Thanks!
Source: (StackOverflow)
I'm struggling to get Dozer to bend to my will for something that I feel should be quite simple. I have two similar models that I wish to map between, however one has a 'deeper' hierarchy than the other and this is causing me problems when dealing with collections. Consider the following classes:
Source classes:
class Foo {
String id;
NameGroup nameGroup;
// Setters/Getters
}
class NameGroup {
private List<Name> names;
// Setters/Getters
}
class Name {
private String nameValue;
// Setters/Getters
}
Destination classes:
class Bar {
private String barId;
private BarNames barNames;
// Setters/Getters
}
class BarNames {
private List<String> names;
// Setters/Getters
}
Now I'd like the following one-way mappings:
Foo.id -> Bar.barId // Simple enough
But I then need:
Foo.nameGroup.names.nameValue -> Bar.barNames.names
So each Name
instance in Foo.nameGroup.names
should result in a String
being added to the BarNames.names
list. Is this possible?
Source: (StackOverflow)