MapStruct Java 流
MapStruct Java Streams
你好我对流等很陌生,只是出于培训目的,我正在尝试使用 mapstruct 构建简单的 api。
我的问题是,我真的不知道如何 return 转换父值以及该实体中的转换字段。
这是我的简单 ObjecDTO
public class RecipeDTO {
private Integer id;
private String title;
private String description;
private String imgUrl;
private String directions;
private String prepTime;
private Integer servings;
private String category;
private Set<IngredientDTO> ingredientDTOSet = new HashSet<>();
}
实体
public class Recipe {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "recipe_id")
private Integer id;
@NotNull
@Column(name = "recipe_title")
private String title;
@NotNull
@Column(name = "recipe_description")
private String description;
@Column(name = "recipe_img_url")
private String imgUrl;
@NotNull
@Column(name = "recipe_direction")
private String directions;
@NotNull
@Column(name = "prep_time")
private String prepTime;
@NotNull
@Column(name = "servings")
private Integer servings;
@NotNull
@Column(name = "category")
private String category;
@OneToMany(mappedBy = "recipe",
cascade = CascadeType.ALL)
private Set<Ingredient> ingredients = new HashSet<>();
}
服务(只有一种方法)
@Override
public List<RecipeDTO> findAll() {
log.debug("\n" + this.getClass().getSimpleName() + " -> findAll() \n");
return recipeRepository.findAll()
.stream()
.map(recipe -> RecipeMapper.INSTANCE.recipeToRecipeDTO(recipe))
.collect(Collectors.toList());
}
@Mapper(componentModel = "spring", uses = {IngredientMapper.class})
public interface RecipeMapper {
RecipeMapper INSTANCE = Mappers.getMapper(RecipeMapper.class);
@Mappings({
@Mapping(source = "ingredients", target = "ingredientDTOSet")
})
RecipeDTO recipeToRecipeDTO(Recipe recipe);
}
何转换嵌套 bean?
当我试图获取所有 Recipes 时抛出异常
java.lang.NullPointerException: 空
在 com.mateuszgeborski.recipeappapi.api.mapper.RecipeMapperImpl.ingredientSetToIngredientDTOSet(RecipeMapperImpl.java:52) ~[类/:na]
在 com.mateuszgeborski.recipeappapi.api.mapper.RecipeMapperImpl.recipeToRecipeDTO(RecipeMapperImpl.java:32) ~[类/:na]
在 com.mateuszgeborski.recipeappapi.service.RecipeServiceImpl.lambda$findAll$0(RecipeServiceImpl.java:38) ~[类/:na]
在 java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[na:1.8.0_181]
在 java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382) ~[na:1.8.0_181]
在 java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[na:1.8.0_181]
在等..
看起来有成分,但是当我使用 Recipe 而不是 DTO 时,一切都很好..
你可以使用流的映射功能
List<Recipe> list = ... //however you get your original list
List<RecipeDTO> dtos = list.stream().map(mapper::convert).collect(Collectors.toList);
我假设你的mapstruct方法叫做"convert",mapper的变量叫做"mapper"
列表的映射将为流中的每个条目调用给定的方法 (mapper::convert),之后流将包含此方法的所有调用的所有 return 值。所以在你的情况下:它将转换列表中的每个条目,之后列表将包含所有转换后的元素
之后只需要重新采集流,就又得到了一个list
在你修改后这个答案不再有效,因为你改变了问题并且已经使用了我的答案。
关于你的后续问题:
一般转换嵌套 bean:只要嵌套 bean 的结构相同,mapstruct 就会开箱即用。如果有差异,则必须对其进行注释。如果没有看到这部分代码,我无法告诉您 Ingrediant 和 IngrediantDTO 之间的区别。
您可以尝试查看生成的 class,并查看导致 NullPointerException 的行。所以你有胶水有什么区别。然后将其注释到映射器接口
对于一般的嵌套 bean:
1)你可以在你的映射器中添加一个接口方法"ingredientToIngredientDTO"。并为此方法注释差异(如果需要)。 MapStruct 将把它用于 recipeToRecipeDTO 方法!
2)你可以注释嵌套差异。例如@Mapping(source = "ingredients.nameA", target = "ingredientDTOSet.nameB")
但是您现在问的问题与开始时完全不同,要回答这个问题,我需要更多信息。因此,我宁愿将其重新编辑为原始问题。如果我的提示还不够,请问一个有足够信息的新人
这不是关于 java 流的问题。 Java 流 api 正在调用失败的 recipeToRecipeDTO
方法。理想情况下,方法 recipeToRecipeDTO
应该能够将整个 Recipe 对象转换为 RecipeDTO。
为了解决这个问题,您需要在RecipeMapper
中添加一个方法,将一个Ingredient
实体对象转换为IngredientDTO
。
问题是您将 componentModel = "spring"
与 Mappers
工厂混合在一起。当您使用 spring 组件模型时,使用的映射器将在生成的 class 中自动装配,而 Mappers
工厂仅初始化实例。这意味着您的食谱映射器没有被注入。
为了解决它,您应该在所有地方使用默认的 componentModel 或使用 spring 并注入您的映射器。
P.S。您现在进行映射的方式并不是真正有效。您可以只添加一个用于将列表映射到映射器的方法并调用它,而不是使用流。
你好我对流等很陌生,只是出于培训目的,我正在尝试使用 mapstruct 构建简单的 api。 我的问题是,我真的不知道如何 return 转换父值以及该实体中的转换字段。
这是我的简单 ObjecDTO
public class RecipeDTO {
private Integer id;
private String title;
private String description;
private String imgUrl;
private String directions;
private String prepTime;
private Integer servings;
private String category;
private Set<IngredientDTO> ingredientDTOSet = new HashSet<>();
}
实体
public class Recipe {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "recipe_id")
private Integer id;
@NotNull
@Column(name = "recipe_title")
private String title;
@NotNull
@Column(name = "recipe_description")
private String description;
@Column(name = "recipe_img_url")
private String imgUrl;
@NotNull
@Column(name = "recipe_direction")
private String directions;
@NotNull
@Column(name = "prep_time")
private String prepTime;
@NotNull
@Column(name = "servings")
private Integer servings;
@NotNull
@Column(name = "category")
private String category;
@OneToMany(mappedBy = "recipe",
cascade = CascadeType.ALL)
private Set<Ingredient> ingredients = new HashSet<>();
}
服务(只有一种方法)
@Override
public List<RecipeDTO> findAll() {
log.debug("\n" + this.getClass().getSimpleName() + " -> findAll() \n");
return recipeRepository.findAll()
.stream()
.map(recipe -> RecipeMapper.INSTANCE.recipeToRecipeDTO(recipe))
.collect(Collectors.toList());
}
@Mapper(componentModel = "spring", uses = {IngredientMapper.class})
public interface RecipeMapper {
RecipeMapper INSTANCE = Mappers.getMapper(RecipeMapper.class);
@Mappings({
@Mapping(source = "ingredients", target = "ingredientDTOSet")
})
RecipeDTO recipeToRecipeDTO(Recipe recipe);
}
何转换嵌套 bean? 当我试图获取所有 Recipes 时抛出异常
java.lang.NullPointerException: 空 在 com.mateuszgeborski.recipeappapi.api.mapper.RecipeMapperImpl.ingredientSetToIngredientDTOSet(RecipeMapperImpl.java:52) ~[类/:na] 在 com.mateuszgeborski.recipeappapi.api.mapper.RecipeMapperImpl.recipeToRecipeDTO(RecipeMapperImpl.java:32) ~[类/:na] 在 com.mateuszgeborski.recipeappapi.service.RecipeServiceImpl.lambda$findAll$0(RecipeServiceImpl.java:38) ~[类/:na] 在 java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[na:1.8.0_181] 在 java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382) ~[na:1.8.0_181] 在 java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[na:1.8.0_181] 在等..
看起来有成分,但是当我使用 Recipe 而不是 DTO 时,一切都很好..
你可以使用流的映射功能
List<Recipe> list = ... //however you get your original list
List<RecipeDTO> dtos = list.stream().map(mapper::convert).collect(Collectors.toList);
我假设你的mapstruct方法叫做"convert",mapper的变量叫做"mapper"
列表的映射将为流中的每个条目调用给定的方法 (mapper::convert),之后流将包含此方法的所有调用的所有 return 值。所以在你的情况下:它将转换列表中的每个条目,之后列表将包含所有转换后的元素
之后只需要重新采集流,就又得到了一个list
在你修改后这个答案不再有效,因为你改变了问题并且已经使用了我的答案。
关于你的后续问题: 一般转换嵌套 bean:只要嵌套 bean 的结构相同,mapstruct 就会开箱即用。如果有差异,则必须对其进行注释。如果没有看到这部分代码,我无法告诉您 Ingrediant 和 IngrediantDTO 之间的区别。
您可以尝试查看生成的 class,并查看导致 NullPointerException 的行。所以你有胶水有什么区别。然后将其注释到映射器接口
对于一般的嵌套 bean: 1)你可以在你的映射器中添加一个接口方法"ingredientToIngredientDTO"。并为此方法注释差异(如果需要)。 MapStruct 将把它用于 recipeToRecipeDTO 方法! 2)你可以注释嵌套差异。例如@Mapping(source = "ingredients.nameA", target = "ingredientDTOSet.nameB")
但是您现在问的问题与开始时完全不同,要回答这个问题,我需要更多信息。因此,我宁愿将其重新编辑为原始问题。如果我的提示还不够,请问一个有足够信息的新人
这不是关于 java 流的问题。 Java 流 api 正在调用失败的 recipeToRecipeDTO
方法。理想情况下,方法 recipeToRecipeDTO
应该能够将整个 Recipe 对象转换为 RecipeDTO。
为了解决这个问题,您需要在RecipeMapper
中添加一个方法,将一个Ingredient
实体对象转换为IngredientDTO
。
问题是您将 componentModel = "spring"
与 Mappers
工厂混合在一起。当您使用 spring 组件模型时,使用的映射器将在生成的 class 中自动装配,而 Mappers
工厂仅初始化实例。这意味着您的食谱映射器没有被注入。
为了解决它,您应该在所有地方使用默认的 componentModel 或使用 spring 并注入您的映射器。
P.S。您现在进行映射的方式并不是真正有效。您可以只添加一个用于将列表映射到映射器的方法并调用它,而不是使用流。