Reputation: 1795
I have next classes:
Mapper
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:
@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;
}
}
And method from spring service class where I use this mapping:
@Transactional
public DeviceTokensDTO storeToken(String tokenId, UserOSType userOsType) {
DeviceTokens deviceTokens = new DeviceTokens(tokenId, userOsType);
DeviceTokens newDevice = deviceTokensRepository.save(deviceTokens);
return DeviceTokensMapper.INSTANCE.toDeviceTokensDTO(newDevice);
}
When I run above method I see next exception:
ERROR [dispatcherServlet]:? - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler processing failed; nested exception is java.lang.ExceptionInInitializerError] with root cause java.lang.ClassNotFoundException: dto.DeviceTokensMapperImpl
So why mapper require implementation class? Could please someone advise? Thanks.
Upvotes: 21
Views: 56618
Reputation: 748
In your Mapper class, use @Mapper(componentModel = "spring")
and to generate Impl classes using mapstruct, you need both of following dependencies.
<!-- Dependencies for Mapper -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
Upvotes: 3
Reputation: 1955
If you are using Project lombok along with mapstruct then you will need to configure both under maven compiler plugin, as both of them generate source at compile time.
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
Upvotes: 5
Reputation: 793
In your build.gradle add
compile group: 'org.mapstruct',name: 'mapstruct-jdk8',version: 1.2.0.Final
annotationProcessor group: 'org.mapstruct',name: 'mapstruct-processor',version: 1.2.0.Final
Enable annotation Processing in your setting
Bonus : add plugin intellij for mapstruct
Upvotes: 2
Reputation: 371
if you use maven, you need to add mapstruct-processor dependency as follows:
<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>
Upvotes: 34
Reputation: 111
I have met the same problem in my project with gradle. And I replace the build.gradel
from
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'
Then sh build clean&build. It works now!
Upvotes: 4
Reputation: 300
I ran into this problem because I didn't run ./gradlew clean build
(gradlew.bat
for Windows) after creating/editing the mapper class or related classes.
Also, something I found was useful is ./gradlew clean build -x test
works, but doesn't run all your test, which was a lot in my case.
Upvotes: 0
Reputation: 1133
In my case I had wrapped <plugin>
within <pluginManagement>
tags to workaround an eclipse (Mars) bug as follows
<pluginManagement>
<plugin> ... </plugin>
</pluginManagement>
Removing <pluginManagement>
tags fixed it for me.
Upvotes: 1
Reputation: 3001
Are you using Maven? If yes, then most probably you have missed the mapstruct-processor configuration under the maven compiler plugin.
The proper configuration is as follows:
<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>
Upvotes: 6
Reputation: 171
Do you have both mapstruct-processor-xx and mapstruct-xx libraries included in your project?
I had the same problem and I realized that I forgot to include mapstruct-processor-xx.
Upvotes: 13
Reputation: 18970
MapStruct generates code at compile time, and the call to Mappers.getMapper(DeviceTokensMapper.class);
will look for the generated implementation of the mapper interface. For some reason it seems to be missing in your deployment unit (WAR etc.).
Btw. when working with Spring as your DI container, you can use @Mapper(componentModel="spring")
and you will be able to obtain mapper instances via dependency injection instead of using the Mappers
factory.
Upvotes: 20