Реализация MapStruct не работает в веб-приложении Spring Boot

Я новичок в использовании Spring Boot и инструмента MapStruct.

Ранее проект (написанный другой командой с использованием этих технологий) не запускался. Затем я внес некоторые изменения в абстрактный класс Mapper, но теперь объект mapper становится пустым при запуске приложения.

Абстрактный класс картографа:

@Mapper(componentModel = "spring")
public abstract class UserAndEmployeeMapper {

    public UserAndEmployeeMapper INSTANCE = Mappers.getMapper( UserAndEmployeeMapper.class );

    @Mapping(source = "username", target = "name")
    @Mapping(source = "ssn", target = "ssn", defaultValue = "xxxxxx" )
    @Mapping(target = "salary", constant = "34.67")
    @Mapping(target = "dob", dateFormat = "dd/MM/yyyy", constant = "10/12/2002")
    public abstract Employee mapToEmployee(User user);

    public abstract List<Employee> mapToEmployee(List<User> users);

    @Mapping(source = "name", target = "username")
    public abstract User mapToUser(Employee employee);

    public abstract List<User> mapToUser(List<Employee> employees);

}

Класс LoginServiceImpl

@Service("loginService")
public class LoginServiceImpl implements LoginService{

    private static final AtomicLong counter = new AtomicLong();

    @Autowired
    private EmployeeDao employeeDao;

    private UserAndEmployeeMapper userAndEmployeeMapper;
...

}

pom.xml

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.plugin.version}</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${mapstruct.jdk8.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
</build>

После того, как я добавил @Autowired в LoginServiceImpl, приложение не запускается, и отображается следующий журнал ошибок

***************************
APPLICATION FAILED TO START
***************************

Description:

Field userAndEmployeeMapper in org.service.impl.LoginServiceImpl required a bean of type 'org.mapper.UserAndEmployeeMapper' that could not be found.


Action:

Consider defining a bean of type 'org.mapper.UserAndEmployeeMapper' in your configuration.

Какие-либо предложения ?


person Ankit    schedule 09.06.2017    source источник
comment
вы пробовали точно то же действие, о котором вам говорила ошибка весенней загрузки? Я имею в виду определение Spring bean-компонента UserAndEmployeeMapper. Похоже, что аннотация Mapper не работает как определение bean-компонента   -  person Normal    schedule 09.06.2017
comment
@Normal: объявление компонента поверх абстрактного класса UserAndEmployeeMapper дает тот же результат ошибки.   -  person Ankit    schedule 09.06.2017
comment
не заметил, это абстрактно, извините. Похоже, это очень похожая проблема stackoverflow.com/questions/32609755/   -  person Normal    schedule 09.06.2017
comment
Как вы вызываете приложение? Через maven / gradle или через IDE? Где твой Application класс?   -  person Filip    schedule 09.06.2017


Ответы (5)


Прежде всего, public UserAndEmployeeMapper INSTANCE = Mappers.getMapper( UserAndEmployeeMapper.class ); следует использовать только с моделью компонентов по умолчанию, иначе вы рискуете получить UserAndEmployeeMapper неправильно инициализированный.

UserAndEmployeeMapper в вашем LoginServiceImpl должен быть аннотирован @Autowired, иначе он не может быть введен Spring, и поэтому это null.

Я не знаю структуру вашего пакета. Если ваш класс приложения Spring Boot в пакете org, он получит UserAndEmployeeMapperImpl. В противном случае убедитесь, что конфигурация пружины соответствует UserAndEmployeeMapperImpl.

Если все вышеперечисленное настроено правильно, и вы запускаете приложение через IDE, убедитесь, что target/generated-sources или альтернатива Gradle является частью ваших источников и подобрана. Взгляните на поддержку IDE, чтобы убедиться, что вы правильно настроили обнаружение процессора аннотаций для IDE. Например, IntelliJ не будет вызывать процессор аннотаций MapStruct с вашей текущей настройкой, он не берет annotationProcessorPaths из компилятора maven.

person Filip    schedule 09.06.2017
comment
Вы говорите об этой компонентной модели @Mapper(componentModel = "spring")? - person Ankit; 12.06.2017
comment
Да я говорю об этом - person Filip; 12.06.2017
comment
Я изменил класс Mapper как интерфейс public interface UserAndEmployeeMapper. Теперь объект UserAndEmployeerMapper инициализируется в классе LoginServiceImpl. - person Ankit; 13.06.2017
comment
Это действительно странно, почему Spring не смог внедрить bean-компонент как абстрактный класс. Это должно было сработать. Хорошо, что вы решили свою проблему. Что касается spring, на самом деле рекомендуется использовать интерфейсы вместо абстрактных классов. - person Filip; 13.06.2017

Зависимость springfox-swagger2 загружает старую версию mapstruct после ее исключения и добавления конкретной версии зависимости mapstruct в pom.xml, она начала генерировать источники

<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.2.2</version>
<exclusions>
 <exclusion>
 <groupId>org.mapstruct</groupId>
  <artifactId>mapstruct</artifactId>
 </exclusion>
</exclusions>

Added below map struct dependency

<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.3.0.Beta1</version>

person skk    schedule 30.08.2018

Чтобы все классы сопоставления квалифицировались как Spring bean-компонент, добавьте следующий compilerArgs в свой maven-compiler-plugin.

<compilerArgs>
<arg>-Amapstruct.suppressGeneratorTimestamp=true</arg>
<arg>-Amapstruct.defaultComponentModel=spring</arg>
</compilerArgs> 

при использовании maven-processor-plugin добавьте следующие параметры

<options>                       
<mapstruct.suppressGeneratorTimestamp>
true
</mapstruct.suppressGeneratorTimestamp>                      
<mapstruct.defaultComponentModel>
spring
</mapstruct.defaultComponentModel>
</options>
person Minnow    schedule 23.09.2018

У меня сработало создание абстрактного класса в качестве интерфейса.

public interface UserAndEmployeeMapper {
person Ankit    schedule 19.06.2017
comment
для тех, у кого возникают проблемы с поиском того, где происходит сбой сопоставителя, также полезно установить unmappedTargetPolicy (например, @Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.WARN)) - person emrekgn; 25.05.2018

В моем случае я считаю, что ошибка возникла из-за неполного build.gradle.

До

dependencies {
    compile group: 'org.mapstruct', name: 'mapstruct-processor', version: '1.2.0.Final'
}

После

apply plugin: 'net.ltgt.apt'

dependencies {
    compile group: 'org.mapstruct', name: 'mapstruct-processor', version: '1.2.0.Final'
    compile group: 'org.mapstruct', name: 'mapstruct-jdk8', version: '1.2.0.Final'
    apt 'org.mapstruct:mapstruct-processor:1.2.0.Final'
}


buildscript {
    repositories {
        mavenCentral()
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath("net.ltgt.gradle:gradle-apt-plugin:0.9")
    }
}

Убедитесь, что вы правильно настроили build.gradle, как описано в документации.

person Chris Neve    schedule 30.09.2018