【问题标题】:how to map from JaxbElement<X> to JaxbElement<Y> with MapStruct如何使用 MapStruct 从 JaxbElement<X> 映射到 JaxbElement<Y>
【发布时间】:2020-03-02 16:46:12
【问题描述】:

我本来打算在 github 上创建一个问题,但是问题模板说我宁愿先在这里讨论它,所以我们开始吧:

我正在尝试使用 Mapstruct 生成从 WSDL 生成的一组实体到另一个实体的映射。但是,如果不添加“默认”方法(手动映射),它就不起作用!这似乎很奇怪,因为我希望这种映射对于 Mapstruct 来说应该不难。复制案例在这里:https://github.com/62mkv/wsdl-mapstruct-repro-case

代码的要点在这里:

@Mapper(uses = {
    org.system.wsdl.legacy.ObjectFactory.class
})
public interface WsMapper {

org.system.wsdl.legacy.SellGarlicRequest fromCloud(org.system.wsdl.cloud.SellGarlicRequest request);

}

上面的代码将无法编译,并带有这样的消息:

无法将属性“javax.xml.bind.JAXBElement inputParameters”映射到“javax.xml.bind.JAXBElement inputParameters”。考虑声明/实现一个映射方法:“javax.xml.bind.JAXBElement map(javax.xml.bind.JAXBElement value)”。 org.system.wsdl.legacy.SellGarlicRequest fromCloud(org.system.wsdl.cloud.SellGarlicRequest request);

基本上,映射如下:EntityNew -> JaxbElement -> FieldNew -> FieldOld -> JaxbElement -> EntityOld

正如我在这里读到的 (https://stackoverflow.com/a/46015381/2583044),从 JaxbElement 到 T 的映射对于 MapStruct 来说是微不足道的,而从 T 到 JaxbElement 的映射必须使用“uses”注释并提供 ObjectFactory.class,我就是这样做的;然而……这似乎还不够。

如果我添加这两个方法,代码编译好:

org.system.wsdl.legacy.GarlicParameterCollection garlicParameterCollectionToGarlicParameterCollection(org.system.wsdl.cloud.GarlicParameterCollection collection);

default JAXBElement<org.system.wsdl.legacy.GarlicParameterCollection> garlicParameterCollectionToGarlicParameterCollection(JAXBElement<org.system.wsdl.cloud.GarlicParameterCollection> parameterCollectionJAXBElement) {
    return new org.system.wsdl.legacy.ObjectFactory().createSellGarlicRequestInputParameters(
            this.garlicParameterCollectionToGarlicParameterCollection(parameterCollectionJAXBElement.getValue())
    );
}

这是mapstruct 的潜在问题还是我只是不知道如何煮好?

【问题讨论】:

    标签: jaxb wsdl mapstruct


    【解决方案1】:

    问题在于 MapStruct 将您的对象工厂方法(带参数)视为映射方法。因此,它提供了一个目标,但它也有一个来源。如果你意识到这一点,那么映射突然就不对称了(就像它最初出现的那样)。

    简单的解决方案是指示 MapStruct 如何处理。

    所以:试试这个:

    
    @Mapper(uses = {
            org.system.wsdl.legacy.ObjectFactory.class
    })
    public interface WsMapper {
    
        org.system.wsdl.legacy.GarlicParameterCollection garlicParameterCollectionToGarlicParameterCollection(org.system.wsdl.cloud.GarlicParameterCollection collection);
    
        @Mapping( target = "inputParameters", source = "inputParameters.value") // this instructs MapStruct to use value of the source JAXBElement (for which it has an object factory method) instead of trying to map JAXBElement to JAXBElement.
        org.system.wsdl.legacy.SellGarlicRequest fromCloud(org.system.wsdl.cloud.SellGarlicRequest request);
    
    }
    
    

    最后但同样重要的是,您需要定义第一个方法garlicParameterCollectionToGarlicParameterCollection,这让我一开始很惊讶。

    原因:MapStruct 要么尝试: 1. 找到一种映射方法(如果你把这个排除在外,它就不存在了) 或者 2. 尝试生成直接映射(通过检查它是否可以找到源和目标上所有属性的方法)。

    但是,MapStruct 找不到此映射的直接案例(原则上它需要在其路径上应用所有其他可能的映射(例如对象工厂中的所有方法),然后尝试生成一个映射方法,如2,这可能是很多组合。该功能不存在(我猜也会是负载密集型的)。

    【讨论】:

    • 可以确认 - 作为一个魅力!非常感谢,@Sjaak!
    猜你喜欢
    • 2018-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-04
    • 2018-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多