Mapstruct Dependency Injection funktioniert nicht mit Spring

DrPils

Bekanntes Mitglied
Hi

Normalerweise hat es bisher immer gereicht die Mapper mit @Mapper(componentModel = "spring") zu annotieren.
Aber jetzt wird der Mapper nicht als Bean genommen.
Bekomme beim builden folgenden Fehler: Parameter 1 of constructor in service.PostServiceImpl required a bean of type 'mapper.PostMapper' that could not be found.

mapper:
Java:
@Mapper(componentModel = "spring")
abstract class PostMapper {

    abstract fun requestToEntity(postRequest: PostRequest): Post

    abstract fun entityToResponse(post: Post): PostResponse

    @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
    abstract fun updateEntityFromResponse(postResponse: PostResponse, @MappingTarget post: Post): Post
}


pom.xml:
XML:
<?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"
    <!--...-->
    <properties>
        <java.version>17</java.version>
        <kotlin.version>1.6.21</kotlin.version>
        <org.mapstruct.version>1.5.2.Final</org.mapstruct.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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-kotlin</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-reflect</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib-jdk8</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${org.mapstruct.version}</version>
        </dependency>
    </dependencies>

    <build>
        <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
        <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.jetbrains.kotlin</groupId>
                <artifactId>kotlin-maven-plugin</artifactId>
                <configuration>
                    <args>
                        <arg>-Xjsr305=strict</arg>
                    </args>
                    <compilerPlugins>
                        <plugin>spring</plugin>
                        <plugin>jpa</plugin>
                        <plugin>all-open</plugin>
                    </compilerPlugins>
                    <pluginOptions>
                        <option>all-open:annotation=javax.persistence.Entity</option>
                        <option>all-open:annotation=javax.persistence.MappedSuperclass</option>
                        <option>all-open:annotation=javax.persistence.Embeddable</option>
                    </pluginOptions>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.jetbrains.kotlin</groupId>
                        <artifactId>kotlin-maven-allopen</artifactId>
                        <version>${kotlin.version}</version>
                    </dependency>
                    <dependency>
                        <groupId>org.jetbrains.kotlin</groupId>
                        <artifactId>kotlin-maven-noarg</artifactId>
                        <version>${kotlin.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java.version}</source> <!-- depending on your project -->
                    <target>${java.version}</target> <!-- 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>

</project>
 

DrPils

Bekanntes Mitglied
Wie sehen denn die generierten Klassen aus?
Die Klasse wird nicht generiert
mvn install, bricht hier ab

Code:
-------------------------------------------------------------------------------
Test set: blogapi.BlogApiApplicationTests
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 2.697 s <<< FAILURE! - in blogapi.BlogApiApplicationTests
contextLoads  Time elapsed: 0 s  <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'postController' defined in file [C:\Users\xxx\Repositories\blog-api\target\classes\blogapi\controller\PostController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'postServiceImpl' defined in file [C:\Users\xxx\Repositories\blog-api\target\classes\blogapi\service\PostServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'blogapi.mapper.PostMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'postServiceImpl' defined in file [C:\Users\xxx\Repositories\blog-api\target\classes\blogapi\service\PostServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'blogapi.mapper.PostMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'blogapi.mapper.PostMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
 

KonradN

Super-Moderator
Mitarbeiter
Die Klasse wird nicht generiert
mvn install, bricht hier ab
Nur zum Verständnis: mvn install bricht beim test ab. Das bedeutet aber, dass die Generierungen und Übersetzungen alle gelaufen sind!

Daher: generate-sources, compile , generate-test-sources und test-compile sind erfolgreich gelaufen und die Ergebnisse sind alle im target Verzeichnis zu finden.

Daher kannst Du sehr wohl schauen, wie die fertigen Klassen aussehen.

Wenn Du mit der Struktur im target Verzeichnis nicht klar kommst und nur im fertigen Resultat Dinge findest, dann kannst Du Maven auch sagen, dass er den Test nicht machen soll: -Dmaven.test.skip oder -DskipTests (Erstes überspringt auch das bauen der Tests, letzteres verhindert nur die Ausführung. Die Übersetzung sollte immer laufen, daher ist das letztere das, was ich nutzen würde.)

Oder - was ich immer allen nahelege: Sag dem surfire plugin, dass es bei fehlgeschlagenen Tests nicht stoppen soll:
Code:
            <!--Test execution -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${maven.surfire.plugin}</version>
                <configuration>
                    <testFailureIgnore>true</testFailureIgnore>
                </configuration>
            </plugin>
Dann werden die Tests ausgeführt, so ein Fehler führt aber nicht zum Abbruch so dass man am Ende sein jar oder war hat.
(Dann kann ein Anfänger mit Unit Tests "spielend" beginnen ohne dass seine gewohnten Abläufe behindert werden. Dann kann auch mal der Punkt sein, dass die "blöden Unit Tests" teilweise Fehler melden weil man was geändert hat oder so ... )
 

Avalon

Bekanntes Mitglied
Ich habe meine Mapstruct Einträge mal mit Deiner pom verglichen und denke, die pom kann man als Fehlerquelle ausschließen. Die sind völlig identisch. Ich würde bei den Konstruktoren anfangen zu suchen, wie angegeben. Es muss ja einen Grund haben, warum Mapstruct die Parameter nicht mappen kann. Using Constructors
 
Zuletzt bearbeitet:

DrPils

Bekanntes Mitglied
Ich habe meine Mapstruct Einträge mal mit Deiner pom verglichen und denke, die pom kann man als Fehlerquelle ausschließen. Die sind völlig identisch. Ich würde bei den Konstruktoren anfangen zu suchen, wie angegeben. Es muss ja einen Grund haben, warum Mapstruct die Parameter nicht mappen kann. Using Constructors
An den Konstruktoren wird es nicht liegen. Der Fehler in den Konstruktoren ist ja nur darauf zurückzuführen dass keine Bean für den Mapper gefunden wird.
PostService erwartet diesen Mapper im Konstruktor und der PostController wiederum den PostService.
Das Problem ist auch nicht das Mappstruct was nicht mappen kann (dann würde ich ja auch den entsprechenden Fehler von Mapstruct bekommen), sondern dass mir keine Implementation vom Mapper erstellt wird.
 

LimDul

Top Contributor
Wie baust du? Ich würde mal einen Maven clean install auf der Console machen um zu sehen, was passiert. Zumindest in Eclipse hab ich das Problem, dass Eclipse nicht immer sauber erkennt, wann es sowas neu bauen muss.
 

DrPils

Bekanntes Mitglied
Bis jetzt immer mit den Maven Tools in IntelliJ. Maven für die Konsole bekomme ich auf meinem Rechner nicht zum laufen.
Bekomme da den Fehler
Code:
The JAVA_HOME environment variable is not defined correctly,
this environment variable is needed to run this program.
Wenn ich java -version eingebe scheint alles ok zu sein
Code:
java version "1.8.0_341"
Java(TM) SE Runtime Environment (build 1.8.0_341-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.341-b10, mixed mode)

Aber kann das echt ein Unterschied machen, ob ich es jetzt mit IntelliJ mache, oder mit der Konsole?
 

LimDul

Top Contributor
Dann mach mal einen Maven Build mit Clean aus intellij - sollte auch gehen. Das Clean ist vermutlich nur wichtig.

Alternativ die Umgebungsvariable JAVA_HOME Home auf das Verzeichnis setzen, wo Java installiert ist.
 

KonradN

Super-Moderator
Mitarbeiter
Das passt aber doch nicht! Der java -version Aufruf hat ein 1,8er java gezeigt, aber die JAVA_HOME Variable hast Du auf ein 17er Java gesetzt.
 

LimDul

Top Contributor
Ansonsten findet sich hier auch noch was bzgl. Maven + Intellij: https://mapstruct.org/documentation/ide-support/

For example, if you use the way of Maven configuration that is proposed in our documentation using annotationProcessorPaths in the maven-compiler-plugin, then you need to configure IntelliJ manually until the feature request IDEA-150621 is implemented. An alternative is to add the mapstruct-processor as a project dependency with <optional>true</optional> in your pom.xml, which should then be picked up automatically again.
 

DrPils

Bekanntes Mitglied
Das passt aber doch nicht! Der java -version Aufruf hat ein 1,8er java gezeigt, aber die JAVA_HOME Variable hast Du auf ein 17er Java gesetzt.
Stimmt passt nicht wirklich, verstehe ich aber auch nicht ...
Ansonsten findet sich hier auch noch was bzgl. Maven + Intellij: https://mapstruct.org/documentation/ide-support/
Ok habe die dependency inkl <optional>true</optional> hinzugefügt. Ergebnis bleibt leider unverändert.

Jetzt habe ich mir Maven mal im WSL Ubuntu auf meinem Rechner installiert und konnte so manuell (also über das Terminal) clean install ausführen. Ergebnis unverändert... Klasse wird nicht generiert
 

Neue Themen


Oben