orika 映射非空字段
这篇文章着眼于使用Orika将JAXB对象映射到业务域对象。 本月初, 我使用基于反射的Dozer讨论 了相同的映射用例 。 在本文中,我假设需要映射相同的示例类,但是它们将使用Orika而不是Dozer进行映射 。
Dozer和Orika旨在解决相同类型的问题:两个“数据”对象的自动映射,这些对象不共享公共继承,但表示相同的数据字段。 推土机使用反射来完成此操作,而Orika使用反射和字节码操作来完成此操作。 Orika的口号是“更简单,更轻便,更快的Java bean映射”。
Orika拥有版本2的Apache许可证,可以从https://github.com/orika-mapper/orika/archive/master.zip (源)或http://search.maven.org/#search下载。 | ga | 1 | orika (二进制)。 Orika对Javassist (用于字节码操作), SLF4J和paranamer (用于在运行时访问方法/构造函数参数名称)具有依赖性 。 这三个依赖项中的两个(JavaAssist和paranamer而不是SLF4J)捆绑在orika-core-1.4.4-deps-included.jar
。 如果依赖项已经可用,则可以使用更薄的orika-core-1.4.4.jar
。 就像这些JAR的名称所暗示的那样,在本文中,我使用Orika 1.4.4作为示例。
在我的“ 推土机:将JAXB对象映射到业务/域对象”一文中 ,我讨论了通常不希望将JAXB生成的类的实例用作业务或域对象的原因。 然后,我展示了JAXB生成的类和自定义数据类之间的“传统”映射方式,以便可以在业务域数据对象中的整个应用程序中传递数据。 在本文中,我将使用相同的方法,但是使用Orika进行映射,而不是执行自定义映射或使用Dozer进行映射。 为方便起见,我在此处列出了JAXB生成的类com.blogspot.marxsoftware.AddressType
和com.blogspot.marxsoftware.PersonType
的成本清单,以及重命名的自定义数据类dustin.examples.orikademo.Address
和dustin.examples.orikademo.Person
。
JAXB生成的AddressType.java
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2013.12.03 at 11:44:32 PM MST
//
package com.blogspot.marxsoftware;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for AddressType complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="AddressType">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <attribute name="streetAddress1" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="streetAddress2" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="city" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="state" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="zipcode" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "AddressType")
public class AddressType {
@XmlAttribute(name = "streetAddress1", required = true)
protected String streetAddress1;
@XmlAttribute(name = "streetAddress2")
protected String streetAddress2;
@XmlAttribute(name = "city", required = true)
protected String city;
@XmlAttribute(name = "state", required = true)
protected String state;
@XmlAttribute(name = "zipcode", required = true)
protected String zipcode;
/**
* Gets the value of the streetAddress1 property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getStreetAddress1() {
return streetAddress1;
}
/**
* Sets the value of the streetAddress1 property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setStreetAddress1(String value) {
this.streetAddress1 = value;
}
/**
* Gets the value of the streetAddress2 property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getStreetAddress2() {
return streetAddress2;
}
/**
* Sets the value of the streetAddress2 property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setStreetAddress2(String value) {
this.streetAddress2 = value;
}
/**
* Gets the value of the city property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getCity() {
return city;
}
/**
* Sets the value of the city property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setCity(String value) {
this.city = value;
}
/**
* Gets the value of the state property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getState() {
return state;
}
/**
* Sets the value of the state property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setState(String value) {
this.state = value;
}
/**
* Gets the value of the zipcode property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getZipcode() {
return zipcode;
}
/**
* Sets the value of the zipcode property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setZipcode(String value) {
this.zipcode = value;
}
}
JAXB生成的PersonType.java
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2013.12.03 at 11:44:32 PM MST
//
package com.blogspot.marxsoftware;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for PersonType complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="PersonType">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="MailingAddress" type="{http://marxsoftware.blogspot.com/}AddressType"/>
* <element name="ResidentialAddress" type="{http://marxsoftware.blogspot.com/}AddressType" minOccurs="0"/>
* </sequence>
* <attribute name="firstName" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="lastName" type="{http://www.w3.org/2001/XMLSchema}string" />
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "PersonType", propOrder = {
"mailingAddress",
"residentialAddress"
})
public class PersonType {
@XmlElement(name = "MailingAddress", required = true)
protected AddressType mailingAddress;
@XmlElement(name = "ResidentialAddress")
protected AddressType residentialAddress;
@XmlAttribute(name = "firstName")
protected String firstName;
@XmlAttribute(name = "lastName")
protected String lastName;
/**
* Gets the value of the mailingAddress property.
*
* @return
* possible object is
* {@link AddressType }
*
*/
public AddressType getMailingAddress() {
return mailingAddress;
}
/**
* Sets the value of the mailingAddress property.
*
* @param value
* allowed object is
* {@link AddressType }
*
*/
public void setMailingAddress(AddressType value) {
this.mailingAddress = value;
}
/**
* Gets the value of the residentialAddress property.
*
* @return
* possible object is
* {@link AddressType }
*
*/
public AddressType getResidentialAddress() {
return residentialAddress;
}
/**
* Sets the value of the residentialAddress property.
*
* @param value
* allowed object is
* {@link AddressType }
*
*/
public void setResidentialAddress(AddressType value) {
this.residentialAddress = value;
}
/**
* Gets the value of the firstName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getFirstName() {
return firstName;
}
/**
* Sets the value of the firstName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setFirstName(String value) {
this.firstName = value;
}
/**
* Gets the value of the lastName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getLastName() {
return lastName;
}
/**
* Sets the value of the lastName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setLastName(String value) {
this.lastName = value;
}
}
域/业务类Address.java
package dustin.examples.orikademo;
import java.util.Objects;
/**
* Address class.
*
* @author Dustin
*/
public class Address
{
private String streetAddress1;
private String streetAddress2;
private String municipality;
private String state;
private String zipCode;
public Address() {}
public Address(
final String newStreetAddress1,
final String newStreetAddress2,
final String newMunicipality,
final String newState,
final String newZipCode)
{
this.streetAddress1 = newStreetAddress1;
this.streetAddress2 = newStreetAddress2;
this.municipality = newMunicipality;
this.state = newState;
this.zipCode = newZipCode;
}
public String getStreetAddress1()
{
return this.streetAddress1;
}
public void setStreetAddress1(String streetAddress1)
{
this.streetAddress1 = streetAddress1;
}
public String getStreetAddress2()
{
return this.streetAddress2;
}
public void setStreetAddress2(String streetAddress2)
{
this.streetAddress2 = streetAddress2;
}
public String getMunicipality()
{
return this.municipality;
}
public void setMunicipality(String municipality)
{
this.municipality = municipality;
}
public String getState() {
return this.state;
}
public void setState(String state)
{
this.state = state;
}
public String getZipCode()
{
return this.zipCode;
}
public void setZipCode(String zipCode)
{
this.zipCode = zipCode;
}
@Override
public int hashCode()
{
return Objects.hash(
this.streetAddress1, this.streetAddress2, this.municipality,
this.state, this.zipCode);
}
@Override
public boolean equals(Object obj)
{
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Address other = (Address) obj;
if (!Objects.equals(this.streetAddress1, other.streetAddress1))
{
return false;
}
if (!Objects.equals(this.streetAddress2, other.streetAddress2))
{
return false;
}
if (!Objects.equals(this.municipality, other.municipality))
{
return false;
}
if (!Objects.equals(this.state, other.state))
{
return false;
}
if (!Objects.equals(this.zipCode, other.zipCode))
{
return false;
}
return true;
}
@Override
public String toString()
{
return "Address{" + "streetAddress1=" + streetAddress1 + ", streetAddress2="
+ streetAddress2 + ", municipality=" + municipality + ", state=" + state
+ ", zipCode=" + zipCode + '}';
}
}
域/业务类Person.java
package dustin.examples.orikademo;
import java.util.Objects;
/**
* Person class.
*
* @author Dustin
*/
public class Person
{
private String lastName;
private String firstName;
private Address mailingAddress;
private Address residentialAddress;
public Person() {}
public Person(
final String newLastName,
final String newFirstName,
final Address newResidentialAddress,
final Address newMailingAddress)
{
this.lastName = newLastName;
this.firstName = newFirstName;
this.residentialAddress = newResidentialAddress;
this.mailingAddress = newMailingAddress;
}
public String getLastName()
{
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName()
{
return this.firstName;
}
public void setFirstName(String firstName)
{
this.firstName = firstName;
}
public Address getMailingAddress()
{
return this.mailingAddress;
}
public void setMailingAddress(Address mailingAddress)
{
this.mailingAddress = mailingAddress;
}
public Address getResidentialAddress()
{
return this.residentialAddress;
}
public void setResidentialAddress(Address residentialAddress)
{
this.residentialAddress = residentialAddress;
}
@Override
public int hashCode()
{
int hash = 3;
hash = 19 * hash + Objects.hashCode(this.lastName);
hash = 19 * hash + Objects.hashCode(this.firstName);
hash = 19 * hash + Objects.hashCode(this.mailingAddress);
hash = 19 * hash + Objects.hashCode(this.residentialAddress);
return hash;
}
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final Person other = (Person) obj;
if (!Objects.equals(this.lastName, other.lastName))
{
return false;
}
if (!Objects.equals(this.firstName, other.firstName))
{
return false;
}
if (!Objects.equals(this.mailingAddress, other.mailingAddress))
{
return false;
}
if (!Objects.equals(this.residentialAddress, other.residentialAddress))
{
return false;
}
return true;
}
@Override
public String toString() {
return "Person{" + "lastName=" + lastName + ", firstName=" + firstName
+ ", mailingAddress=" + mailingAddress + ", residentialAddress="
+ residentialAddress + '}';
}
}
与Dozer一样,要映射的类需要具有无参数的构造函数以及“ set”和“ get”方法以支持双向转换,而无需任何特殊的附加配置。 另外,与Dozer一样,Orika会自动映射同名字段,并易于配置异常的映射(名称不匹配的字段)。 下一个代码清单(针对我称为OrikaPersonConverter
的类)演示了OrikaPersonConverter
MapperFactory的实例化和配置,以默认情况下映射大多数字段,并通过显式映射来映射名称彼此不同的字段 (“市政”和“城市”)组态。 一旦配置了MapperFactory ,就可以轻松地从一个对象复制到另一个对象,并且两个方向都在copyPersonTypeFromPerson
和copyPersonFromPersonType
方法中进行了描述。
OrikaPersonConverter
package dustin.examples.orikademo;
import com.blogspot.marxsoftware.AddressType;
import com.blogspot.marxsoftware.PersonType;
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
/**
* Convert between instances of {@link com.blogspot.marxsoftware.PersonType}
* and {@link dustin.examples.orikademo.Person}.
*
* @author Dustin
*/
public class OrikaPersonConverter
{
/** Orika Mapper Facade. */
private final static MapperFacade mapper;
static
{
final MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
mapperFactory.classMap(Address.class, AddressType.class)
.field("municipality", "city")
.byDefault()
.register();
mapper = mapperFactory.getMapperFacade();
}
/** No-arguments constructor. */
public OrikaPersonConverter() {}
/**
* Provide an instance of {@link com.blogspot.marxsoftware.PersonType}
* that corresponds with provided {@link dustin.examples.orikademo.Person} as
* mapped by Dozer Mapper.
*
* @param person Instance of {@link dustin.examples.orikademo.Person} from which
* {@link com.blogspot.marxsoftware.PersonType} will be extracted.
* @return Instance of {@link com.blogspot.marxsoftware.PersonType} that
* is based on provided {@link dustin.examples.orikademo.Person} instance.
*/
public PersonType copyPersonTypeFromPerson(final Person person)
{
PersonType personType = mapper.map(person, PersonType.class);
return personType;
}
/**
* Provide an instance of {@link dustin.examples.orikademo.Person} that corresponds
* with the provided {@link com.blogspot.marxsoftware.PersonType} as
* mapped by Dozer Mapper.
*
* @param personType Instance of {@link com.blogspot.marxsoftware.PersonType}
* from which {@link dustin.examples.orikademo.Person} will be extracted.
* @return Instance of {@link dustin.examples.orikademo.Person} that is based on the
* provided {@link com.blogspot.marxsoftware.PersonType}.
*/
public Person copyPersonFromPersonType(final PersonType personType)
{
Person person = mapper.map(personType, Person.class);
return person;
}
}
与Dozer的情况一样,两个类之间的映射是双向的,因此只需进行一次映射,并将应用于从一个对象到另一个对象的复制。
结论
像推土机一样,Orika提供的自定义性和灵活性比本文中演示的要好得多。 但是,对于相对简单的映射(在使用JAXB生成的对象的应用程序中很常见),Orika非常易于使用。 《 Orika用户指南》是了解更多有关Orika的好资源。
翻译自: https://www.javacodegeeks.com/2013/12/orika-mapping-jaxb-objects-to-businessdomain-objects.html
orika 映射非空字段