MapStruct требует класс Impl

у меня есть следующие классы:

маппер

public interface DeviceTokensMapper {

    DeviceTokensMapper INSTANCE = Mappers.getMapper(DeviceTokensMapper.class);

    @Mappings({
            @Mapping(source = "tokenName", target = "tokenName"),
            @Mapping(source = "userOsType", target = "osType"),
    })

    DeviceTokensDTO toDeviceTokensDTO(DeviceTokens deviceTokens);
}

сущности:

@Entity
public class DeviceTokens {

    @Id
    @Column(name="token_name", nullable = false)
    private String tokenName;

    @Column(name = "os", nullable = false)
    @Enumerated
    private UserOSType userOsType;

    public DeviceTokens() {}

    public DeviceTokens(String tokenName, UserOSType userOSType) {
        this.tokenName = tokenName;
        this.userOsType = userOSType;
    }

    public String getTokenName() {
        return tokenName;
    }

    public void setTokenName(String tokenName) {
        this.tokenName = tokenName;
    }

    public UserOSType getUserOsType() {
        return userOsType;
    }

    public void setUserOsType(UserOSType userOsType) {
        this.userOsType = userOsType;
    }
}

DTO:

public class DeviceTokensDTO {

    private String tokenName;

    private UserOSType osType;

    public DeviceTokensDTO() {}

    public DeviceTokensDTO(String tokenName, UserOSType osType) {
        this.tokenName = tokenName;
        this.osType = osType;
    }

    public UserOSType getOsType() {
        return osType;
    }

    public void setOsType(UserOSType osType) {
        this.osType = osType;
    }

    public String getTokenName() {
        return tokenName;
    }

    public void setTokenName(String tokenName) {
        this.tokenName = tokenName;
    }
}

и способ от источников класс, где я использую это сопоставление:

@Transactional
public DeviceTokensDTO storeToken(String tokenId, UserOSType userOsType) {
    DeviceTokens deviceTokens = new DeviceTokens(tokenId, userOsType);
    DeviceTokens newDevice = deviceTokensRepository.save(deviceTokens);

    return DeviceTokensMapper.INSTANCE.toDeviceTokensDTO(newDevice);
}

когда я запускаю выше метод, я вижу следующее исключение:

ошибка [dispatcherServlet]:? - Сервлет.обслуживания() для сервлета [dispatcherServlet] в контексте с path [] бросил обработчик исключений ошибка обработки; вложенное исключение Ява.ленг.ExceptionInInitializerError] с первопричиной Ява.ленг.ClassNotFoundException: dto.DeviceTokensMapperImpl

так почему mapper требует класса реализации? Может, кто-нибудь посоветует? Спасибо.

7 ответов


MapStruct генерирует код во время компиляции, и вызов Mappers.getMapper(DeviceTokensMapper.class); будет искать сгенерированную реализацию интерфейса mapper. По какой-то причине он отсутствует в вашем подразделении развертывания (война и т. д.).

кстати. при работе с Spring в качестве контейнера DI вы можете использовать @Mapper(componentModel="spring") и вы сможете получить экземпляры mapper с помощью инъекции зависимостей вместо использования Mappers фабрики.


У вас есть как mapstruct-processor-xx и mapstruct-xx библиотеки, включенные в ваш проект?

У меня была такая же проблема, и я понял, что забыл включить mapstruct-processor-xx.


Если вы используете maven, вам нужно добавить зависимость mapstruct-processor следующим образом:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-jdk8</artifactId>
    <version>1.2.0.Final</version>
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.2.0.Final</version>
</dependency>

вы используете Maven? Если да, то, скорее всего, вы пропустили конфигурацию mapstruct-processor под плагином компилятора maven.

правильная конфигурация выглядит следующим образом:

<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
        <version>${org.mapstruct.version}</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.6</source> <!-- or higher, depending on your project -->
                <target>1.6</target> <!-- or higher, depending on your project -->
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

в моем случае я завернул <plugin> внутри <pluginManagement> теги для обхода ошибки eclipse (Mars) следующим образом

<pluginManagement>
 <plugin> ... </plugin> 
</pluginManagement>

удаление <pluginManagement> теги исправили это для меня.


я столкнулся с той же проблемой в моем проекте с gradle. И я заменяю build.gradel от

compile 'org.mapstruct:mapstruct:1.2.0.CR2'

to

compile 'org.mapstruct:mapstruct-jdk8:1.1.0.Final'
compile 'org.mapstruct:mapstruct-processor:1.1.0.Final'

затем sh build clean & build. Теперь работает!


я столкнулся с этой проблемой, потому что я не запустить ./gradlew clean build (gradlew.bat для Windows) после создания / редактирования класса mapper или связанных классов.

кроме того, то, что я нашел, было полезно ./gradlew clean build -x test работает, но не запускает весь ваш тест, что было много в моем случае.