4

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.

  1. Answer By @Som
  2. Answer by @Gunnar

Edit 1

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

}

Edit 2

Package structure of the project

Package structure of the project

Please help, Thank you :)

Anshuman
  • 758
  • 7
  • 23

5 Answers5

3

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.

Marius Schmidt
  • 633
  • 6
  • 18
1

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>
Faramarz Afzali
  • 726
  • 1
  • 10
  • 24
  • Hey @Faramarz, thanks for looking into my issue. I added that part in `plugins` section of `pom.xml` but still getting the same error :( – Anshuman Oct 17 '21 at 08:23
  • @anshuman If you are using lombok you also need to add `lombok` and `lombok-mapstruct-binding` in the `annotationProcessorPaths` as well. In addition to that you also need to validate that the generated source are created. Check whether it works only with Maven as well – Filip Oct 19 '21 at 18:27
1

Added to plugins:

 <compilerArgs>
      <compilerArg>
             -Amapstruct.defaultComponentModel=spring
      </compilerArg>
 </compilerArgs>
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 06 '21 at 21:36
0

There are several suggestions you can investigate. First, check if there is @Component in the class generated by mvn.

Giang Phan
  • 534
  • 7
  • 15
0

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.

Jay Yadav
  • 236
  • 1
  • 2
  • 10