Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MapStruct 1.3.0.Final produces uncompilable code when using Java 11 + Lombok 1.18.6 #1742

Closed
DmitriiSolovev opened this issue Mar 6, 2019 · 9 comments · Fixed by #1811
Closed
Assignees
Labels
Milestone

Comments

@DmitriiSolovev
Copy link

DmitriiSolovev commented Mar 6, 2019

My setup: Java 11.02, Gradle 5.2.1, MapStruct 1.3.0.Final, Lombok 1.18.6 and Spring Boot 2.3.1.

build.gradle

plugins {
    id "net.ltgt.apt" version "0.21"
    id "net.ltgt.apt-idea" version "0.21"
}

...

/* Lombok */
compileOnly "org.projectlombok:lombok:${lombokVersion}"
annotationProcessor "org.projectlombok:lombok:${lombokVersion}"

/* Map Struct */
implementation "org.mapstruct:mapstruct-jdk8:${mapstructVersion}"
annotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"
testAnnotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"

FirstEntity.java

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = "id")
@Entity
@Table(name="first_entity")
public class FirstEntity {

  @Id
  private Long id;

  @ManyToOne
  @JoinColumn(name="second_entity_id")
  private SecondEntity secondEntity;

}

FirstEntityDTO.java

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FirstEntityDTO {

  private Long id;
  private SecondEntityDTO secondEntity;

}

SecondEntity.java

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = "id")
@Entity
@Table(name="second_entity")
public class SecondEntity {

  @Id
  private Long id;

}

SecondEntityDTO.java

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SecondEntityDTO {

  private Long id;

}

EntityMapper.java

@Mapper(
        unmappedTargetPolicy = ReportingPolicy.IGNORE,
        componentModel = "spring"
)
public interface EntityMapper {

    FirstEntity updateEntity(FirstEntityDTO entityDto, @MappingTarget FirstEntity entity);
}

Generated code, MapStruct 1.3.0.Final

if (entityDto.getSecondEntity() != null ) {
    if (entity.getSecondEntity() == null ) {
        entity.setSecondEntity( SecondEntity.builder() ); //compilation error: incompatible types
    }
    secondEntityDTOToSecondEntity( entityDto.getSecondEntity(), entity.getSecondEntity());
}

Generated code, MapStruct 1.2.0.Final

if (entityDto.getSecondEntity() != null ) {
    if (entity.getSecondEntity() == null ) {
        entity.setSecondEntity( new SecondEntity() ); //success
    }
    secondEntityDTOToSecondEntity( entityDto.getSecondEntity(), entity.getSecondEntity());
}

As a workaround, I use MapStruct 1.2.0.Final now.

@sjaakd
Copy link
Contributor

sjaakd commented Mar 6, 2019

2 questions..Have you looked at: #1713 ? you can disable builders, which most likely solves your problem..

Why are you combining setter/getter with builder?

@DmitriiSolovev
Copy link
Author

DmitriiSolovev commented Mar 6, 2019

JPA requires getters/setters. The Builder annotation is convenient for testing (mock data). If I remove the Builder annotation from the SecondEntityDTO class - will this solve the problem?

@sjaakd
Copy link
Contributor

sjaakd commented Mar 6, 2019

If I remove the Builder annotation from the SecondEntityDTO class - will this solve the problem?

Most likely yes.. The Builder implies to us (at this point in time) immutable. Hence, we try to analyse it that way.

@sjaakd
Copy link
Contributor

sjaakd commented Mar 7, 2019

@DmitriiSolovev .. That this solve your problem?

@DmitriiSolovev
Copy link
Author

@DmitriiSolovev .. That this solve your problem?

@sjaakd I need both getters/setters (jpa) and a builder (mock data, unit testing etc, ). As a workaround, I use MapStruct 1.2.0.Final now. However, it seems to me that this will help me - https://projectlombok.org/features/experimental/Accessors

@Accessors(chain = true)

Then I can remove Builder annotation. I will write you the results later.

@michalgce
Copy link

Same problem here with nested objects

    void updateDto(ChargerCrnk chargerCrnk, @MappingTarget ChargerDTO charger);

Generate

public void updateDto(ChargerCrnk chargerCrnk, ChargerDTO charger) {
        if ( chargerCrnk == null ) {
            return;
        }

        if ( charger.getMetadata() == null ) {
            charger.setMetadata( ChargerMetadataDTO.builder() );
        }
...

@ajayshenoyh
Copy link

I have the same problem when source and target is of same class. I am going with work around MapStruct 1.2.0.Final for now. Thanks! @DmitriiSolovev

@filiphr filiphr added the bug label Apr 12, 2019
@filiphr filiphr added this to the 1.4.0 milestone Apr 12, 2019
@sjaakd sjaakd self-assigned this Apr 20, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue May 2, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue May 2, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue May 2, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue May 3, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue May 8, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue May 8, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue May 10, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue May 10, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue May 11, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue May 11, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue May 11, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue May 24, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue May 24, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue May 24, 2019
@filiphr filiphr mentioned this issue Sep 22, 2019
2 tasks
filiphr added a commit to filiphr/mapstruct that referenced this issue Sep 26, 2019
filiphr added a commit to filiphr/mapstruct that referenced this issue Sep 27, 2019
filiphr added a commit to filiphr/mapstruct that referenced this issue Sep 27, 2019
filiphr added a commit to filiphr/mapstruct that referenced this issue Sep 27, 2019
filiphr added a commit to filiphr/mapstruct that referenced this issue Sep 27, 2019
filiphr added a commit to filiphr/mapstruct that referenced this issue Sep 28, 2019
filiphr added a commit to filiphr/mapstruct that referenced this issue Sep 28, 2019
filiphr added a commit to filiphr/mapstruct that referenced this issue Sep 28, 2019
filiphr added a commit that referenced this issue Sep 28, 2019
filiphr added a commit that referenced this issue Sep 28, 2019
filiphr added a commit that referenced this issue Sep 28, 2019
@filiphr filiphr modified the milestones: 1.4.0, 1.3.1 Sep 28, 2019
@lo-rodriguez
Copy link

Thanks for your comments. At the moment I don't have much time to build a demo from my project, but I put my POM file with what I built my project and my DTOs, I hope this helps.


4.0.0

org.springframework.boot
spring-boot-starter-parent
2.3.0.RELEASE


net.ronasoft
rsftapi
0.0.1-SNAPSHOT
war
wsftapi
Ws family api

<properties>
	<java.version>11</java.version>
	<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
	<hibernate.version>5.3.7.Final</hibernate.version>
	<jackson.version>1.8.6</jackson.version>
	<HikariCP.version>3.4.3</HikariCP.version>
	<cfx-version>3.3.5</cfx-version>
	<bcprov-ext-jdk15on-version>1.64</bcprov-ext-jdk15on-version>
	<gson.version>2.8.5</gson.version>
	<uuid-generator.version>4.0.1</uuid-generator.version>
	<cxf.swagger.ui.version>3.25.3</cxf.swagger.ui.version>
	<cxf-rt-rs-service-swagge-version>3.1.7</cxf-rt-rs-service-swagge-version>
	<cxf-rt-rs-service-openapi-v3-version>3.3.5</cxf-rt-rs-service-openapi-v3-version>
	<com.nimbus-jose-jwt>8.18.1</com.nimbus-jose-jwt>
	<javax.xml.ws.version>2.3.1</javax.xml.ws.version>
	<org.mapstruct.version>1.3.1.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-jdbc</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-configuration-processor</artifactId>
		<optional>true</optional>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
		<exclusions>
			<exclusion>
				<groupId>org.junit.vintage</groupId>
				<artifactId>junit-vintage-engine</artifactId>
			</exclusion>
		</exclusions>
	</dependency>
	<!-- MariaDB -->
	<dependency>
		<groupId>org.mariadb.jdbc</groupId>
		<artifactId>mariadb-java-client</artifactId>
	</dependency>
	<!-- -CXF -->
	<dependency>
		<groupId>org.apache.cxf</groupId>
		<artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
		<version>3.3.5</version>
	</dependency>
	<dependency>
		<groupId>org.apache.cxf</groupId>
		<artifactId>cxf-rt-frontend-jaxrs</artifactId>
		<version>${cfx-version}</version>
	</dependency>
	<dependency>
		<groupId>org.apache.cxf</groupId>
		<artifactId>cxf-rt-rs-client</artifactId>
		<version>${cfx-version}</version>
	</dependency>
	<!-- JOSE -->
	<dependency>
		<groupId>org.apache.cxf</groupId>
		<artifactId>cxf-rt-rs-security-jose</artifactId>
		<version>${cfx-version}</version>
	</dependency>
	<dependency>
		<groupId>org.apache.cxf</groupId>
		<artifactId>cxf-rt-rs-security-jose-jaxrs</artifactId>
		<version>${cfx-version}</version>
	</dependency>
	<dependency>
		<groupId>org.codehaus.jackson</groupId>
		<artifactId>jackson-core-asl</artifactId>
		<version>${jackson.version}</version>
	</dependency>
	<dependency>
		<groupId>org.codehaus.jackson</groupId>
		<artifactId>jackson-mapper-asl</artifactId>
		<version>${jackson.version}</version>
	</dependency>
	<dependency>
		<groupId>org.codehaus.jackson</groupId>
		<artifactId>jackson-jaxrs</artifactId>
		<version>${jackson.version}</version>
	</dependency>
	<dependency>
		<groupId>org.apache.cxf</groupId>
		<artifactId>cxf-rt-rs-service-description-swagger</artifactId>
		<version>${cxf-rt-rs-service-swagge-version}</version>
	</dependency>
	<dependency>
		<groupId>org.apache.cxf</groupId>
		<artifactId>cxf-rt-rs-service-description-openapi-v3</artifactId>
		<version>${cxf-rt-rs-service-openapi-v3-version}</version>
	</dependency>
	<dependency>
		<groupId>org.apache.cxf</groupId>
		<artifactId>cxf-rt-rs-extension-providers</artifactId>
		<version>${cfx-version}</version>
	</dependency>
	<dependency>
		<groupId>com.nimbusds</groupId>
		<artifactId>nimbus-jose-jwt</artifactId>
		<version>${com.nimbus-jose-jwt}</version>
	</dependency>
	<!-- -CXF END -->
	<!-- -OTHERS -->
	<dependency>
		<groupId>com.zaxxer</groupId>
		<artifactId>HikariCP</artifactId>
		<version>${HikariCP.version}</version>
	</dependency>
	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-entitymanager</artifactId>
		<version>${hibernate.version}</version>
	</dependency>
	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-validator</artifactId>
		<version>5.2.4.Final</version>
	</dependency>
	<dependency>
		<groupId>com.google.code.gson</groupId>
		<artifactId>gson</artifactId>
		<version>${gson.version}</version>
	</dependency>
	<dependency>
		<groupId>com.fasterxml.uuid</groupId>
		<artifactId>java-uuid-generator</artifactId>
		<version>${uuid-generator.version}</version>
	</dependency>
	<dependency>
		<groupId>org.bouncycastle</groupId>
		<artifactId>bcprov-ext-jdk15on</artifactId>
		<version>${bcprov-ext-jdk15on-version}</version>
	</dependency>
	<!-- https://mvnrepository.com/artifact/javax.xml.ws/jaxws-api -->
	<dependency>
		<groupId>javax.xml.ws</groupId>
		<artifactId>jaxws-api</artifactId>
		<version>${javax.xml.ws.version}</version>
	</dependency>
	<dependency>
		<groupId>org.mapstruct</groupId>
		<artifactId>mapstruct</artifactId>
		<version>${org.mapstruct.version}</version>
	</dependency>
	<dependency>
		<groupId>org.mapstruct</groupId>
		<artifactId>mapstruct-processor</artifactId>
		<version>${org.mapstruct.version}</version>
		<scope>provided</scope>
	</dependency>
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.12</version>
		<scope>test</scope>
	</dependency>

</dependencies>

<build>
	<finalName>rsftapi</finalName>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-surefire-plugin</artifactId>
			<version>2.22.2</version>
		</plugin>

		<plugin>
			<artifactId>maven-compiler-plugin</artifactId>
			<version>3.8.1</version>
			<configuration>
				<source>11</source>
				<target>11</target>
				<release>11</release>
				<forceJavacCompilerUse>true</forceJavacCompilerUse>
				<compilerArgs>
					<arg>-Werror</arg>
					<arg>-verbose</arg>
				</compilerArgs>
				<annotationProcessorPaths>
					<path>
						<groupId>org.mapstruct</groupId>
						<artifactId>mapstruct-processor</artifactId>
						<version>${org.mapstruct.version}</version>
					</path>
					<!-- other annotation processors -->
				</annotationProcessorPaths>
			</configuration>
		</plugin>

	</plugins>
</build>

package net.ronasoft.rsftapi.dto;
import org.mapstruct.Qualifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@qualifier
@target(ElementType.TYPE)
@retention(RetentionPolicy.CLASS)
public @interface DateConverter {

}
package net.ronasoft.rsftapi.dto;

import java.sql.Timestamp;
import java.text.ParseException;
import java.util.Date;

import net.ronasoft.rsftapi.commons.CONSTANTS;
@DateConverter
public class DateMapper {
@DateToString
public String asString(Date date) {
return date != null ? CONSTANTS.dateformat.format(date) : null;
}
@UtilDate
public Date asDate(String date) throws ParseException {
return date != null ? CONSTANTS.dateformat.parse(date) : null;
}
@TimestampToString
public String timestampToString(Timestamp time) throws ParseException {
return time != null ? CONSTANTS.dateformat2.format(time) : null;
}
@TimestampSQL
public Timestamp asTimestamp(String time) throws ParseException {
return time != null ?new Timestamp( CONSTANTS.dateformat2.parse(time).getTime() ): null;
}
}
package net.ronasoft.rsftapi.dto;
import org.mapstruct.Qualifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@qualifier
@target(ElementType.METHOD)
@retention(RetentionPolicy.CLASS)
public @interface DateToString {

}
package net.ronasoft.rsftapi.dto;

public class ListDetailDTO {
private String id;
private String description;
private String idUserList;
private String newValue;
private String oldValue;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getIdUserList() {
return idUserList;
}
public void setIdUserList(String idUserList) {
this.idUserList = idUserList;
}
public String getNewValue() {
return newValue;
}
public void setNewValue(String newValue) {
this.newValue = newValue;
}
public String getOldValue() {
return oldValue;
}
public void setOldValue(String oldValue) {
this.oldValue = oldValue;
}
@OverRide
public String toString() {
return "ListDetailDTO [id=" + id + ", description=" + description + ", idUserList=" + idUserList + ", newValue="
+ newValue + ", oldValue=" + oldValue + "]";
}

}

package net.ronasoft.rsftapi.dto;
import org.mapstruct.Qualifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@qualifier
@target(ElementType.METHOD)
@retention(RetentionPolicy.CLASS)
public @interface TimestampSQL {

}
package net.ronasoft.rsftapi.dto;
import org.mapstruct.Qualifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@qualifier
@target(ElementType.METHOD)
@retention(RetentionPolicy.CLASS)
public @interface TimestampToString {

}
package net.ronasoft.rsftapi.dto;

import java.util.List;

public class UserListDTO {
private String id;
private String dateUpdate;
private String dateCreate;
private String idUser;
private String type;
private List listDetail;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDateUpdate() {
return dateUpdate;
}
public void setDateUpdate(String dateUpdate) {
this.dateUpdate = dateUpdate;
}
public String getDateCreate() {
return dateCreate;
}
public void setDateCreate(String dateCreate) {
this.dateCreate = dateCreate;
}
public String getIdUser() {
return idUser;
}
public void setIdUser(String idUser) {
this.idUser = idUser;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List getListDetail() {
return listDetail;
}
public void setListDetail(List listDetail) {
this.listDetail = listDetail;
}
@OverRide
public String toString() {
return "UserListDTO [id=" + id + ", dateUpdate=" + dateUpdate + ", dateCreate=" + dateCreate + ", idUser="
+ idUser + ", type=" + type + ", listDetail=" + listDetail + "]";
}

}
package net.ronasoft.rsftapi.dto;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;

import net.ronasoft.rsftapi.entities.ListDetail;
import net.ronasoft.rsftapi.entities.UserList;

@Mapper(uses=DateMapper.class, componentModel = "cdi")
public interface UserListMapper {
UserListMapper INSTANCE = Mappers.getMapper(UserListMapper.class);
abstract ListDetail listDetailDTOtoListDetail(ListDetailDTO dto);
@mappings({
@mapping(target="dateUpdate", source="dto.dateUpdate", dateFormat = "dd-MM-yyyy HH:mm:ss"),
@mapping(target="dateCreate",source="dto.dateCreate",qualifiedBy= {DateConverter.class,TimestampSQL.class})})
UserList userListDTOtoUserList(UserListDTO dto);
@mappings({
@mapping(target="dateUpdate",source="list.dateUpdate",qualifiedBy= {DateConverter.class,DateToString.class}),
@mapping(target="dateCreate",source="list.dateCreate",qualifiedBy= {DateConverter.class,TimestampToString.class})})
UserListDTO userListDTOtoUserList(UserList list);
}
package net.ronasoft.rsftapi.dto;
import org.mapstruct.Qualifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@qualifier
@target(ElementType.METHOD)
@retention(RetentionPolicy.CLASS)
public @interface UtilDate {

}

The truth is not if it is a new problem but I would think it is the same problem, this is also written in https://stackoverflow.com/ in the question: Is Mapstruct Java11 compatible ?. He carried out the same operations and they mention and I have not had a positive result.

@filiphr
Copy link
Member

filiphr commented Jun 15, 2020

@lo-rodriguez I would ask you again to not comment on old issues. Please open a new issue explaining what problem you have and how we can reproduce it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants