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。您现在进行映射的方式并不是真正有效。您可以只添加一个用于将列表映射到映射器的方法并调用它,而不是使用流。