1

I am using clean architecture and have 3 modules: application -> details -> core
I'm trying to use Mapstruct to generate mappers in application & mappers in details. I have this mapper in application module

When I do mvn package in the parent pom to build all modules then mvn spring-boot:run -pl application when I send a request & hit the mapper method it throws this error

java.lang.Error: Unresolved compilation problems: 
        The import com.aura.app.http.rest.v1.institutions.requests cannot be resolved
        The import com.aura.app.http.rest.v1.institutions.responses cannot be resolved
        AppInstitutionMapper cannot be resolved to a type
        CreateInstitutionRequestDTO cannot be resolved to a type
        InstitutionResponseDTO cannot be resolved to a type
        The method from(Institution) of type AppInstitutionMapperImpl must override or implement a supertype method
        InstitutionResponseDTO cannot be resolved to a type
        InstitutionResponseDTO cannot be resolved

        at com.aura.app.http.rest.v1.institutions.mappers.AppInstitutionMapperImpl.<init>(AppInstitutionMapperImpl.java:3) ~[classes/:na]
        at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) ~[na:na]
        at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[na:na]
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:483) ~[na:na]
        at org.mapstruct.factory.Mappers.doGetMapper(Mappers.java:85) ~[mapstruct-1.6.3.jar:na]
        at org.mapstruct.factory.Mappers.getMapper(Mappers.java:69) ~[mapstruct-1.6.3.jar:na]
        at org.mapstruct.factory.Mappers.getMapper(Mappers.java:58) ~[mapstruct-1.6.3.jar:na]
        at com.aura.app.http.rest.v1.institutions.mappers.AppInstitutionMapper.<clinit>(AppInstitutionMapper.java:11) ~[classes/:na]
        at com.aura.app.http.rest.v1.institutions.InstitutionsController.createInstitution(InstitutionsController.java:51) ~[classes/:na]
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:565) ~[na:na]

AppInstitutionMapper.java:

package com.aura.app.http.rest.v1.institutions.mappers;

import com.aura.app.http.rest.v1.institutions.requests.CreateInstitutionRequestDTO;
import com.aura.app.http.rest.v1.institutions.responses.InstitutionResponseDTO;
import com.aura.core.institutions.entities.Institution;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface AppInstitutionMapper {
    AppInstitutionMapper INSTANCE = Mappers.getMapper(AppInstitutionMapper.class);

    Institution from(CreateInstitutionRequestDTO dto);

    InstitutionResponseDTO from(Institution institution);
}

This is the generated AppInstitutionMapperImpl.java:

package com.aura.app.http.rest.v1.institutions.mappers;

import com.aura.app.http.rest.v1.institutions.requests.CreateInstitutionRequestDTO;
import com.aura.app.http.rest.v1.institutions.responses.InstitutionResponseDTO;
import com.aura.core.institutions.entities.Institution;
import javax.annotation.processing.Generated;

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2025-11-07T00:04:30+0800",
    comments = "version: 1.6.3, compiler: javac, environment: Java 25 (Homebrew)"
)
public class AppInstitutionMapperImpl implements AppInstitutionMapper {

    @Override
    public Institution from(CreateInstitutionRequestDTO dto) {
        if ( dto == null ) {
            return null;
        }

        Institution.InstitutionBuilder institution = Institution.builder();

        institution.name( dto.getName() );
        institution.email( dto.getEmail() );
        institution.uen( dto.getUen() );
        institution.address( dto.getAddress() );
        institution.contactNumber( dto.getContactNumber() );

        return institution.build();
    }

    @Override
    public InstitutionResponseDTO from(Institution institution) {
        if ( institution == null ) {
            return null;
        }

        InstitutionResponseDTO.InstitutionResponseDTOBuilder institutionResponseDTO = InstitutionResponseDTO.builder();

        institutionResponseDTO.id( institution.id() );
        institutionResponseDTO.name( institution.name() );
        institutionResponseDTO.email( institution.email() );
        institutionResponseDTO.uen( institution.uen() );
        institutionResponseDTO.address( institution.address() );
        institutionResponseDTO.contactNumber( institution.contactNumber() );

        return institutionResponseDTO.build();
    }
}

The CreateInstitutionRequestDTO exists in the correct package, likewise for Institution .

In my parent pom I list out my modules like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0          http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.aura</groupId>
    <artifactId>parent</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>
    <name>Aura Parent</name>
    <description>Parent POM for Aura</description>
    <modules>
        <module>core</module>
        <module>details</module>
        <module>application</module>
    </modules>
    <properties>
        <java.version>24</java.version>
        <maven.compiler.source>24</maven.compiler.source>
        <maven.compiler.target>24</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- Dependency versions -->
        <spring.boot.version>3.5.6</spring.boot.version>
        <lombok.version>1.18.38</lombok.version>
        <mapstruct.version>1.6.3</mapstruct.version>
        <lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
        <keycloak-admin-client.version>26.0.7</keycloak-admin-client.version>
        <hibernate-envers.version>6.6.5.Final</hibernate-envers.version>
        <springdoc-openapi-stgarter-webmvc-ui.version>2.8.8</springdoc-openapi-stgarter-webmvc-ui.version>
        <spring-boot-starter-data-jpa.version>3.4.2</spring-boot-starter-data-jpa.version>
        <jakarta-validation-api.version>3.0.2</jakarta-validation-api.version>
        <archunit.version>1.4.1</archunit.version>
        <junit.version>4.13.2</junit.version>
        <slf4j.version>2.0.17</slf4j.version>
        <!--        used for liquibase profile, TODO: check if needed-->
        <liquibase.version>4.27.0</liquibase.version>
        <liquibase-maven-plugin.version>4.27.0</liquibase-maven-plugin.version>
        <liquibase-hibernate6.version>4.23.0</liquibase-hibernate6.version>
        <hibernate-validation.version>8.0.2.Final</hibernate-validation.version>
        <postgresql.version>42.7.5</postgresql.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <!-- Spring Boot BOM, only imports the SB dependency versioning -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

and in the application module, I import the dependencies from core & details module.

<?xml version="1.0"?>
<project 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"
         xmlns="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.aura</groupId>
        <artifactId>parent</artifactId>
        <version>1.0.0</version>
    </parent>
    <packaging>jar</packaging>
    <artifactId>application</artifactId>
    <version>1.0.0</version>
    <description>aura application containing app runtime and configurations</description>
    <dependencies>
        <dependency>
            <groupId>com.aura</groupId>
            <artifactId>core</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.aura</groupId>
            <artifactId>details</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- Liquibase -->
        <dependency>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-core</artifactId>
            <version>${liquibase.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>${springdoc-openapi-stgarter-webmvc-ui.version}</version>
        </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-admin-client</artifactId>
            <version>${keycloak-admin-client.version}</version>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${mapstruct.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-contract-shade</artifactId>
            <version>4.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <profiles>
        <profile>
            <id>generate-db-changelog</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.liquibase</groupId>
                        <artifactId>liquibase-maven-plugin</artifactId>
                        <version>${liquibase-maven-plugin.version}</version>
                        <configuration>
                            <propertyFile>src/main/resources/db/liquibase.properties</propertyFile>
                        </configuration>
                        <dependencies>
                            <dependency>
                                <groupId>org.liquibase.ext</groupId>
                                <artifactId>liquibase-hibernate6</artifactId>
                                <version>${liquibase-hibernate6.version}</version>
                            </dependency>
                            <!-- Add this dependency -->
                            <dependency>
                                <groupId>jakarta.validation</groupId>
                                <artifactId>jakarta.validation-api</artifactId>
                                <version>${jakarta-validation-api.version}</version>
                            </dependency>
                            <!-- Also add the implementation -->
                            <dependency>
                                <groupId>org.hibernate.validator</groupId>
                                <artifactId>hibernate-validator</artifactId>
                                <version>${hibernate-validation.version}</version>
                            </dependency>
                            <!-- Include your PostgreSQL driver -->
                            <dependency>
                                <groupId>org.postgresql</groupId>
                                <artifactId>postgresql</artifactId>
                                <version>${postgresql.version}</version>
                            </dependency>
                            <!-- Add your database driver dependency here -->

                        </dependencies>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
    <build>
        <finalName>report-api</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <release>${java.version}</release>
                    <!-- processes annotations -->
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${mapstruct.version}</version>
                        </path>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>${lombok.version}</version>
                        </path>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok-mapstruct-binding</artifactId>
                            <version>${lombok-mapstruct-binding.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring.boot.version}</version>
                <configuration>
                    <mainClass>com.aura.app.Application</mainClass>
                    <layout>JAR</layout>
                    <excludes>
                        <!-- Exclude Lombok as it's not needed at runtime -->
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                    <!-- Force unpacking of module dependencies -->
                    <requiresUnpack>
                        <dependency>
                            <groupId>com.aura</groupId>
                            <artifactId>core</artifactId>
                        </dependency>
                        <dependency>
                            <groupId>com.aura</groupId>
                            <artifactId>details</artifactId>
                        </dependency>
                    </requiresUnpack>
                    <!-- This ensures classes are included in the JAR properly -->
                    <classifier>exec</classifier>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Since the annotations for mapper are successfully being processed in both details & application module, I do not know why when the application jar is run at runtime, the generated mapper implementation cannot find any of the other classes.

more details when i look into the jar of application module to check if the relevant classes are there i find that the classes are all there

the details module dependency is in classpath as a jar

jar tf application/target/report-api.jar | grep /details
> BOOT-INF/lib/details-1.0.0.jar

the mapper modules seem to be there too

jar tf application/target/report-api.jar | grep /mapper 
> BOOT-INF/classes/com/aura/app/http/rest/v1/institutions/mappers/
BOOT-INF/classes/com/aura/app/http/rest/v1/institutions/mappers/AppInstitutionMapper.class
BOOT-INF/classes/com/aura/app/http/rest/v1/institutions/mappers/AppInstitutionMapperImpl.class
BOOT-INF/classes/com/aura/app/http/rest/v1/institutions/mappers/UserMapper.class

the DTO class which the AppInstitutionMapperImpl could not find is also there

jar tf application/target/report-api.jar | grep /response
BOOT-INF/classes/com/aura/app/http/rest/v1/institutions/responses/
BOOT-INF/classes/com/aura/app/http/rest/v1/institutions/responses/InstitutionResponseDTO$InstitutionResponseDTOBuilder.class
BOOT-INF/classes/com/aura/app/http/rest/v1/institutions/responses/InstitutionResponseDTO.class

this is weird because the mapper class could not import the DTO class at runtime, however the DTO class is just literally in the same jar

2
  • 1
    Just a note: Since you're using Spring Boot, we recommend using the related dpedency injection. mapstruct.org/documentation/stable/reference/html/… It probably won't fix your issue, but it's good practice and certainly preferable. Commented Nov 6 at 21:51
  • @Ray Thanks for the suggestion. i tried it just in case and yea you're right, it did not work Commented Nov 7 at 7:13

2 Answers 2

1

Have you tried to swap mapstruct-processor and lombok? Like this

<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>

Order might be important

Sign up to request clarification or add additional context in comments.

4 Comments

hey @max, i've tried it already and it did not work.
I understood. Need to add <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${mapstruct.version}</version> </dependency> to dependency
it worked! didnt know i need to import teh annotation processs in the actual runtime dependency. however im getting a similar issue in my applications module im using a class in the details module called InstitutionRepositoryImplm this class uses a InstitutionMapper also in details module. now this mapper throws the same error ``` java.lang.Error: Unresolved compilation problems: The import com.aura.details.tables cannot be resolved InstitutionMapper cannot be resolved to a type InstitutionTable cannot be resolved to a type ``` I added mapstruct-processor to det
i solved the subsequent problem by building a standalone fat jar with with spring-boot-maven-plugin:repackage goal. I'm suspecting that the mapper in the details module could not import from core module somehow when not packaged as a fat jar.
0

Thanks @Max for solving this. I had to use spring-boot-mvn-plugin repackage goal to repackage the multiple modules to a standalone fat jar. this allowed the mapper classes to be able to import classes from other modules without errors

2 Comments

If this is the solution, it indicates something is "off" with your project setup. The processor shouldn't be a runtime dependency. It doesn't add anything beyond the build time.
you were right. i removed the processor from the runtime dependencies and it still works. It was just the repackaging build step that i needed

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.