【发布时间】:2019-07-16 17:48:05
【问题描述】:
我已经关注这个问题很长时间了,但一直无法找到答案。我正在尝试使用 mapstruct 映射具有作为通用 SingleValue 对象实现的字段的对象。
让我用一个简化的例子来说明这个问题。 (为了便于阅读,省略了抛出)
我们有一个单值对象:
public abstract class SingleValue<T extends Serializable> implements Serializable {
private T value;
public SingleValue(T value) {
this.value = value;
}
}
具体的单值类如下所示
public class FirstName extends SingleValue<String>{
}
并且将用于可能相互映射的不同对象
应该可能的映射:
- 字符串 -> 名字
- 名字 -> 字符串
- FirstName -> 另一个扩展 SingleValue 对象
当前解决方案可以进行以下映射:
- 字符串 -> 名字
- 名字 -> 字符串
当前单值映射器
@Mapper
public interface SingleValueMapper {
SingleValueMapper INSTANCE = Mappers.getMapper(SingleValueMapper.class);
default <Z extends Serializable, T extends SingleValue<Z>> T singleValue(Z obj, Class<Z> objClass, @TargetType Class<T> targetType) {
if (obj == null) {
return null;
}
return targetType.getConstructor(objClass).newInstance(obj);
}
default <T extends Serializable, Z extends SingleValue<T>> T getValue(Z singleValue) {
if (singleValue == null) {
return null;
}
return singleValue.getValue();
}
default <T extends SingleValue<String>> T singleValue(String obj, @TargetType Class<T> targetType) {
return singleValue(obj, String.class, targetType);
}
}
对于 FirstName -> 另一个扩展 SingleValue 对象映射我想出了以下不起作用的解决方案:
default <T extends SingleValue<String>> T stringSingleValue(SingleValue<String> obj, @TargetType Class<T> targetType)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
return singleValue(obj.getValue(), String.class, targetType);
}
上面提到的映射方法存在的问题:
- 在自动选择中,Mapstruct 将更喜欢 getValue(Z singleValue) 映射而不是这个映射(我真的不想使用限定符,因为那样我需要限定每个映射的字段)
- 例如,如果我们还为 UUID 单个值添加一个映射方法,Mapstruct 会认为映射方法不明确
在将 String 映射到 A extends SingleValue 时,mapstruct 会生成此调用:
A a = singleValueMapper.singleValue( client.getCompanyName(), A.class )
此调用不是由 mapstruct 选择的,但我们可以在手动使用它时使用它,并将 @Mapping 作为表达式。但是,我们希望 mapstruct 在将 A extends SingleValue 映射到 B extends SingleValue 时自动映射这些调用:
B b =singleValueMapper.stringSingleValue(command.getTitle(), B.class)
有没有办法使用 mapstruct 和 java 泛型来解决这个问题?
我正在使用 Mapstruct 版本 1.3.0-final。
【问题讨论】:
-
您使用的是哪个版本的 MapStruct?
-
版本 1.3.0-final
-
您的第一个方法似乎有 3 个参数.. ` default
> T singleValue(Z obj, Class objClass, @TargetType Class targetType)` MapStruct 只能选择基于源/目标的映射方法。不能基于 2 个源。但是,它可以基于多个来源构建类..这是您的意图吗?实际上是 @ObjectFactory吗? -
在这种情况下很难为您提供帮助。您能否也提供此示例的调用映射器。?
-
@Sjaak 在回答您的问题时,我意识到我的问题中有一个错误,我想到但没有奏效的解决方案不是正确的代码 sn-p 我在问题中解决了这个问题。 SingleValueMapper 之外的其他映射器永远不会调用具有 3 个参数的方法。在上面的示例中,它仅被称为具有 2 个参数的方法,即 'default
> T singleValue(String obj, '@'TargetType Class targetType)' 方法。我在问题中添加了呼叫示例和一些描述性文本