Solution:
I had to change the ordering of my mapstruct
and lombok
annotationProcessorPaths
.
I had to place mapstruct
above lombok
, then it worked.
I updated the pom below to the working version, so there is no non-working-code in here.
I also converted the lombok version back to the current release and not using the edge-version.
Original Problem:
I have 2 more or less identical sets of classes (see example below)
Initially I set the project up to use:
I found the Lombok documentation explaining how to add the annotation-processor to the maven-plugin https://projectlombok.org/setup/maven
But when executing I still get Error:(16,25) java: ClassX does not have an accessible parameterless constructor.
Searching for this message I found some 2 to 3 years of problems, but nothing up to date. Also I saw, that the issue was resolved for those posts.
In at least one of the posts it was mentioned, that it worked, when splitting the project into modules. And this worked for me as well. When I move the DTOs to another maven module, build them there and set the dependency it works, but this is definitely not the project-structure I want to have. Also since I might need to move my entities out as well and I don't want to create a new module for each Pojo-structure I'm creating.
I also found that post on the Lombok Edge version: https://projectlombok.org/download-edge The second point in the change-list is
BREAKING CHANGE: mapstruct users should now add a dependency to lombok-mapstruct-binding. This solves compiling modules with lombok (and mapstruct).
So I tried that as well. I added the repository to my pom, added lombok-mapstruct-binding and set the lombok version to edge-SNAPSHOT
But even after a clean the compile step fails.
In between I changed my DTOs to use @Data as well, but I would like to change this back.
Finally here are some examples and details on the code.
DTOs
@Data
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = BDto.class, name = "b"),
@JsonSubTypes.Type(value = CDto.class, name = "c")
})
public abstract class ADto {
private long id;
private String type;
private Set<String> metadata;
private Set<String> tags;
}
@Data
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BDto extends ADto {
private String path;
@Builder
private BDto(long id, String path, Set<String> metadata, Set<String> tags) {
super(id, "b", metadata, tags);
this.path = path;
}
}
@Data
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CDto extends ADto {
private String name;
private Set<A> collection;
@Builder
private CDto(long id, String name, Set<A> collection, Set<String> metadata, Set<String> tags) {
super(id, "c", metadata, tags);
this.collection = collection;
this.name = name;
}
}
Entities
@Entity
@Table
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type")
@AllArgsConstructor
@NoArgsConstructor
@Getter
public abstract class A extends PanacheEntityBase {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected long id;
@Column(name = "type", insertable = false, updatable = false)
private String type;
/* ... */
}
@Entity
@DiscriminatorValue("b")
@NoArgsConstructor
@Getter
@ToString
public class B extends A {
public B(long id, String path, Set<String> metadata, Set<Tag> tags) {
super(id, "b", metadata, tags);
this.path = path;
}
public B(String path) {
super(0, "b", new HashSet<>(), new HashSet<>());
this.path = path;
}
@Column(name = "path")
@Setter
private String path;
}
@Entity
@DiscriminatorValue("c")
@NoArgsConstructor
@Getter
public class C extends A {
public C(long id, String name, List<A> collection, Set<String> metadata, Set<Tag> tags) {
super(id, "c", metadata, tags);
this.collection = collection;
this.name = name;
}
@Column(name = "name")
private String name;
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "c_id")
@OrderBy("order")
List<A> collection;
}
Mappers
public interface AMapper {
default String tagToDto(Tag tag) {
return tag.getTag();
}
default Tag tagFromDto(String tag) {
return Tag.createIfNotExists(tag);
}
}
@Mapper()
public interface BMapper extends AMapper {
@Override
@Mapping(target = "tags",
qualifiedByName = "tagToDto")
BDto toDto(B b);
@Override
@Mapping(target = "tags",
qualifiedByName = "tagToEntity")
B toEntity(BDto b);
}
@Mapper()
public interface CMapper extends AMapper {
@Override
@Mapping(target = "tags",
qualifiedByName = "tagToDto")
CDto toDto(C b);
@Override
@Mapping(target = "tags",
qualifiedByName = "tagToEntity")
C toEntity(CDto b);
}
Pom
<?xml version="1.0"?>
<project 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"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<artifactId>dummy</artifactId>
<groupId>dummy</groupId>
<version>0.1.0</version>
<packaging>pom</packaging>
<properties>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<maven.compiler.parameters>true</maven.compiler.parameters>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<lombok.version>1.18.12</lombok.version>
<mapstruct.version>1.3.1.Final</mapstruct.version>
</properties>
<repositories>
<repository>
<id>projectlombok.org</id>
<url>https://projectlombok.org/edge-releases</url>
</repository>
</repositories>
<dependencies>
<!-- other stuff -->
<!-- Tools -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<!-- <scope>provided</scope> -->
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</annotationProcessorPath>
<annotationProcessorPath>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
With lombok (1.18.18) and mapstruct (1.4.2.Final) everything worked after I:
lombok-mapstruct-binding
annotationProcessorPaths
section of plugin maven-compiler-plugin
links:
If you are using Lombok 1.18.16 or newer you also need to add lombok-mapstruct-binding in order to make Lombok and MapStruct work together.
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