@MAPSTRUCT. No property named "packaging" exists in source parameter(s)
Asked Answered
S

12

33

I am writing an MVC REST application with Spring Boot and Hibernate. I decided to do DTO mapping using MAPSTRUCT. It seems that I did everything according to the guide, but an error is issued. What is the problem, I cannot understand. There is very little information on forums and on google.

P.S. At first I thought that the problem was in Lombok, so I removed Lombok and manually assigned getters / setters. Then the problem was not solved. I took both in the Drink class and in the DrinkDTO I prescribed getters / setters. It still didn't help.

Drink:

@Entity
@Table(name = "drink", schema = "public")
public class Drink {

    public Drink() { // Constructor for Hibernate

    }


    // Fields
    //
    private @Id
    @GeneratedValue
    Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "price")
    private float price;

    @Column(name = "about")
    private String about;

    @Column(name = "is_deleted")
    private boolean isDeleted;

    // Relationships
    //
    @ManyToOne
    @JoinColumn(name = "packaging_id")
    private Packaging packaging;

    @ManyToOne
    @JoinColumn(name = "manufacturer_id")
    private Manufacturer manufacturer;

    @ManyToOne
    @JoinColumn(name = "country_id")
    private Countries countries;
}

DrinkDTO:

public class DrinkDTO {

    // Fields
    //
    private String drinkName;

    private float drinkPrice;

    private String drinkAbout;

    private Packaging drinkPackaging;

    private Manufacturer drinkManufacturer;

    private Countries drinkCountries;


    // Getters and Setters
    //
    public String getDrinkName() {
        return drinkName;
    }

    public void setDrinkName(String drinkName) {
        this.drinkName = drinkName;
    }

    public float getDrinkPrice() {
        return drinkPrice;
    }

    public void setDrinkPrice(float drinkPrice) {
        this.drinkPrice = drinkPrice;
    }

    public String getDrinkAbout() {
        return drinkAbout;
    }

    public void setDrinkAbout(String drinkAbout) {
        this.drinkAbout = drinkAbout;
    }

    public Packaging getDrinkPackaging() {
        return drinkPackaging;
    }

    public void setDrinkPackaging(Packaging drinkPackaging) {
        this.drinkPackaging = drinkPackaging;
    }

    public Manufacturer getDrinkManufacturer() {
        return drinkManufacturer;
    }

    public void setDrinkManufacturer(Manufacturer drinkManufacturer) {
        this.drinkManufacturer = drinkManufacturer;
    }

    public Countries getDrinkCountries() {
        return drinkCountries;
    }

    public void setDrinkCountries(Countries drinkCountries) {
        this.drinkCountries = drinkCountries;
    }

    // toSTRING
    @Override
    public String toString() {
        return "DrinkDTO{" +
                "drinkName='" + drinkName + '\'' +
                ", drinkPrice=" + drinkPrice +
                ", drinkAbout='" + drinkAbout + '\'' +
                ", drinkPackaging=" + drinkPackaging +
                ", drinkManufacturer=" + drinkManufacturer +
                ", drinkCountries=" + drinkCountries +
                '}';
    }

CustomerController:

@GetMapping("/drinks")
    List<DrinkDTO> getAllDrinks(){
        return DrinkMapper.INSTANCE.drinksToDrinksDTO(customerService.getAllDrinks());
    }

BUILD.GRADLE

// Mapstruct
    implementation 'org.mapstruct:mapstruct:1.3.1.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.3.1.Final'

DrinkMapper:

@Mapper
public interface DrinkMapper {

    DrinkMapper INSTANCE = Mappers.getMapper(DrinkMapper.class);

    @Mapping(source = "name", target = "drinkName")
    @Mapping(source = "price", target = "drinkPrice")
    @Mapping(source = "about", target = "drinkAbout")
    @Mapping(source = "packaging", target = "drinkPackaging")
    @Mapping(source = "manufacturer", target = "drinkManufacturer")
    @Mapping(source = "countries", target = "drinkCountries")
    DrinkDTO drinkToDrinkDTO(Drink drink);

    @Mapping(source = "drinkName", target = "name")
    @Mapping(source = "drinkPrice", target = "price")
    @Mapping(source = "drinkAbout", target = "about")
    @Mapping(source = "drinkPackaging", target = "packaging")
    @Mapping(source = "manufacturer", target = "drinkManufacturer")
    @Mapping(source = "countries", target = "drinkCountries")
    Drink drinkDTOtoDrink(DrinkDTO drinkDTO);

    @Mapping(source = "name", target = "drinkName")
    @Mapping(source = "price", target = "drinkPrice")
    @Mapping(source = "about", target = "drinkAbout")
    @Mapping(source = "packaging", target = "drinkPackaging")
    @Mapping(source = "manufacturer", target = "drinkManufacturer")
    @Mapping(source = "countries", target = "drinkCountries")
    List<DrinkDTO> drinksToDrinksDTO(List<Drink> drinks);
}

ERRORS: enter image description here

Siouan answered 22/7, 2020 at 13:7 Comment(4)
Did you use mvn -clean install to generate the classes? Could you check that what does you have under target/generated-sources ?Easement
Not. I do not use. How can I see this?Siouan
You don't need separate @Mappings on method List<DrinkDTO> drinksToDrinksDTO(List<Drink> drinks) as mapping rules are implicitly inherited from drinkToDrinkDTO methodMore
Also this link might be helpful: #47676869More
M
6

The error comes from the fact that you tried to map properties from List<> objects, but those don't exist. Mapstruct is smart enough to generate mappers between lists, provided it knows how to map the elements inside the list.

So you don't need to specify @Mapping annotations on the list-to-list mapping. Mapstruct will use the drinkToDrinkDTO mapping method automatically.

@Mapping(...)
DrinkDTO drinkToDrinkDTO(Drink drink);

List<DrinkDTO> drinksToDrinksDTO(List<Drink> drinks);
Milla answered 22/7, 2020 at 17:43 Comment(0)
M
106

For those, who have the same issue when using mapstruct + lombok:

I had the same issue. The reason was that I've been using Lombok plugin too. There's no need to remove it, but you have to ensure that in pom.xml in <annotationProcessorPaths> Lombok tag is before the Mapstruct one.

Example (part of pom.xml file):

<build>
    <pluginManagement>
        <plugins>
            <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>
                    <encoding>${project.build.sourceEncoding}</encoding>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId> <!-- IMPORTANT - LOMBOK BEFORE MAPSTRUCT -->
                            <artifactId>lombok</artifactId>
                            <version>${lombok.version}</version>
                        </path>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${org.mapstruct.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
Moralize answered 20/10, 2021 at 16:22 Comment(9)
The ordering did not seem to do the trick for me, but adding this annotation processor as well did: <path> <groupId>org.projectlombok</groupId> <artifactId>lombok-mapstruct-binding</artifactId> <version>0.2.0</version> </path>Dyal
I had a problem with the warning from the original question being shown in Netbeans IDE although I am using the lombok-mapstruct-binding. A similar issue appeared when using "Mapping Composition" from Mapstruct. Both issues showed a problem in Netbeans' code editor, but were not stopping the project from being compiled and running without problems. What solved these issues for me was ordering the <annotationProcessorPaths> like: 1. Lombok 2. Mapstruct-processor 3. Lombok-mapstruct-bindingMatron
I had the same issue, the trick is working for meOracle
Thanks for that one. Worked for me as well and save me some headacheNordgren
After lots of searching, this finally helped. Thanks for sharing!Coen
Thanks for sharing! It solved my same issue...Chromo
If you don't have them under annotationProcessorPaths, just make sure that lombok comes first as a dependency under dependencies, that did the trick for me.Globefish
The same is true using gradle and build.gradle: the lombok annotationProcessor config has to be before the mapstruct annotation processor.Slapstick
The MapStruct guide now has instructions.Note that newer versions of lombok require the lombok-mapstruct-binding artifact mentioned above.Joyejoyful
H
8

Just to add to @Jakub Słowikowski answer, the same happens with gradle dependencies. The following order was causing the error:

dependencies {    
...
annotationProcessor("org.mapstruct:mapstruct-processor:${mapstructVersion}")

annotationProcessor("org.projectlombok:lombok:${lombokVersion}")
...
}

hence I was forced to switch the order:

dependencies {    
...
annotationProcessor("org.projectlombok:lombok:${lombokVersion}")
    
annotationProcessor("org.mapstruct:mapstruct-processor:${mapstructVersion}")
...
}
Hocuspocus answered 4/2, 2022 at 14:50 Comment(2)
Thanks a lot! I was wondering what was I doing wrong. This was very helpfulEarmuff
Thanks so much. Excelent workaround, this worked for me.Centum
M
6

The error comes from the fact that you tried to map properties from List<> objects, but those don't exist. Mapstruct is smart enough to generate mappers between lists, provided it knows how to map the elements inside the list.

So you don't need to specify @Mapping annotations on the list-to-list mapping. Mapstruct will use the drinkToDrinkDTO mapping method automatically.

@Mapping(...)
DrinkDTO drinkToDrinkDTO(Drink drink);

List<DrinkDTO> drinksToDrinksDTO(List<Drink> drinks);
Milla answered 22/7, 2020 at 17:43 Comment(0)
G
1

In my case, the error did not stem from the declaration order of the annotationProcessors but from a missing Lombok annotation.

I had a mapping for Customer to CustomerDto, but the Customer was missing getters and setters.

CustomerDto toCustomerDto(Customer customer);

With

@Data
public class CustomerDto {
  ...
}

and

public class Customer {
  ...
}

Adding @Data to the Customer class solved the issue for me.

Goggler answered 1/8, 2022 at 20:27 Comment(1)
The irony is, in case Customer is an entity, you shouldn't use @DataBrahmani
B
1

just put lombok dependencie as first dependencie in your pom.xml file

then reload maven project

you don't need to add mapstruct plugin, i just used dependencies

    <dependencies>
    **<dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>**
    <!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct-processor -->
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>1.5.5.Final</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct -->
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>1.5.5.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>

Trust me you can still use Lombok in your project even if you have excluded it in the Spring Boot Maven plugin configuration. The excludes configuration in the plugin simply tells Maven to exclude the specified artifact from the plugin's classpath. In this case, the lombok artifact is being excluded from the Spring Boot Maven plugin's classpath, but it is not being excluded from your project's classpath.

Babism answered 6/5, 2023 at 18:50 Comment(0)
F
0

Try add a uses parameter in @Mapper annotation if you also have PackakingMapper, CoutriesMapper ... , like this:

@Mapper(uses = {PackagingMapper.class, CountriesMapper.class, ManufacturerMapper.class})
public interface DrinkMapper{
    ....
}
Forsyth answered 22/7, 2020 at 14:50 Comment(0)
W
0

For those, who have the same issue when using mapstruct + lombok
Adding lombok before mapstruct works as Both lombok & Mapstruct are based on annotation-processor, and mapstruct depends on getter & setter generated from lombok to generate the Mapper implementation. On changing the order lombok getter & setter are created first which are then used by mapstruct, so that why changin g order of annotationProcessor works !!

Walls answered 7/6, 2023 at 14:43 Comment(3)
That would be flaky af if the order of dependencies would matter. In my case it does not help using Gradle and I'm glad it did not help. Are you using Maven?Brahmani
Yes I am using MavenWalls
I have found out that it is really the same with Gradle as well after reading the other answers and I had to forgot to re-arrange the testAnnotationProcessors as well. Seems to really be the issueBrahmani
H
0

I ran into this as well, and the culprit was the use of

@Accessors(fluent=true)

on my Entity classes. Serves me right for using experimental Lombok features! :)

Houphouetboigny answered 16/6, 2023 at 13:19 Comment(0)
H
0

I was not sure if this problem still coming for anyone. I have encountered the same problem and the issue is due to invalid mappings. As in your case to map the packaging_id in the map struct interface you should mention like

@Mapping(source = "packaging.field_name" target = "drinkPackaging")

here packaging is the field name of Packaging entity and field_name is whatever the field you want to assign which is declared in your packaging entity. The naming conventions should match exactly means the field name in your entity should be the same as in your mapper interface source attribute.

Hollowell answered 19/6, 2023 at 6:37 Comment(0)
C
0

For people who asking Why (not only looking for the code - Jakub answer was correct)

Lombok generates(actually modifies as tree node exploit to Tokenize stream for modifying the AST) constructors and methods at compile-time using a Java annotations processor and Abstract Syntax Tree, MapStruct having almost the same mechanism (its way simpler cause of the fact it actually generates new nodes instead of node exploit) for generating concrete mapping implementation but it uses constructors to create instances of target and source objects during mapping. If it can't find constructor for the entity classes, it results in an ambiguous constructors in compilation time, they way to overcome this exception is to first let constructors being created before Mapstruct accessing them, which can be achieved by adding Lombok path before Mpastruct within in Maven Compiler plugin (if its your build system, for Gradle same concept holds).

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    ...
    <annotationProcessorPaths>
      <path>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
      </path>
      <path>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
      </path>
    </annotationProcessorPaths>
    ...
  </configuration>
</plugin>
Crumley answered 14/11, 2023 at 16:14 Comment(0)
M
0

I put this pluging at the end of my plugin list and it solved the issue for me: (I had this plugin but not at the end of list)

        <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>
Marijuana answered 15/12, 2023 at 5:45 Comment(1)
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.Assort
S
-2

Steps:

  1. Generate Getters / Setters for Drink and DrinkDTO classes(maybe without Lombok).

  2. Build project with Gradle Task: Build

  3. Start project!

Siouan answered 22/7, 2020 at 17:15 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.