如何使用 MapStruct 从 JaxbElement<X> 映射到 JaxbElement<Y>
how to map from JaxbElement<X> to JaxbElement<Y> with MapStruct
我本来打算在 github 上创建一个问题,但问题模板说我宁愿先在这里讨论它,所以我们开始吧:
我正在尝试使用 Mapstruct 生成从一组 WSDL 生成的实体到另一组实体的映射。但是,如果不添加 "default" 方法(手动映射),它是行不通的!这似乎很奇怪,因为我认为这种映射对于 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);
}
以上代码将无法编译,并显示以下消息:
Can't map property "javax.xml.bind.JAXBElement inputParameters" to "javax.xml.bind.JAXBElement inputParameters". Consider to declare/implement a mapping method: "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
正如我在这里读到的那样 (),从 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
中的一个潜在问题还是我只是不知道如何煮好?
问题是 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 中解释,可能有很多组合。该功能不存在(我猜也会是负载密集型的)。
我本来打算在 github 上创建一个问题,但问题模板说我宁愿先在这里讨论它,所以我们开始吧:
我正在尝试使用 Mapstruct 生成从一组 WSDL 生成的实体到另一组实体的映射。但是,如果不添加 "default" 方法(手动映射),它是行不通的!这似乎很奇怪,因为我认为这种映射对于 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);
}
以上代码将无法编译,并显示以下消息:
Can't map property "javax.xml.bind.JAXBElement inputParameters" to "javax.xml.bind.JAXBElement inputParameters". Consider to declare/implement a mapping method: "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
正如我在这里读到的那样 (),从 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
中的一个潜在问题还是我只是不知道如何煮好?
问题是 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 中解释,可能有很多组合。该功能不存在(我猜也会是负载密集型的)。