Java反射:调用集合类型对象的Setter和Getter方法

8
我有两个不同的用户定义对象包...
1) ws.lender.dto (all Objects exists in this package are source side).
2) copl.com.dto (all Objects exists in this package are destination side).

两侧对象层次结构和对象名称不同。我想通过反射,逐个字段或使用getter和setter将源侧对象复制到目标侧对象。

例如:

源侧对象

   package ws.lender.dto;

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "CustomerAddresses", propOrder = {
        "previousAddresses"
    })
    public class CustomerAddresses {

        protected PreviousAddresses previousAddresses;

        public PreviousAddresses getPreviousAddresses() {
            return previousAddresses;
        }

        public void setPreviousAddresses(PreviousAddresses value) {
            this.previousAddresses = value;
        }

    }


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "PreviousAddresses", propOrder = {
    "previousAddress"
})
public class PreviousAddresses {

    @XmlElement(name = "PreviousAddress", required = true)
    protected List<PreviousAddress> previousAddress;

    public List<PreviousAddress> getPreviousAddress() {
        if (previousAddress == null) {
            previousAddress = new ArrayList<PreviousAddress>();
        }
        return this.previousAddress;
    }
}


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "PreviousAddress", propOrder = {

    "streetNo",
    "streetName"
})
public class PreviousAddress {

    @XmlElement(name = "StreetNo", required = true)
    protected String streetNo;
    @XmlElement(name = "StreetName", required = true)
    protected String streetName;

    public String getStreetNo() {
        return streetNo;
    }
    public void setStreetNo(String value) {
        this.streetNo = value;
    }
    public String getStreetName() {
        return streetName;
    }
    public void setStreetName(String value) {
        this.streetName = value;
    }
}

目的地方对象
package copl.com.dto;

@javax.persistence.Entity
public class Customer implements java.io.Serializable
{
private Set<CustomerAddress> customerAddresses;

   public Set<CustomerAddress> getCustomerAddresses()
    {
        return customerAddresses;
    }

        public void setCustomerAddresses(Set<CustomerAddress> customerAddresses)
    {
        this.customerAddresses = customerAddresses;
    }
}

@javax.persistence.Entity
public class CustomerAddress implements java.io.Serializable
{   
    private String unitNumber;
    private String streetName;
    private String streetNumber;

   public String getUnitNumber()
    {
        return unitNumber;
    }   
        public void setUnitNumber(String unitNumber)
    {
        this.unitNumber = unitNumber;
    }
        public String getStreetName()
    {
        return streetName;
    }
       public String getStreetNumber()
    {
        return streetNumber;
    }
        public void setStreetName(String streetName)
    {
        this.streetName = streetName;
    }

    public void setStreetNumber(String streetNumber)
    {
        this.streetNumber = streetNumber;
    }
}   

@MadProgrammer 我需要你的帮助。 - Z.I.J
4个回答

8
我认为您可以使用MapStruct来映射具有不同属性名称的POJO之间的关系。
但是,您的情况比较复杂,因为您想要将ws.lender.dto.CustomerAddresses转换为copl.com.dto.Customer,这意味着需要将包含在ws.lender.dto.PreviousAddresses对象中的List<ws.lender.dto.PreviousAddress>转换为包含在copl.com.dto.Customer对象中的Set<copl.com.dto.CustomerAddress>
所以,我将一步一步地解释。

1. 从ws.lender.dto.PreviousAddress转换为copl.com.dto.CustomerAddress

为了进行此转换,您需要一个接口(MapStruct将为此创建一个实例),负责从源对象映射到目标对象:
import ws.lender.dto.PreviousAddress;
import copl.com.dto.CustomerAddress;

@Mapper
public interface CustomerAddressesMapper{

    CustomerAddressesMapper INSTANCE = Mappers.getMapper( CustomerAddressesMapper.class );

    @Mappings(@Mapping(source = "streetNo", target = "streetNumber")
    CustomerAddress previousToCustomerObject(PreviousAddress address);
}

这个接口将会把PreviousAddress对象映射到CustomerAddress,并考虑到streetNo属性需要映射到streetNumber。由于没有源,unitNumber属性不需要映射。

2. 将List<ws.lender.dto.PreviousAddress>转换为Set<copl.com.dto.CustomerAddress>

现在你需要在现有的CustomerAddressesMapper接口中添加另一个映射方法:

Set<CustomerAddress> previousToCustomerSet(List<PreviousAddress> addresses);

这个方法将使用之前的previousToCustomerObject来将源列表中的每个元素转换为目标集合。

3. 从ws.lender.dto.CustomerAddresses转换为copl.com.dto.Customer

最后,您需要在CustomerAddressesMapper接口中添加最后一个映射方法:

@Mappings(@Mapping(source = "previousAddresses.previousAddress", target = "customerAddresses")
Customer customerAddrsToCustomerObject(CustomerAddresses addresses);

这是一个将源对象映射到目标对象的过程,将previousAddresses.previousAddress属性转换为customerAddresses属性,使用前面的方法。

4. 使用映射器

要使用映射器,您需要编写以下代码:

CustomerAddressesMapper mapper = CustomerAddressesMapper.INSTANCE;
CustomerAddresses origin = //Retrieve it from anywhere
Customer dest = mapper.customerAddrsToCustomerObject(origin);

5. 设置

MapStruct是一个源代码生成器,因此您需要正确配置pom.xml以包含MapStruct依赖项并调用此代码生成。您可以在这里了解如何操作。

我不构建和运行此代码,但这是完成操作的方法。

希望它能帮到您!


非常感谢您花时间回答这个问题,我已经尝试使用上述方法但没有成功,然后我转向了Orika Mapper框架,并完成了工作。最后,我决定将赏金颁发给您。 - Z.I.J
@Z.I.J,出于兴趣,你遇到了哪些具体问题?很高兴了解更多细节,也许我们可以在MapStruct中改进一些东西。谢谢! - Gunnar

3

我已经研究了许多对象映射框架,例如:

最终我选择了Orika框架来完成上述对象到对象的映射。虽然我们也可以通过其他映射框架来完成这种映射,但我喜欢Orika框架,因为该框架非常易于使用。

接下来我将逐步解释。

1.创建源端和目标端对象。

类似于这样...

    Customer destination = new Customer();
    CustomerAddresses source = new CustomerAddresses();
    source = filledCustomerAddressesObject();

2. 构建DefaultMapperFactory

MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();

3. 映射字段


    ClassMapBuilder<CustomerAddresses, Customer> builder;
    
    builder= mapperFactory.classMap(CustomerAddresses.class, Customer.class).constructorA();

    builder.field("previousAddresses.previousAddress{streetNo}","customerAddresses{streetNumber}");
    builder.field("previousAddresses.previousAddress{streetName}","customerAddresses{streetName}");
    
    builder.register();

    BoundMapperFacade<CustomerAddresses, Customer> boundMapper;
    
    boundMapper = mapperFactory.getMapperFacade(CustomerAddresses.class, Customer.class);
    
    destination = boundMapper.map(source, destination);

它能正常工作,棒极了!


2
您可以尝试使用Object Mapper进行更好的转换或复制。您可以向其他包中的其他类添加一些属性值,例如

senderClassrvcClass

稍后,您可以读取这些属性并继续转换类。可能您已经准备好了将发送方类映射到接收方类的映射。


我认为Object Mapper用于JSON到对象或对象到JSON的转换。 - Z.I.J
请查看此链接:https://dev59.com/p3M_5IYBdhLWcg3wThR3 - Bhushan Pawar
非常感谢您的帮助。 - Z.I.J

1
如果我理解正确,您需要一种将一个对象中所有同名属性复制到另一个对象中的方法。同名属性是指源对象具有类似于getPropertyName()的方法,而目标对象具有类似于setPropertyName()的方法。
如果是这样,您可以使用Apache Commons库中BeanUtils类的copyProperties方法。文档在这里
现在,在您的示例中,您有一些对应的属性名称不相同,例如StreetNumber和StreetNo。恐怕没有简单的方法通过反射自动处理这种情况;您需要自己定义源和目标属性之间的映射,可能需要定义一个辅助类来进行复制。

非常感谢您的帮助。 - Z.I.J

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接