Dozer Mapping Confusion - java

I ve a confusion regarding how the dozer maps the source object to destination object. I have the following scenario:
Source Object:
public class Rule {
private String id;
private String name;
private String group;
private String content;
private RuleType ruleType;
private String drlContent;
private boolean enabled;
private Strategy strategy;
// getters and setters
}
Destination Object:
public class RuleActivity {
private String id;
private String name;
private Strategy strategy;
// getters and setters
}
XML Mapping:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<stop-on-errors>true</stop-on-errors>
<date-format>MM/dd/yyyy HH:mm</date-format>
</configuration>
<mapping wildcard="false">
<class-a>com.magick.models.shared.Rule</class-a>
<class-b>com.magick.models.shared.log.RuleActivity</class-b>
<field>
<a>id</a>
<b>ruleId</b>
</field>
<field>
<a>strategy.name</a>
<b>strategy.name</b>
</field>
<field>
<a>name</a>
<b>name</b>
</field>
</mapping>
Now How these would be mapped ? I mean , does the destination Object contains the Complete Strategy Object or only the strategy.name field of it.

First of all, by default dozer mappings are bi-directional. So,
mapping from class-a to class-b and vice-versa is permitted.
As you have done your mapping as follows:
<field>
<a>strategy.name</a>
<b>strategy.name</b>
</field>
If the source object is having a Strategy object which is not null and have all the relevant field's value. Then dozer will create a new Strategy object for destination as well and will only populate the name field of newly created Strategy object.
Further, dozer also works on retrospection so suppose the name and type of all fields of Strategy object in source and destination is same. Dozer will map or copy all the fields automatically. So you don't have to map each field individually. you just have to write as below.
<field>
<a>strategy</a>
<b>strategy</b>
</field>
But if your field names or type is not same, you need to define mapping for each field as you did for id field for Rule class and ruleId field for RuleActivity class.
<field>
<a>id</a>
<b>ruleId</b>
</field>
Hope this clarifies your doubts.

Related

Parent - Child relationship - self join mapping

I'm trying to build an application which will receive the XML file with list of Employees and store the parent-child/employee-manager relation in the single database table.
My XML file looks like this one:
<Employees>
<Employee manager="Patrick">Martin</Employee>
<Employee manager="Patrick">Kent</Employee>
<Employee manager="Martin">Mark</Employee>
<Employee>Hugo</Employee> <!-- root element of the employee-manager tree -->
<Employee manager="Hugo">Osa</Employee>
<Employee manager="Osa">Patrick</Employee>
</Employee>
One employee can have only one manager, but one manager can have multiple subordinates/employees.
I have no troubles when unmarshalling the received XML file but now I'm trying to create the appropriate model which will allow me to store the unmarshalled values in the database. Data should be stored in the table named "Employee" and should contain following data:
------------------------------
| id | Integer |
------------------------------
| employee_name | String |
------------------------------
| parent_id | Integer | -- reference to the manager
------------------------------
I created a new class named Employee but I'm not sure how to define appropriate ManyToOne/OneToMany annotations.
Since I'm fairly new to this, I've Googled couple of examples and tutorials (as well as the answers on the similar questions here on Stack Overflow), but I guess I'm making some big mistake in this implementation when defining this model. My latest try looks like this:
public class Employee {
#Id
#GeneratedValue
private int id;
#Column(name = "parent_id")
#Transient
#ManyToOne(cascade={CascadeType.ALL})
private String managerName;
#Column(name = "employee_name")
#JoinColumn(name="parent_id")
private String employeeName;
// getters and setters
If anyone could point me in the the direction of defining appropriate model, it would be much, much appreciated!
In Hibernate when you want to map a ManyToOne relationship you map it between entities and not just properties, so you need to reference an object of type Employee and not only a String or an id.
Problems:
So your mapping is incorrect and will throw many mapping errors,
instead of writing:
#Column(name = "parent_id")
#Transient
#ManyToOne(cascade={CascadeType.ALL})
private String managerName;
You need to map the ManyToOne realtionship like this:
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name="manager_id")
private Employee manager;
And make sure you map the other side of the relationship like this:
#OneToMany(mappedBy="manager")
private Set<Employee> subordinates = new HashSet<Employee>();
Also your mapping for the column employee_name is incorrect, the
#JoinColumn is only used for relationships and can't be used with a
simple column, you need to write it like this:
#Column(name = "employee_name")
private String employeeName;
The #Transient is useless in your mapping, we only use it if we
want to use an attribute that won't be persisted in the database.
And most important make sure you map your class with #Entity, so it can be
persisted in the database.
Example:
You can check Hibernate Self Join Annotations One To Many mapping example it uses the same model you want to implement.
You should simply have a ManyToOne relation to your Employee table, that is several employees can have the same manager (who is also an employee) and for the manager this field will remain empty, like this:
#Entity
#Table(name = "EMPLOYEE")
public class Employee {
#Id
#GeneratedValue
private int id;
#ManyToOne
private Employee manager;
#Column(name = "employee_name")
private String employeeName;

Dozer - From List of entities to list of entities' id

I have a domain object called User:
public class User {
private long id;
private String username;
private String email;
private List<Profile> profiles;
// getters & setters
}
And I have the related DTO (UserDTO) which is
public class UserDTO {
private long id;
private String username;
private String email;
private List<Long> profilesId;
// getters & setters
}
I'd like to use Dozer to convert from domain object to DTO. The Profile class has a property
Long id;
What I want is that Dozer takes the profile's id for each profile in the list and save it in the DTO's list. Can I do something like that? Do I have to use custom converters?
Here's my actual mapping file
<mapping>
<class-a>common.model.User</class-a>
<class-b>common.model.dto.UserDTO</class-b>
<field>
<a>legalEntity.id</a>
<b>legalEntityId</b>
</field>
<field type="one-way">
<a>profiles.id</a>
<b>profilesId</b>
</field>
</mapping>
Solved
just add to the source class this method
public List<Long> getProfilesId() {
List<Long> profilesId = new ArrayList<Long>();
for(Profile p : this.profiles) {
profilesId.add(p.getId());
}
return profilesId;
}
and to the mapping file
<field type="one-way">
<a get-method="getProfilesId">profiles</a>
<b>profilesId</b>
</field>
which says Dozer which method use to make the conversion.

Hibernate + Dozer - Using map-id on mapped collection items property

I have two hibernate entities:
#Entity
#Table(name = DBConstants.TABLE_PARTNER)
public class Partner extends XWeedEntity {
private static final long serialVersionUID = 5692151244956513381L;
#Id
#Column(name = DBConstants.PARTNER_COL_PARTNER_NUMBER)
private Integer partnerNumber;
#OneToMany(mappedBy = DBConstants.VISIT_PROP_VISITOR)
private List<Visit> visits;
// More fields and properties...
}
#Entity
#Table(name = DBConstants.TABLE_VISIT)
public class Visit extends XWeedEntity {
private static final long serialVersionUID = -8324746049334117579L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = DBConstants.VISIT_COL_ID)
private Integer id;
#ManyToOne
#JoinColumn(name = DBConstants.VISIT_COL_VISITOR, nullable = false)
private Partner visitor;
// More fields and properties...
}
And two DTO entities:
public class PartnerDto extends XWeedEntity {
private static final long serialVersionUID = 5692151244956513381L;
private Integer partnerNumber;
private List<VisitDto> visits;
// More fields and properties...
}
public class VisitDto extends XWeedEntity {
private static final long serialVersionUID = -8324746049334117579L;
private Integer id;
private PartnerDto visitor;
// More fields and properties...
}
And I've got the following dozer mappings:
<mapping map-id="partnerWithCollections" map-empty-string="false" map-null="false">
<class-a>org.xweed.model.app.domain.dbo.Partner</class-a>
<class-b>org.xweed.model.app.domain.dto.PartnerDto</class-b>
<field map-id="visitWithPartner">
<a>visits</a>
<b>visits</b>
</field>
</mapping>
<mapping map-id="partnerBasic" wildcard="false" map-empty-string="false" map-null="false">
<class-a>org.xweed.model.app.domain.dbo.Partner</class-a>
<class-b>org.xweed.model.app.domain.dto.PartnerDto</class-b>
<field>
<a>partnerNumber</a>
<b>partnerNumber</b>
</field>
</mapping>
<mapping map-id="visitWithPartner" map-empty-string="false" map-null="false">
<class-a>org.xweed.model.app.domain.dbo.Visit</class-a>
<class-b>org.xweed.model.app.domain.dto.VisitDto</class-b>
<field map-id="partnerBasic">
<a>visitor</a>
<b>visitor</b>
</field>
</mapping>
The problem is that when I call dozer using "partnerWithCollections" mapping, dozer is mapping all Visit objects from the Partner visits, but every single visit has it's visitor with it's visits collection and so on, when the visitor attribute of each visit should only contain the partnerNumber.
If I try to exclude visitor field from visit, then works, and each visitor's visit is null, but for some reason it is not working using map-id to use some concrete Partner mapping.
Any ideas?
Thanks in advance.
This happens because by default, dozer always maps properties with same name:
Partner.visits
PartnerDto.visits
You can disable this setting the <mapping> atribute "wildcard=false".
From de oficial documentation:
Does Dozer automatically map fields with matching property names?
Yes. All fields with matching property names are implicitly mapped. It would be atypical usage, but you could suppress this behavior by setting wilcard="false".
http://dozer.sourceforge.net/documentation/faq.html#auto-property-name
You also can do that to all mappings, using the global configuration:
<configuration>
<wildcard>false</wildcard>
</configuration>
http://dozer.sourceforge.net/documentation/globalConfiguration.html

Hibernate generated select statement has two ids, entity id value populated with a null on load

We have Hibernate Interceptor (extending EmptyInterceptor) that loads Spring classes on instantiate based on the incoming entityName:
#Override
public Object instantiate(String entityName, EntityMode entityMode, Serializable id) {
Object bean = null;
String className = entityName.substring(entityName.lastIndexOf(".") + 1);
StringBuffer entity = new StringBuffer(className.substring(0, 1).toLowerCase());
entity.append(className.substring(1));
String beanName = entity.toString();
// Place any modified bean names here
if ("policyType".equalsIgnoreCase(entity.toString())) {
beanName = "policyTypeEntity";
}
if (this.applicationContext.containsBean(beanName)) {
bean = this.applicationContext.getBean(beanName);
}
return bean;
}
Based on this setup, when a createCriteria query is run,
this.policyInfo = (PolicyInfo) session.createCriteria(PolicyInfo.class).createAlias("quote", "q").add(Restrictions.eq("q.id", quoteId)).uniqueResult();
Hibernate is generating all SQL (abridged) as below (This is just one of the sub queries that is eagerly initialized):
/* load one-to-many com.ipacc.onelink.model.entitybeans.PolicyInfo.persons */ select
persons0_.POLICY_INFO_ID as POLICY_I5_35_1_,
persons0_.ID as ID1_27_1_,
persons0_.ID as ID1_27_0_,
persons0_.WORK_ADDRESS_ID as WORK_ADD2_27_0_,
persons0_.HOME_ADDRESS_ID as HOME_ADD3_27_0_,
persons0_.MAIL_ADDRESS_ID as MAIL_ADD4_27_0_,
persons0_.POLICY_INFO_ID as POLICY_I5_27_0_,
persons0_.HOMEOWNER_VERIFIED as HOMEOWN26_27_0_
from
COMBO21_OWNER.PERSON_INFO persons0_
where
persons0_.POLICY_INFO_ID=?
If you notice, the ID column is repeated twice, resulting in the actual class property being set to null.
Here's how the beginning of PersonInfo entity looks like:
package com.ipacc.onelink.model.entitybeans;
import javax.persistence.Transient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#SuppressWarnings("serial")
#Component
#Scope("prototype")
public class PersonInfo extends DomainObject implements Comparable<PersonInfo> {
private Address workAddress;
private Address homeAddress;
private Address mailAddress;
private PolicyInfo policyInfo;
private String firstName;
private String lastName;
private String middleName;
private String titlePrefix;
private String priorLastName;
private String ssn;
private Date birthDate;
private String ethnicGroup;
private String language;
and so on...
This inherits the DomainObject which looks like below:
package com.ipacc.onelink.model;
import java.io.Serializable;
#SuppressWarnings("serial")
public class DomainObject implements Serializable {
protected Integer id;
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
}
Adding the abridged mapping file:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ipacc.onelink.model.entitybeans.PersonInfo" table="PERSON_INFO" schema="COMBO21_OWNER" dynamic-update="true" select-before-update="true">
<id name="id" type="integer">
<column name="ID" precision="10" scale="0" />
<generator class="sequence">
<param name="sequence">PERSON_INFO_SEQ</param>
</generator>
</id>
<many-to-one name="workAddress" class="com.ipacc.onelink.model.entitybeans.Address" fetch="select"
cascade="all">
<column name="WORK_ADDRESS_ID" precision="10" scale="0" />
</many-to-one>
Any ideas as to why this is happening?
Thanks
Update:
I flattened the classes to push down the id column and removed the DomainObject as mentioned above but have still not made any progress. So we can rule out an issue with the the Hibernate inheritance mapping strategy (as I do not use an ancestor class any more).
I also tried this on Hibernate 4.2.7.SP1, so I can confirm it was an issue in previous revision too. I do not believe this is an Hibernate issue, but an issue with the handshake between Spring and Hibernate when using the instantiate interceptor.
Here's the duplicate IDs I am getting:
Hibernate:
/* load one-to-many com.ipacc.onelink.model.entitybeans.PolicyInfo.installments */ select
installmen0_.POLICY_INFO_ID as POLICY_I2_35_1_,
installmen0_.ID as ID1_18_1_,
installmen0_.ID as ID1_18_0_,
installmen0_.POLICY_INFO_ID as POLICY_I2_18_0_,
Hibernate:
/* load one-to-many com.ipacc.onelink.model.entitybeans.PolicyInfo.policyQuestionAnswers */ select
policyques0_.POLICY_INFO_ID as POLICY_I2_35_2_,
policyques0_.ID as ID1_37_2_,
policyques0_.ID as ID1_37_1_,
Has anyone used Hibernate EmptyInterceptor's instantiate method to instantiate Spring beans and had success?
I think it's a mapping problem within your PersonInfo class.
You have 3 different address associations. This is in my point of view a database design issue. The foreign key assocation should be in this case managed by the Address class or entity. Check how this association is implemented.
Additionally PersonInfo has an association to its own. Recusrive dependency.
public class PersonInfo extends DomainObject implements Comparable<PersonInfo> {
private Address workAddress;
private Address homeAddress;
private Address mailAddress;
private PolicyInfo policyInfo;
So check if the mapping could be a problem and if not check if Spring is able to resolve
that kind of recursive dependencies with interceptor mechanism. I don't know but this could be a problem.
Try to simplify your PersonInfo mapping and check if it works than in proper way with Spring and the Interceptor mechanism.
I think i have a possible answer. You don't provide an inheritence strategy for your
DomainObject and PersonInfo association.
Check for Inheritance Strategies and their requironments. Seems that your PersonInfo class
needs in the case of default inheritance strategy an additionally Id property.
Following strategies exist
Table per Class Hierarchy
Table per Class
Table per concrete Class
I think your mapping does not provide any inheritance strategy definitions.
Additionally you can do that kind of inheritance with annotation based mapping.
But you use xml mappings and there it seems to me that you don't define that association.
Additionally i think you try to resolve this inheritance dependency with the recursive dependency to a PersonInfo reference. But this is just an assumption.
So this should be the reaseon why there are two ids. One id for the DomainObject Table and one id for the PersonInfo table. Check if you have an DomainObject with a foreignkey constraint to PersonInfo or check your inheritance strategy.

Dozer Mapping between primitive datatype and Custom object?

I have the following scenario :
Class A{
private List<Long> longList;
//getter and setter
}
Class B{
private List<C> listC;
//getter and setter
}
Class C{
private Long id;
//getter and setter
}
Now, I want to convert between longList and C. I found the following mapping :
<mapping>
<class-a>A</class-a>
<class-b>B</class-b>
<field>
<a>longList</a>
<b>listC</b>
<a-hint>java.lang.Long</a-hint>
<b-hint>C</b-hint>
</field>
</mapping>
I am not sure whether the above mapping is the proper solution or not.
Can I set up a mapping between long and C , such that long gets mapped to C.id ?
You could try mapping Long to C like so:
<mapping>
<class-a>A</class-a>
<class-b>B</class-b>
<field>
<a>longList</a>
<b>listC</b>
<field>
</mapping>
<mapping>
<class-a>java.lang.Long</class-a>
<class-b>C</class-b>
<field>
<a>this</a>
<b>id</b>
<field>
</mapping>

Categories

Resources