Reputation: 803
I was following this tutorial about the partial update. As instructed, I created mapper interface with proper annotations.
Here's the mapper
@Mapper(componentModel = "spring")
public interface UserEntityMapper {
@Mapping(source = "password", target = "password")
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
void updatePasswordFromDTO(PasswordResetRequest dto, @MappingTarget User entity);
}
As per the tutorial, @Mapper(componentModel = "spring")
generates mapper as a Spring bean that can be retrieved via @Autowired
.
But when I tried to do same in my service layer class
,
@Service
@Transactional
public class AccountServiceImpl implements IAccountService {
...
@Autowired
private UserEntityMapper userMapper;
...
}
I get this error, my application failed to start.
***************************
APPLICATION FAILED TO START
***************************
Description:
Field userMapper in com.application.services.AccountServiceImpl required a bean of type 'com.application.mappers.UserEntityMapper' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.application.mappers.UserEntityMapper' in your configuration.
And at last, here's pom.xml
of my project.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.myproject</groupId>
<artifactId>myproject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>authentication-template</name>
<description>Description</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-freemarker -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.2.Final</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
I also tried these different solution, but same result.
Here's @SpringBootApplication
file.
@SpringBootApplication
@PropertySources(value = {
@PropertySource("classpath:mail.properties"),
@PropertySource("classpath:messages.properties"),
@PropertySource("classpath:security.properties")
})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Package structure of the project
Please help, Thank you :)
Upvotes: 4
Views: 14230
Reputation: 25
I've had the same problem with all correct pom configurations etc. The error came up randomly.
What I did was, I had a bean mapper class
public interface MyBeanMapper
But I autowired it like this
@Autowired
MyBeanMapperImpl beanMapper;
And the error was fixed. mapstruct generates the impl class, so autowired that one.
Upvotes: 0
Reputation: 181
For folks who still have the problem, You need to match versions of spring and mapstruct.
You can find what versions worked for me under. (Note: I'm using build.gradle, you should to)
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor "org.mapstruct:mapstruct-processor:$mapstruct_version"
implementation "org.mapstruct:mapstruct:$mapstruct_version"
in gradle.properties:
spring_boot_version=3.2.1
mapstruct_version=1.5.5.Final
lombok_version=1.18.12
Upvotes: 0
Reputation: 803
I know, I'm too late. Apologies for the delay in responding to the question. Let's dive into configuring MapStruct.
The actual issue was with configuration. I follow the following steps to successfully configure MapStruct with Spring Boot.
First add mapstruct
dependency in pom.xml
.
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<scope>provided</scope> <!-- Required -->
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>
Note: Make sure
<scope>provided</scope>
is set forlombok
. Without that@Builder
was not working for me.
Since mapstruct
requires annotation processing, so we need to add the plugin into our pom.xml
.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
Note:
lombok-mapstruct-binding
is required forLombok
andMapstruct
, to allow them to cooperate.
Make sure annotation processing is enable in you IDE. You can check these links for IntelliJ Idea and Eclipse/STS
Once done, you can create mapper interface
.
import static org.mapstruct.MappingConstants.ComponentModel.SPRING;
@Mapper(componentModel = SPRING)
public interface UserMapper {
UserModel dtoToModel(UserDTO userDto);
}
Then the mapper
can be easily @Autowired
.
@Service
public class UserService {
private final UserMapper userMapper;
@Autowired
public UserService(UserMapper userMapper) {
this.userMapper= userMapper;
}
// Business logic
}
I hope this will help. Thanks and Regards.
Upvotes: 2
Reputation: 440
I was able to make this work follow these steps, also I was using lombok & mapstruct together with maven
Step 1: Add lombok & mapstruct dependency
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
Step 2: Since both mapstruct & lombok are based on annotation processing. Add config in maven build plugin section, you don't need this step if using IntelliJ IDEA, by enabling annotation processiong in IDE settings.
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass></mainClass> <!-- FQN of class with main method
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
Step 3: Mapper class should have be annotated with @Mapper annotation
@Mapper(componentModel = "spring")
@Service
public interface PersonMapper {
// add appropriate mapper methods
}
Step 3: Update maven project & run
mvn clean install
Run the application. Inside target folder there will be PersonMapperImpl.java generated by mapstruct.
Upvotes: 1
Reputation: 141
Added to plugins:
<compilerArgs>
<compilerArg>
-Amapstruct.defaultComponentModel=spring
</compilerArg>
</compilerArgs>
Upvotes: 2
Reputation: 663
If the pom.xml you provided is the latest version, I think you are missing the step, that actually generates the MapStruct mappers from your definitions. You need to define it as part of the build setup as stated here https://mapstruct.org/documentation/installation/
You need to add that part to the build - plugins section
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source> <!-- depending on your project -->
<target>1.8</target> <!-- depending on your project -->
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<!-- other annotation processors -->
</annotationProcessorPaths>
</configuration>
</plugin>
Also check your target/generated folders if the mappers are successfully generated
EDIT:
after running the build, please verify, that your maven build output folder target/generated-sources actually contains some generated mappers for MapStruct. Also observe your maven build log output for hints, that MapStruct mappers are generated.
IF no mappers are generated, something in your build setup is fishy and we'd need a closer look into your log output.
But IF mappers are generated, you should check, that that have the @Component annotation of spring AND that they are in a package, that is on Springs scan-path for beans.
Upvotes: 3
Reputation: 795
I have the dependency like below, all the things are Ok.
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.2.Final</version>
</dependency>
And in part of plugins.
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.4.2.Final</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
Upvotes: 2
Reputation: 544
There are several suggestions you can investigate. First, check if there is @Component in the class generated by mvn.
Upvotes: 0