MapStruct Java Streams - PullRequest
       6

MapStruct Java Streams

0 голосов
/ 01 октября 2018

Здравствуйте, я довольно новичок в потоках и т. Д., Просто для целей обучения я пытаюсь создать простой API с помощью MapStore.Моя проблема в том, что я не знаю, как вернуть преобразованное родительское значение с преобразованным полем в этой сущности.

Вот мой простой 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<>();
}

Entity

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);


}

Ho для преобразования вложенных бинов?Когда я пытаюсь получить все рецепты, создается исключениеna] at com.mateuszgeborski.recipeappapi.api.mapper.RecipeMapperImpl.recipeToRecipeDTO (RecipeMapperImpl.java:32) ~ [классы /: na] в com.mateuszgeborski.recipeappapi.service.RecipeServiceImplAll38) ~ [classes /: 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] в etc ..

Похоже, что тамэто ингредиенты, но когда я работаю с рецептом, а не DTO все в порядке ..

Ответы [ 3 ]

0 голосов
/ 01 октября 2018

Это не вопрос о потоке Java.Java-поток API вызывает метод recipeToRecipeDTO, который не работает.В идеале метод recipeToRecipeDTO должен иметь возможность конвертировать весь объект Recipe в RecipeDTO.

Чтобы решить эту проблему, вам нужно добавить метод в RecipeMapper, который преобразует один Ingredient объектный объект в IngredientDTO.

0 голосов
/ 02 октября 2018

Проблема в том, что вы смешиваете componentModel = "spring" с фабрикой Mappers.При использовании модели компонентов пружины используемые преобразователи автоматически подключаются в сгенерированном классе, и фабрика Mappers только инициализирует экземпляр.Это означает, что ваш рецепт маппер не вводится.

Чтобы решить эту проблему, вы должны либо везде использовать компонент по умолчанию componentModel, либо использовать spring и внедрить свой маппер.

PS То, как вы сейчас делаете отображение, на самом деле неэффективно.Вы можете просто добавить метод для отображения списков в mapper и вызывать его вместо использования потоков.

0 голосов
/ 01 октября 2018

вы можете использовать функцию map для потоков

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) для каждой записи в потоке, и поток впоследствии будет содержать все возвращаемые значения всех вызовов этого метода.так что в вашем случае: он преобразует каждую запись вашего списка, и после этого список будет содержать все преобразованные элементы

После этого вам нужно будет только снова собрать поток, поэтому у вас снова есть список


после вашего редактирования этот ответ больше не действителен, потому что вы изменили вопрос и уже использовали мой ответ.

На ваш дополнительный вопрос: для преобразования вложенных бинов в целом: до тех пор, пока структураиз вложенных bean-компонентов идентичны, mapstruct сделает работу из коробки.Если у вас есть различия, вы должны их комментировать.Я не могу сказать вам различия между вашим Ingrediant и IngrediantDTO, не видя эту часть вашего кода.

Вы можете попробовать посмотреть в сгенерированном классе и взглянуть на строку, которая вызывает исключение NullPointerException.Итак, у вас есть клей, в чем разница.А затем аннотируйте это в интерфейсе mapper

Для вложенных bean-компонентов в целом: 1) вы можете добавить интерфейсный метод "componentToIngredientDTO" в ваш mapper.и аннотировать различия (если необходимо) прямо к этому методу.MapStruct будет использовать его для метода recipeToRecipeDTO!2) вы можете комментировать вложенные различия.Например, @Mapping (source = "ингридиенты.nameA", target = "ингридиентыDTOSet.nameB")

Но вы задаете сейчас совершенно другой вопрос, чем в начале, и чтобы ответить на него, мне потребуется многоДополнительная информация.Поэтому я бы предпочел переосмыслить его на исходный вопрос.И спросите нового с достаточной информацией, если моих подсказок было недостаточно

...