I try to autowire my mapstruct mapper:
@Mapper(uses = {
A.class,
B.class,
C.class
})
public interface WindowDtoMapper {
WindowDtoMapper INSTANCE = Mappers.getMapper(WindowDtoMapper.class);
DetailedDto mapToDetailedDto(Window window);
ReadDto mapToReadDto(Window window);
}
This works:
return WindowDtoMapper.INSTANCE.mapToDetailedDto(window)
But WHY I can't use:
@RequiredArgsConstructor
public class AAA(){
private final WindowDtoMapper windowDtoMapper;
windowDtoMapper.mapToDetailedDto(window)
}
I get the following error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'pl.comp.window.application.mapper.WindowDtoMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1717) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1273)
Maybe I should stay with the first working solution? Is it bad solution or not?
By default, MapStruct generates ordinary Java classes, and that's all. Spring has no way of knowing that you want these to be beans.
As described in the MapStruct documentation, you can use @Mapper(componentModel = "spring") to have MapStruct put @Component on the classes it creates (you'll need to make sure that the package with the mappers is getting component-scanned).
Spent 70% of my day on this.
I am using Spring Tool Suite IDE, with Gradle.
I had two discoveries in sequence:
1. The Application could not start
The reason a bean will not be injected is due to mapping issues. In your mapper interface, you need to ensure that fields in source class and target class are taken care of (such as ignoring fields that should not be applied in target class).
For example:
@Mapping(target = "receiptSignature", ignore = true)
SalesTransactionEntity toEntity(SalesTransaction source);
How did I know what fields were causing this issue?
I headed to Gradle Tasks tab > ["My Project"] > clean + build
Navigate to Gradle Executions > Run Build > Run main tasks > Run tasks > :compileJava
if :compileJava has errors (red accents), Right-click > Show Failures. Explore the logs to see the fields not currently mapped (correctly).
2. The manual Gradle Build will compile without issue, no error, and even run the application, but the IDE refuses to start the application (claiming "a bean of type ... was required ...")
In this step, the following doc was recommended:
https://mapstruct.org/documentation/ide-support/
According to Eclipse IDE section, update the project's build file (build.gradle):
plugins {
id 'java'
id 'org.springframework.boot' version '4.0.2-SNAPSHOT'
id 'io.spring.dependency-management' version '1.1.7'
id("com.diffplug.eclipse.apt") version "4.4.1" // <-------------- ADD THIS
}
Of course you already have these in the rest of the build file:
ext {
mapstructVersion = "1.6.2"
}
dependencies {
// ...
implementation "org.mapstruct:mapstruct:${mapstructVersion}"
annotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"
testAnnotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"
compileOnly "org.mapstruct:mapstruct-processor:${mapstructVersion}"
// ...
}
Run the Refresh Gradle Project (Right-click on project > Gradle > Refresh Gradle Project)
Once the refresh is done, go to the root project's directory, run this:
./gradlew eclipseJdtApt eclipseFactorypath eclipseJdt
Once you get BUILD SUCCESSFUL, head back to the IDE.
Right-click on project > Properties > Java Compiler > Annotation Processing:
On this page select these checkboxes:
1. Enable Project Specific Settings
2. Enable Annotation Processing
3. Enable Processing in Editor
Apply and Close
Run the project now, the app should start again. (You may need to Refresh Gradle Project)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With