推土机:将JAXB对象映射到业务/域对象

Dozer是开放源代码( Apache 2许可 )“ Java Bean到Java Bean映射器,可将数据从一个对象递归复制到另一个对象”。 正如从其主页上的描述所描述的那样,它用于映射两个JavaBeans实例,以在实例之间进行自动数据复制。 尽管这些可以是多种JavaBeans实例中的任何一种,但我将重点介绍如何使用Dozer将JAXB生成的对象映射到“业务数据对象”(有时称为“域对象”)。

在使用Java XML绑定体系结构JAXB )的Java应用程序中,开发人员编写特定的业务或域对象供应用程序本身使用,而仅使用JAXB生成的对象进行读取(解组)和写入操作,这是很常见的 。 (编组)XML。 尽管将JAXB生成的对象本身用作业务/域对象具有一定的吸引力DRY ),但是这种方法存在一些缺点。 JAXB生成的类没有toString()equals(Object)hashCode()实现,这使得这些生成的类不适合用于多种类型的集合中,除身份比较之外不适合比较,并且不便于记录其内容。 在对生成的类进行生成之后,对其进行手动编辑很麻烦,并且即使对源XSD进行了很小的更改,也不利于再次生成JAXB类。

尽管可以使用JAXB2 Basics来确保JAXB生成的类具有在集合中使用,进行比较以及记录其内容所需的一些通用方法,但是使用JAXB生成的类作为domain /可能存在更大的问题业务对象是业务逻辑与XSD紧密结合的必然结果。 XSD中的模式更改(例如版本更新)通常会导致通过JAXB从该XSD生成的类的包结构不同。 然后,不同的包结构将强制所有导入那些JAXB生成的类的代码来更改其导入语句。 XSD的内容更改可能会产生更大的影响,从而影响JAXB类的get / set方法,如果将JAXB类用于域/业务对象,则该方法会散布在整个应用程序中。

假定决定不使用JAXB生成的类作为业务/域类,有多种方法可以通过代码或配置中描述的“映射层”将生成的JAXB类映射到定义业务/域对象的类。 为了演示两个基于代码的映射层实现并演示基于Dozer的映射层,我介绍了一些JAXB生成的类和定制构建的业务/域类的简单示例。

本文的示例的第一部分是XSD,将从中指示JAXB'x xjc到通用类,以将其编组到该XSD所描述的XML或从该XSD所描述的XML解组。 接下来显示的XSD定义了一个Person元素,该元素可以具有嵌套的MailingAddressResidentialAddress元素以及两个用于名字和姓氏的String属性。 还要注意,主要名称空间是http://marxsoftware.blogspot.com/,JAXB将使用它来确定从该XSD生成的类的Java包层次结构。

人格

<?xml version="1.0"?>
<xs:schema version="1.0"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:marx="http://marxsoftware.blogspot.com/"
           targetNamespace="http://marxsoftware.blogspot.com/"
           elementFormDefault="qualified">
   
   <xs:element name="Person" type="marx:PersonType" />
   
   <xs:complexType name="PersonType">
      <xs:sequence>
         <xs:element name="MailingAddress" type="marx:AddressType" />
         <xs:element name="ResidentialAddress" type="marx:AddressType" minOccurs="0" />
      </xs:sequence>
      <xs:attribute name="firstName" type="xs:string" />
      <xs:attribute name="lastName" type="xs:string" />
   </xs:complexType>
   
   <xs:complexType name="AddressType">
      <xs:attribute name="streetAddress1" type="xs:string" use="required" />
      <xs:attribute name="streetAddress2" type="xs:string" use="optional" />
      <xs:attribute name="city" type="xs:string" use="required" />
      <xs:attribute name="state" type="xs:string" use="required" />
      <xs:attribute name="zipcode" type="xs:string" use="required" />
   </xs:complexType>
   
</xs:schema>

当针对上述XSD执行xjc (Oracle JDK随附的JAXB编译器)时,在com / blogspot / marxsoftware目录中(从XSD的命名空间派生)生成以下四个类: AddressType.javaPersonType.javaObjectFactory.javapackage-info.java

jaxbGeneratedClassesPersonAddress

接下来的两个代码清单是JAXB生成的两个主要感兴趣的类( PersonType.javaAddressType.java )。 在这里显示它们的主要目的是提醒他们,它们缺少我们经常需要我们的业务/域类拥有的方法。

JAXB生成的PersonType.java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 
// See http://java.sun.com/xml/jaxb 
// 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;
    }

}

JAXB生成的AddressType.java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 
// See http://java.sun.com/xml/jaxb 
// 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生成的对象和自定义编写的业务/域对象之间复制数据的一种常见而直接的策略是使用一个对象的“ get”方法并将其返回值传递给另一个对象的“ set”方法。 例如,在将XML解组/读取到应用程序的过程中,可以将JAXB生成的对象上调用的“ get”方法的结果传递给业务/域对象的“ set”方法。 相反,通过将域/业务对象上的“ get”方法的结果传递给JAXB生成的对象的相应“ set”方法,可以轻松完成编组/编写XML。 下一个代码清单用于PersonCoverter.java并说明了此方法的一种实现。

PersonConverter.java

package dustin.examples.dozerdemo;

import com.blogspot.marxsoftware.AddressType;
import com.blogspot.marxsoftware.ObjectFactory;
import com.blogspot.marxsoftware.PersonType;
import dustin.examples.Address;
import dustin.examples.Person;

/**
 * Static functions for converting between JAXB-generated objects and domain
 * objects.
 * 
 * @author Dustin
 */
public class PersonConverter
{
   /**
    * Extract business object {@link dustin.examples.Person} from the JAXB
    * generated object {@link com.blogspot.marxsoftware.PersonType}.
    * 
    * @param personType JAXB-generated {@link com.blogspot.marxsoftware.PersonType}
    *    from which to extract {@link dustin.examples.Person} object.
    * @return Instance of {@link dustin.examples.Person} based on the provided
    *    {@link com.blogspot.marxsoftware.PersonType}.
    */
   public static Person extractPersonFromPersonType(final PersonType personType)
   {
      final String lastName = personType.getLastName();
      final String firstName = personType.getFirstName();
      final Address residentialAddress =
         extractAddressFromAddressType(personType.getResidentialAddress());
      final Address mailingAddress =
         extractAddressFromAddressType(personType.getMailingAddress());
      return new Person(lastName, firstName, residentialAddress, mailingAddress);
   }

   /**
    * Extract business object {@link dustin.examples.Address} from the JAXB
    * generated object {@link com.blogspot.marxsoftware.AddressType}.
    * 
    * @param addressType JAXB-generated {@link com.blogspot.marxsoftware.AddressType}
    *    from which to extract {@link dustin.examples.Address} object.
    * @return Instance of {@link dustin.examples.Address} based on the provided
    *    {@link com.blogspot.marxsoftware.AddressType}.
    */
   public static Address extractAddressFromAddressType(final AddressType addressType)
   {
      return new Address(
         addressType.getStreetAddress1(), addressType.getStreetAddress2(),
         addressType.getCity(), addressType.getState(), addressType.getZipcode());
   }

   /**
    * Extract an instance of {@link com.blogspot.marxsoftware.PersonType} from
    * an instance of {@link dustin.examples.Person}.
    * 
    * @param person Instance of {@link dustin.examples.Person} from which
    *    instance of JAXB-generated {@link com.blogspot.marxsoftware.PersonType}
    *    is desired.
    * @return Instance of {@link com.blogspot.marxsoftware.PersonType} based on
    *    provided instance of {@link dustin.examples.Person}.
    */
   public static PersonType extractPersonTypeFromPerson(final Person person)
   {
      final ObjectFactory objectFactory = new ObjectFactory();
      final AddressType residentialAddressType =
         extractAddressTypeFromAddress(person.getResidentialAddress());
      final AddressType mailingAddressType =
         extractAddressTypeFromAddress(person.getMailingAddress());
      
      final PersonType personType = objectFactory.createPersonType();
      personType.setLastName(person.getLastName());
      personType.setFirstName(person.getFirstName());
      personType.setResidentialAddress(residentialAddressType);
      personType.setMailingAddress(mailingAddressType);
      
      return personType;
   }

   /**
    * Extract an instance of {@link com.blogspot.marxsoftware.AddressType} from
    * an instance of {@link dustin.examples.Address}.
    * 
    * @param address Instance of {@link dustin.examples.Address} from which
    *    instance of JAXB-generated {@link com.blogspot.marxsoftware.AddressType}
    *    is desired.
    * @return Instance of {@link com.blogspot.marxsoftware.AddressType} based on
    *    provided instance of {@link dustin.examples.Address}.
    */
   public static AddressType extractAddressTypeFromAddress(final Address address)
   {
      final ObjectFactory objectFactory = new ObjectFactory();
      final AddressType addressType = objectFactory.createAddressType();
      addressType.setStreetAddress1(address.getStreetAddress1());
      addressType.setStreetAddress2(address.getStreetAddress2());
      addressType.setCity(address.getMunicipality());
      addressType.setState(address.getState());
      addressType.setZipcode(address.getZipCode());
      return addressType;
   }
}

最后的代码清单演示了一种通用的第三方类方法,用于在JAXB生成的对象和域/业务对象之间双向复制数据。 另一种方法是将这种复制功能构建到域/业务对象本身中。 这在PersonPlus.javaAddressPlus.java两个代码清单中PersonPlus.java ,它们是先前介绍的Person.javaAddress.java版本,并添加了对从JAXB生成的对象复制数据的支持。 为了方便起见,我在toString实现之后将新方法添加到类的底部。

PersonPlus.java

package dustin.examples;

import com.blogspot.marxsoftware.ObjectFactory;
import com.blogspot.marxsoftware.PersonType;
import java.util.Objects;

/**
 * Person class enhanced to support copying to/from JAXB-generated PersonType.
 * 
 * @author Dustin
 */
public class PersonPlus
{
   private String lastName;
   private String firstName;
   private AddressPlus mailingAddress;
   private AddressPlus residentialAddress;

   public PersonPlus(
      final String newLastName,
      final String newFirstName,
      final AddressPlus newResidentialAddress,
      final AddressPlus 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 AddressPlus getMailingAddress()
   {
      return this.mailingAddress;
   }

   public void setMailingAddress(AddressPlus mailingAddress)
   {
      this.mailingAddress = mailingAddress;
   }

   public AddressPlus getResidentialAddress()
   {
      return this.residentialAddress;
   }

   public void setResidentialAddress(AddressPlus 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 PersonPlus other = (PersonPlus) 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  "PersonPlus{" + "lastName=" + lastName + ", firstName=" + firstName
            + ", mailingAddress=" + mailingAddress + ", residentialAddress="
            + residentialAddress + '}';
   }
   
   /**
    * Provide a JAXB-generated instance of {@link com.blogspot.marxsoftware.PersonType}
    * that corresponds to me.
    * 
    * @return Instance of {@link com.blogspot.marxsoftware.PersonType} that
    *    corresponds to me.
    */
   public PersonType toPersonType()
   {
      final ObjectFactory objectFactory = new ObjectFactory();
      final PersonType personType = objectFactory.createPersonType();
      personType.setFirstName(this.firstName);
      personType.setLastName(this.lastName);
      personType.setResidentialAddress(this.residentialAddress.toAddressType());
      personType.setMailingAddress(this.mailingAddress.toAddressType());
      return personType;
   }

   /**
    * Provide instance of {@link dustin.examples.PersonPlus} corresponding
    * to the provided instance of JAXB-generated object
    * {@link com.blogspot.marxsoftware.PersonType}.
    * 
    * @param personType Instance of JAXB-generated object
    *    {@link com.blogspot.marxsoftware.PersonType}.
    * @return Instance of me corresponding to provided JAXB-generated object
    *    {@link com.blogspot.marxsoftware.PersonType}.
    */
   public static PersonPlus fromPersonType(final PersonType personType)
   {
      final AddressPlus residentialAddress =
         AddressPlus.fromAddressType(personType.getResidentialAddress());
      final AddressPlus mailingAddress =
         AddressPlus.fromAddressType(personType.getMailingAddress());
      return new PersonPlus(personType.getLastName(), personType.getFirstName(),
                            residentialAddress, mailingAddress);
   }
}

AddressPlus.java

package dustin.examples;

import com.blogspot.marxsoftware.AddressType;
import com.blogspot.marxsoftware.ObjectFactory;
import java.util.Objects;

/**
 * Address class with support for copying to/from JAXB-generated class
 * {@link com.blogspot.marxsoftware.AddressType}.
 * 
 * @author Dustin
 */
public class AddressPlus
{
   private String streetAddress1;
   private String streetAddress2;
   private String municipality;
   private String state;
   private String zipCode;

   public AddressPlus(
      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 AddressPlus other = (AddressPlus) 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 + '}';
   }

    /**
    * Provide a JAXB-generated instance of {@link com.blogspot.marxsoftware.AddressType}
    * that corresponds to an instance of me.
    *
    * @return Instance of JAXB-generated {@link com.blogspot.marxsoftware.AddressType}
    *    that corresponds to me.
    */
   public AddressType toAddressType()
   {
      final ObjectFactory objectFactory = new ObjectFactory();
      final AddressType addressType = objectFactory.createAddressType();
      addressType.setStreetAddress1(this.streetAddress1);
      addressType.setStreetAddress2(this.streetAddress2);
      addressType.setCity(this.municipality);
      addressType.setState(this.state);
      addressType.setZipcode(this.zipCode);
      return addressType;
   }

   /**
    * Provide instance of {@link dustin.examples.AddressPlus} corresponding
    * to the provided instance of JAXB-generated object
    * {@link com.blogspot.marxsoftware.AddressType}.
    * 
    * @param addressType Instance of JAXB-generated object
    *    {@link com.blogspot.marxsoftware.AddressType}.
    * @return Instance of me corresponding to provided JAXB-generated object
    *    {@link com.blogspot.marxsoftware.AddressType}.
    */
   public static AddressPlus fromAddressType(final AddressType addressType)
   {
      return new AddressPlus(
         addressType.getStreetAddress1(),
         addressType.getStreetAddress2(),
         addressType.getCity(),
         addressType.getState(),
         addressType.getZipcode());
   }
}

上面演示的将JAXB生成的对象映射到业务/域对象的两种方法肯定会起作用,对于我的简单示例,可以将其视为最佳的使用方法(尤其是考虑到NetBeans使业务/域对象的生成几乎变得微不足道)。 但是,对于需要映射的更重要的对象层次结构,可以认为基于Dozer配置的映射是更可取的。

下载页面 (在此情况下为dozer-5.3.2.jar )下载了Dozer。 “ 入门”页面显示,当要映射的类的属性具有相同的名称时,映射确实非常容易(最小配置)。 在我的示例中,情况并非如此,我故意将一个属性设为“城市”,将另一个属性设为“市政性”,以使映射更加有趣。 由于这些名称不同,因此我需要自定义Dozer映射 ,这是通过XML映射配置完成的。 必要的映​​射文件以dozerBeanMapping.xml的“默认映射名称”命名,并在下面显示。 我只需要映射两个具有不同名称的字段( citymunicipality ),因为被映射的两个类的所有其他字段都具有相同的名称,并且无需显式配置即可自动映射在一起。

dozerBeanMapping.xml

<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozer.sourceforge.net"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://dozer.sourceforge.net
          http://dozer.sourceforge.net/schema/beanmapping.xsd">

  <configuration>
    <stop-on-errors>true</stop-on-errors>
    <date-format>MM/dd/yyyy HH:mm:ss</date-format>
    <wildcard>true</wildcard>
  </configuration>

  <mapping>
    <class-a>dustin.examples.Address</class-a>
    <class-b>com.blogspot.marxsoftware.AddressType</class-b>
      <field>
        <a>municipality</a>
        <b>city</b>
      </field>
  </mapping>  
                   
</mappings>

请注意, XML不是可用于自定义Dozer映射的唯一方法 。 还支持注释程序化API

Dozer 第三方对象工厂”页面简要介绍了如何将Dozer与JAXB和JAXBBeanFactory一起使用。 还建议与Dozer一起使用注入,并提供Spring集成的示例。 对于应用Dozer的简单示例,我没有使用这些方法,而是使用了非常简单的实例化方法。 这显示在下一个代码清单中。

DozerPersonConverter.java

package dustin.examples.dozerdemo;

import com.blogspot.marxsoftware.PersonType;
import dustin.examples.Person;
import java.util.ArrayList;
import java.util.List;
import org.dozer.DozerBeanMapper;

/**
 * Dozer-based converter.
 * 
 * @author Dustin
 */
public class DozerPersonConverter
{
   static final DozerBeanMapper mapper = new DozerBeanMapper();
   
   static
   {
      final List<String> mappingFilesNames = new ArrayList<>();
      mappingFilesNames.add("dozerBeanMapping.xml");
      mapper.setMappingFiles(mappingFilesNames);
   }

   /**
    * Provide an instance of {@link com.blogspot.marxsoftware.PersonType}
    * that corresponds with provided {@link dustin.examples.Person} as
    * mapped by Dozer Mapper.
    * 
    * @param person Instance of {@link dustin.examples.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.Person} instance.
    */
   public PersonType copyPersonTypeFromPerson(final Person person)
   {
      final PersonType personType = 
         mapper.map(person, PersonType.class);
      return personType;
   }

   /**
    * Provide an instance of {@link dustin.examples.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.Person} will be extracted.
    * @return Instance of {@link dustin.examples.Person} that is based on the
    *    provided {@link com.blogspot.marxsoftware.PersonType}.
    */
   public Person copyPersonFromPersonType(final PersonType personType)
   {
      final Person person = 
         mapper.map(personType, Person.class);
      return person;
   }
}

前面的示例显示了将JAXB生成的对象映射到业务/域对象所需的代码量。 当然,需要一些XML,但仅适用于名称不同的字段。 这意味着字段名称之间的差异越大,就需要进行更多的配置。 但是,只要大多数字段之间是一对一映射的,并且它们之间没有任何特殊的“转换”逻辑,Dozer就会用配置映射替换许多繁琐的代码。

如果需要转换字段(例如将一个对象中的米转换为另一对象中的公里),那么当必须编写自定义转换器时,此映射支持可能会不太吸引人。 推土机映射也很难更正确地应用于深层嵌套的对象,但我的示例确实将Address嵌套在Person作为一个简单示例。 尽管复杂的映射在Dozer中可能不再那么吸引人,但是JAXB生成的对象到业务/域对象的许多映射都是足够简单的映射,可以由Dozer很好地服务。

我想在这篇文章中指出的最后一件事是,Dozer对某些第三方库具有运行时依赖性。 幸运的是,无论如何,这些库还是Java项目中常用的,并且随时可用。 如下面的两个图像所示,所需的运行时依赖项是SLF4J,Apache Commons Lang,Apache Commons Logging和Apache BeanUtils。

推土机运行时相关性页面
dozerAdvertisedRuntimeDependencies
本帖子示例的NetBeans 7.4项目库 dozerNetBeansProjectRuntimeDependencies 设置Dozer及其依赖项并配置映射需要花费很少的精力,但是在许多常见的JAXB到企业对象数据复制应用程序中,可以通过大大减少映射代码来很好地回报这种努力。

参考: 推土机:在我们的JCG合作伙伴 Dustin Marx的“ 实际事件启发”博客上,将JAXB对象映射到业务/域对象

翻译自: https://www.javacodegeeks.com/2013/12/dozer-mapping-jaxb-objects-to-businessdomain-objects.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值