无法使用mapstruct将List <Source>映射到List <Target>

时间:2019-09-16 07:16:09

标签: java spring-boot mapstruct

我有一个基本的Spring引导应用程序,我正在尝试使用Mapstruct(版本1.3.0.Final)将实体列表映射到DTO列表。

来源:

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.sql.Timestamp;

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder(toBuilder = true)
    @Table(name = "source")
    @Entity(name = "Source")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public class Source implements Serializable {

        private static final long serialVersionUID = 964150155782995534L;

        @Id
        @JsonIgnore
        @Column(name = "id")
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SourceSeq")
        @SequenceGenerator(sequenceName = "source_id_seq", allocationSize = 1, name = "SourceSeq")
        private long id;

        @NotNull
        @Size(min = 36, max = 36)
        @Column(name = "uuid", nullable = false, length = 36)
        private String uuid;

        @Column(name = "user_id")
        private Long userId;

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

        @Column(name = "user_org_id")
        private Long userOrgId;

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

        @Column(name = "account_number")
        private Integer accountNumber;

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

        @Column(name = "billing_delay")
        private Integer billingDelay;

        @Column(name = "default_billing_delay")
        private Integer defaultBillingDelay;

        @Column(name = "billing_enabled")
        private Boolean billingEnabled = true;

        @JsonIgnore
        @CreationTimestamp
        @Column(name = "created_date")
        private Timestamp createdDate;

        @JsonIgnore
        @UpdateTimestamp
        @Column(name = "updated_date")
        private Timestamp updatedDate;
    }

目标:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class Target implements Serializable {

    private static final long serialVersionUID = 8939532280496355293L;

    @ApiModelProperty(hidden = true)
    private String uuid;

    @ApiModelProperty(value = "user ID", example = "123456", dataType = "int64", position = 1)
    private Long userId;

    @ApiModelProperty(value = "username", example = "myUser", position = 2)
    private String username;

    @ApiModelProperty(hidden = true)
    private String firstName;

    @ApiModelProperty(hidden = true)
    private String lastName;

    @ApiModelProperty(value = "user organization ID", example = "71836", dataType = "int64", position = 3)
    private Long userOrgId;

    @ApiModelProperty(value = "user organization name", example = "Org Inc", position = 4)
    private String userOrgName;

    @ApiModelProperty(value = "account number", example = "987654", position = 5)
    private Integer accountNumber;

    @ApiModelProperty(value = "account name", example = "My Mapping Acc", position = 6)
    private String accountName;

    @ApiModelProperty(value = "billing delay (in days)", example = "60", position = 7)
    private Integer billingDelay;

    @ApiModelProperty(value = "default billing delay (in days)", example = "30", position = 8)
    private Integer defaultBillingDelay;

    @ApiModelProperty(value = "is billing enabled?", example = "true", position = 9)
    private Boolean billingEnabled = true;

    @ApiModelProperty(hidden = true)
    private Date createdDate;
}

映射器:

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

import java.util.List;

@Mapper
public interface MyMapper {

    MyMapper MAPPER = Mappers.getMapper(MyMapper.class);


    // Target toTarget(Source source);
    // I have tried using this as well but my target mapped list only contains billingEnabled = true for every object in the response list. MapperImpl class also included below. Without toTarget method get a compilation error (also included below)
    // Response: 
        /*[

      {
        "billingEnabled": true
      },
      {
        "billingEnabled": true
      },
      {
        "billingEnabled": true
      }
    ]*/

    List<Target> toTargets(List<Source> sources);
}

MapperImpl:

import java.util.ArrayList;
import java.util.List;
import javax.annotation.Generated;

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2019-09-16T00:06:14-0700",
    comments = "version: 1.3.0.Final, compiler: javac, environment: Java 1.8.0_202 (Oracle Corporation)"
)
public class MyMapperImpl implements MyMapper {

    @Override
    public Target toTarget(Source source) {
        if ( source == null ) {
            return null;
        }

        Target target = new Target();

        return target;
    }

    @Override
    public List<Target> toTargets(List<Source> sources) {
        if ( sources == null ) {
            return null;
        }

        List<Target> list = new ArrayList<Target>( sources.size() );
        for ( Source source : sources ) {
            list.add( toTarget( source ) );
        }

        return list;
    }
}

错误:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.5.1:compile (default-compile) on project my-project: Compilation failure
[ERROR] /Users/user8812/workspace/my-project-/src/main/java/MyMapper.java:[17,23] Can't map Collection element "Source source" to "Target target". Consider to declare/implement a mapping method: "Target map(Source value)".

我正在寻找具有相同字段名的Target列表,而没有另一个单独的toTarget方法,而该方法已经在另一个具有较旧Mapstruct版本的项目中为我工作。

3 个答案:

答案 0 :(得分:0)

由于“目标”类型和“源”类型中的字段名称和类型相同,所以使用BeanUtils.copyProperties(source,target)会更有益,更容易吗?这非常简单,并允许陈述被忽略的字段。

答案 1 :(得分:0)

在编译过程中MapStruct引发的异常告诉您如何解决它:

  

无法将集合元素“源源”映射到“目标目标”。 考虑声明/实现映射方法:“目标映射(源值)”。

您甚至可以将此方法签名放置在与我们展示的相同的界面内。

修改

似乎该应用程序中MapStruct的默认全局配置已更改。尝试在界面内将此注释应用于您的“从源到目标”方法:

@BeanMapping(ignoreByDefault = false)

或者您可以使用@Mapping注释显式映射它们的字段。

答案 2 :(得分:0)

我认为声明应该在MyMapper界面中具有注释。

@Mapping(source = "sources", target = "targets")
List<Target> toTargets(List<Source> sources);

参考:https://mapstruct.org/