Orika:将JAXB对象映射到业务/域对象
這篇文章著眼于使用Orika將JAXB對象映射到業(yè)務(wù)域?qū)ο蟆?本月初, 我使用基于反射的Dozer討論 了相同的映射用例 。 在本文中,我假設(shè)需要映射相同的示例類,但是它們將使用Orika而不是Dozer進(jìn)行映射 。
Dozer和Orika旨在解決相同類型的問題:兩個“數(shù)據(jù)”對象的自動映射,這些對象不共享公共繼承,但表示相同的數(shù)據(jù)字段。 推土機(jī)使用反射來完成此操作,而Orika使用反射和字節(jié)碼操作來完成此操作。 Orika的口號是“更簡單,更輕便,更快的Java bean映射”。
Orika擁有版本2的Apache許可證,可以從https://github.com/orika-mapper/orika/archive/master.zip (源)或http://search.maven.org/#search下載。 | ga | 1 | orika (二進(jìn)制)。 Orika對Javassist (用于字節(jié)碼操作), SLF4J和paranamer (用于在運行時訪問方法/構(gòu)造函數(shù)參數(shù)名稱)具有依賴性 。 這三個依賴項中的兩個(JavaAssist和paranamer而不是SLF4J)捆綁在orika-core-1.4.4-deps-included.jar 。 如果依賴項已經(jīng)可用,則可以使用更薄的orika-core-1.4.4.jar 。 就像這些JAR的名稱所暗示的那樣,在本文中,我使用Orika 1.4.4作為示例。
在我的《 推土機(jī):將JAXB對象映射到業(yè)務(wù)/域?qū)ο蟆芬晃闹?,我討論了通常不希望將JAXB生成的類的實例用作業(yè)務(wù)或域?qū)ο蟮脑颉?然后,我展示了JAXB生成的類和自定義數(shù)據(jù)類之間的“傳統(tǒng)”映射方式,以便可以在業(yè)務(wù)域數(shù)據(jù)對象中的整個應(yīng)用程序中傳遞數(shù)據(jù)。 在本文中,我將使用相同的方法,但是使用Orika進(jìn)行映射,而不是進(jìn)行自定義映射或使用Dozer進(jìn)行映射。 為了方便起見,我在此處列出了JAXB生成的類com.blogspot.marxsoftware.AddressType和com.blogspot.marxsoftware.PersonType的成本清單,以及重命名的自定義數(shù)據(jù)類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;}}域/業(yè)務(wù)類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;}@Overridepublic int hashCode(){return Objects.hash(this.streetAddress1, this.streetAddress2, this.municipality,this.state, this.zipCode);}@Overridepublic 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;}@Overridepublic String toString(){return "Address{" + "streetAddress1=" + streetAddress1 + ", streetAddress2="+ streetAddress2 + ", municipality=" + municipality + ", state=" + state+ ", zipCode=" + zipCode + '}';}}域/業(yè)務(wù)類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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic String toString() {return "Person{" + "lastName=" + lastName + ", firstName=" + firstName+ ", mailingAddress=" + mailingAddress + ", residentialAddress="+ residentialAddress + '}';}}與Dozer一樣,要映射的類需要具有無參數(shù)的構(gòu)造函數(shù)以及“ set”和“ get”方法以支持雙向轉(zhuǎn)換,而無需任何特殊的附加配置。 此外,與Dozer一樣,Orika會自動映射同名字段,并易于配置異常的映射(名稱不匹配的字段)。 下一個代碼清單(針對我稱為OrikaPersonConverter的類)演示了OrikaPersonConverter MapperFactory的實例化和配置,以默認(rèn)情況下映射大多數(shù)字段,并通過顯式映射來映射名稱彼此不同的字段 (“市政”和“城市”)組態(tài)。 一旦配置了MapperFactory ,就可以輕松地從一個對象復(fù)制到另一個對象,并且兩個方向都在copyPersonTypeFromPerson和copyPersonFromPersonType方法中進(jìn)行了描述。
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的情況一樣,兩個類之間的映射是雙向的,因此只需要進(jìn)行一次映射,并將應(yīng)用于從一個對象到另一個對象的復(fù)制。
結(jié)論
像推土機(jī)一樣,Orika提供的可定制性和靈活性比本文中演示的要好得多。 但是,對于相對簡單的映射(在使用JAXB生成的對象的應(yīng)用程序中很常見),Orika非常易于使用。 《 Orika用戶指南》是了解Orika的一個很好的資源。
翻譯自: https://www.javacodegeeks.com/2013/12/orika-mapping-jaxb-objects-to-businessdomain-objects.html
總結(jié)
以上是生活随笔為你收集整理的Orika:将JAXB对象映射到业务/域对象的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 海关如何备案商品(海关如何备案)
- 下一篇: JOOQ事实:从JPA批注到JOOQ表映