Appearance
MapStruct
MapStruct 简介
MapStruct 是一个 Java 注释处理器,用于生成类型安全的 bean 映射类。
您所要做的就是定义一个映射器接口,该接口声明任何必需的映射方法。在编译期间,MapStruct 将生成该接口的实现。这个实现使用普通的 Java 方法调用在源和目标对象之间进行映射,即没有反射或类似。
MapStruct 依赖
MapStruct 包含以下依赖:
org.mapstruct:mapstruct
- 包含必需的注解,如@Mapping
org.mapstruct:mapstruct-processor
- 包含生成 mapper 实现的注解处理器
xml
<properties>
<org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
</properties>
<dependencies>
<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>
</dependencies>
基本映射
要创建一个映射器,只需用所需的映射方法定义一个 Java 接口,并用 org.mapstruct.Mapper
注解它。@Mapper
注解导致 MapStruct 代码生成器在构建期间创建一个 Mapper 接口的实现。
在生成的方法实现中,源类型的所有可读属性将被复制到目标类型的相应属性中:
- 当一个属性与它的目标实体对应物具有相同的名称时,它将被隐式映射。
- 当属性在目标实体中具有不同的名称时,可以通过
@Mapping
注释指定它的名称。
相同属性名
Source
javapackage study.helloworld.mapstruct_samples.same_name; import java.time.LocalDate; public class Source { private String name; private Integer age; private LocalDate birthday; ... }
Target
javapackage study.helloworld.mapstruct_samples.same_name; import java.time.LocalDate; public class Target { private String name; private Integer age; private LocalDate birthday; ... }
Mapper
javapackage study.helloworld.mapstruct_samples.same_name; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @Mapper public interface SourceTargetMapper { SourceTargetMapper INSTANCE = Mappers.getMapper(SourceTargetMapper.class); Target toTarget(Source source); }
Demo
javapackage study.helloworld.mapstruct_samples.same_name; import java.time.LocalDate; public class SameNameDemo { public static void main(String[] args) { Source source = new Source(); source.setName("小明"); source.setAge(18); source.setBirthday(LocalDate.now()); System.out.println(source); Target target = SourceTargetMapper.INSTANCE.toTarget(source); System.out.println(target); } }
logSource [name=小明, age=18, birthday=2021-10-29] Target [name=小明, age=18, birthday=2021-10-29]
不同属性名
Source
javapackage study.helloworld.mapstruct_samples.different_name; import java.time.LocalDate; public class Source { private String sourceName; private Integer sourceAge; private LocalDate sourceBirthday; ... }
Target
javapackage study.helloworld.mapstruct_samples.different_name; import java.time.LocalDate; public class Target { private String targetName; private Integer targetAge; private LocalDate targetBirthday; ... }
Mapper
javapackage study.helloworld.mapstruct_samples.different_name; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @Mapper public interface SourceTargetMapper { SourceTargetMapper INSTANCE = Mappers.getMapper(SourceTargetMapper.class); @Mapping(source = "sourceName", target = "targetName") @Mapping(source = "sourceAge", target = "targetAge") @Mapping(source = "sourceBirthday", target = "targetBirthday") Target toTarget(Source source); }
Demo
javapackage study.helloworld.mapstruct_samples.different_name; import java.time.LocalDate; public class DifferentNameDemo { public static void main(String[] args) { Source source = new Source(); source.setSourceName("小明"); source.setSourceAge(18); source.setSourceBirthday(LocalDate.now()); System.out.println(source); Target target = SourceTargetMapper.INSTANCE.toTarget(source); System.out.println(target); } }
logSource [sourceName=小明, sourceAge=18, sourceBirthday=2021-10-29] Target [targetName=小明, targetAge=18, targetBirthday=2021-10-29]
多个参数源的映射
Source
javapackage study.helloworld.mapstruct_samples.several_source; import java.time.LocalDate; public class Source1 { private String name; private Integer age; private LocalDate birthday; ... } package study.helloworld.mapstruct_samples.several_source; public class Source2 { private Double height; private Character gender; ... }
Target
javapackage study.helloworld.mapstruct_samples.several_source; import java.time.LocalDate; public class Target { private String targetName; private Integer age; private LocalDate birthday; private Double targetHeight; private Character gender; ... }
Mapper
javapackage study.helloworld.mapstruct_samples.several_source; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @Mapper public interface SourceTargetMapper { SourceTargetMapper INSTANCE = Mappers.getMapper(SourceTargetMapper.class); @Mapping(source = "source1.name", target = "targetName") @Mapping(source = "source2.height", target = "targetHeight") Target toTarget(Source1 source1, Source2 source2); @Mapping(source = "name", target = "targetName") @Mapping(source = "height", target = "targetHeight") Target toTarget(Source1 source1, Source2 source2, String name, Double height); }
Demo
javapackage study.helloworld.mapstruct_samples.several_source; import java.time.LocalDate; public class SeveralSourceDemo { public static void main(String[] args) { Source1 source1 = new Source1(); source1.setName("小明"); source1.setAge(18); source1.setBirthday(LocalDate.now()); Source2 source2 = new Source2(); source2.setHeight(1.75D); source2.setGender('男'); System.out.println(source1.toString() + ", " + source2.toString()); Target target = SourceTargetMapper.INSTANCE.toTarget(source1, source2); System.out.println(target); System.out.println("-------------------------------------"); target = SourceTargetMapper.INSTANCE.toTarget(source1, source2, "小白", 1.80D); System.out.println(target); } }
logSource [name=小明, age=18, birthday=2021-10-29], Source2 [height=1.75, gender=男] Target [targetName=小明, age=18, birthday=2021-10-29, targetHeight=1.75, gender=男] ------------------------------------- Target [targetName=小白, age=18, birthday=2021-10-29, targetHeight=1.8, gender=男]
嵌套的 bean 映射
Source
javapackage study.helloworld.mapstruct_samples.nested_bean; import java.time.LocalDate; public class Source { private String name; private Integer age; private LocalDate birthday; private NestedSource nestedSource; ... } package study.helloworld.mapstruct_samples.nested_bean; public class NestedSource { private Double height; private Character gender; ... }
Target
javapackage study.helloworld.mapstruct_samples.nested_bean; import java.time.LocalDate; public class Target { private String targetName; private Integer age; private LocalDate birthday; private TargetSource targetSource; ... } package study.helloworld.mapstruct_samples.nested_bean; public class TargetSource { private Double targetHeight; private Character gender; ... }
Mapper
javapackage study.helloworld.mapstruct_samples.nested_bean; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @Mapper public interface SourceTargetMapper { SourceTargetMapper INSTANCE = Mappers.getMapper(SourceTargetMapper.class); @Mapping(source = "source.name", target = "targetName") @Mapping(source = "source.nestedSource.height", target = "targetSource.targetHeight") Target toTarget(Source source); }
Demo
javapackage study.helloworld.mapstruct_samples.nested_bean; import java.time.LocalDate; public class NestedDemo { public static void main(String[] args) { Source source = new Source(); source.setName("小明"); source.setAge(18); source.setBirthday(LocalDate.now()); NestedSource nestedSource = new NestedSource(); nestedSource.setHeight(1.75D); nestedSource.setGender('男'); source.setNestedSource(nestedSource); System.out.println(source); Target target = SourceTargetMapper.INSTANCE.toTarget(source); System.out.println(target); } }
logSource [name=小明, age=18, birthday=2021-10-29, nestedSource=NestedSource [height=1.75, gender=男]] Target [targetName=小明, age=18, birthday=2021-10-29, targetSource=TargetSource [targetHeight=1.75, gender=男]]
更新现有的 bean
Source
javapackage study.helloworld.mapstruct_samples.existing_bean; import java.time.LocalDate; public class Source { private String name; private Integer age; private LocalDate birthday; ... }
Target
javapackage study.helloworld.mapstruct_samples.existing_bean; import java.time.LocalDate; public class Target { private String name; private Integer age; private LocalDate birthday; ... }
Mapper
javapackage study.helloworld.mapstruct_samples.existing_bean; import org.mapstruct.Mapper; import org.mapstruct.MappingTarget; import org.mapstruct.factory.Mappers; @Mapper public interface SourceTargetMapper { SourceTargetMapper INSTANCE = Mappers.getMapper(SourceTargetMapper.class); void updateTarget(Source source, @MappingTarget Target target); }
Demo
javapackage study.helloworld.mapstruct_samples.existing_bean; import java.time.LocalDate; public class ExistingBeanDemo { public static void main(String[] args) { Source source = new Source(); source.setName("小明"); source.setAge(18); source.setBirthday(LocalDate.now()); System.out.println(source); Target target = new Target(); target.setName("小花"); target.setAge(28); target.setBirthday(LocalDate.now()); SourceTargetMapper.INSTANCE.updateTarget(source, target); System.out.println(target); } }
logSource [name=小明, age=18, birthday=2021-10-30] Target [name=小明, age=18, birthday=2021-10-30]
数据类型转换
Source
javapackage study.helloworld.mapstruct_samples.data_type_conversions; import java.time.LocalDate; public class Source { private String name; private Integer age; private LocalDate birthday; private Double height; private Character gender; ... }
Target
javapackage study.helloworld.mapstruct_samples.data_type_conversions; public class Target { private String name; private String age; private String birthday; private String height; private String gender; ... }
Mapper
javapackage study.helloworld.mapstruct_samples.data_type_conversions; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @Mapper public interface SourceTargetMapper { SourceTargetMapper INSTANCE = Mappers.getMapper(SourceTargetMapper.class); @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy/MM/dd") @Mapping(source = "height", target = "height", numberFormat = ".000") Target toTarget(Source source); }
Demo
javapackage study.helloworld.mapstruct_samples.data_type_conversions; import java.time.LocalDate; public class SameNameDemo { public static void main(String[] args) { Source source = new Source(); source.setName("小明"); source.setAge(18); source.setBirthday(LocalDate.now()); source.setHeight(1.75D); source.setGender('男'); System.out.println(source); Target target = SourceTargetMapper.INSTANCE.toTarget(source); System.out.println(target); } }
logSource [name=小明, age=18, birthday=2021-10-30, height=1.75, gender=男] Target [name=小明, age=18, birthday=2021/10/30, height=1.750, gender=男]
映射集合容器
List 和 Set
Source
javapackage study.helloworld.mapstruct_samples.collections; import java.time.LocalDate; public class Source { private String name; private Integer age; private LocalDate birthday; ... }
Target
javapackage study.helloworld.mapstruct_samples.collections; public class Target { private String name; private String age; private String birthday; ... }
Mapper
javapackage study.helloworld.mapstruct_samples.collections; import java.util.List; import java.util.Set; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @Mapper public interface SourceTargetMapper { SourceTargetMapper INSTANCE = Mappers.getMapper(SourceTargetMapper.class); Set<String> integerSetToStringSet(Set<Integer> integers); List<Target> toTargets(List<Source> sources); @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy/MM/dd") Target toTarget(Source source); }
Demo
javapackage study.helloworld.mapstruct_samples.collections; import java.time.LocalDate; import java.util.List; import java.util.Set; public class CollectionsDemo { public static void main(String[] args) { Set<Integer> integers = Set.of(1, 2, 3, 4, 5); System.out.println(integers); Set<String> strings = SourceTargetMapper.INSTANCE.integerSetToStringSet(integers); System.out.println(strings); System.out.println("-------------------------------------"); Source source = new Source(); source.setName("小明"); source.setAge(18); source.setBirthday(LocalDate.now()); List<Source> sources = List.of(source); System.out.println(sources); List<Target> targets = SourceTargetMapper.INSTANCE.toTargets(sources); System.out.println(targets); } }
log[1, 2, 3, 4, 5] [1, 2, 3, 4, 5] ------------------------------------- [Source [name=小明, age=18, birthday=2021-10-30]] [Target [name=小明, age=18, birthday=2021/10/30]]
Map
Source
javapackage study.helloworld.mapstruct_samples.maps; import java.time.LocalDate; public class Source { private String name; private Integer age; private LocalDate birthday; ... }
Target
javapackage study.helloworld.mapstruct_samples.maps; public class Target { private String name; private String age; private String birthday; ... }
Mapper
javapackage study.helloworld.mapstruct_samples.maps; import java.util.Date; import java.util.Map; import org.mapstruct.MapMapping; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @Mapper public interface SourceTargetMapper { SourceTargetMapper INSTANCE = Mappers.getMapper(SourceTargetMapper.class); @MapMapping(valueDateFormat = "yyyy-MM-dd") Map<String, String> longDateMapToStringStringMap(Map<Long, Date> source); Map<String, Target> toTargets(Map<String, Source> sources); @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy/MM/dd") Target toTarget(Source source); }
Demo
javapackage study.helloworld.mapstruct_samples.maps; import java.time.LocalDate; import java.util.Date; import java.util.Map; public class MapsDemo { public static void main(String[] args) { Map<Long, Date> longDateMap = Map.of(1L, new Date()); System.out.println(longDateMap); Map<String, String> stringStringMap = SourceTargetMapper.INSTANCE.longDateMapToStringStringMap(longDateMap); System.out.println(stringStringMap); System.out.println("-------------------------------------"); Source source = new Source(); source.setName("小明"); source.setAge(18); source.setBirthday(LocalDate.now()); Map<String, Source> sources = Map.of("小明", source); System.out.println(sources); Map<String, Target> targets = SourceTargetMapper.INSTANCE.toTargets(sources); System.out.println(targets); } }
log{1=Sat Oct 30 17:20:53 CST 2021} {1=2021-10-30} ------------------------------------- {小明=Source [name=小明, age=18, birthday=2021-10-30]} {小明=Target [name=小明, age=18, birthday=2021/10/30]}
映射枚举
Source
javapackage study.helloworld.mapstruct_samples.enums; import java.time.LocalDate; public class Source { private String name; private Integer age; private LocalDate birthday; private SourceEnum sourceEnum; ... } package study.helloworld.mapstruct_samples.enums; public enum SourceEnum { MALE('男'), FEMALE('女'), SECRECY('-'); ... }
Target
javapackage study.helloworld.mapstruct_samples.enums; import java.time.LocalDate; public class Target { private String name; private Integer age; private LocalDate birthday; private TargetEnum targetEnum; ... } package study.helloworld.mapstruct_samples.enums; public enum TargetEnum { MAN('男'), WOMAN('女'), SECRECY('-'); ... }
Mapper
javapackage study.helloworld.mapstruct_samples.enums; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.ValueMapping; import org.mapstruct.factory.Mappers; @Mapper public interface SourceTargetMapper { SourceTargetMapper INSTANCE = Mappers.getMapper(SourceTargetMapper.class); @ValueMapping(source = "MALE", target = "MAN") @ValueMapping(source = "FEMALE", target = "WOMAN") TargetEnum toTargetEnum(SourceEnum sourceEnum); @Mapping(source = "sourceEnum", target = "targetEnum") Target toTarget(Source source); }
Demo
javapackage study.helloworld.mapstruct_samples.enums; import java.time.LocalDate; public class EnumsDemo { public static void main(String[] args) { Source source = new Source(); source.setName("小明"); source.setAge(18); source.setBirthday(LocalDate.now()); SourceEnum sourceEnum = SourceEnum.MALE; source.setSourceEnum(sourceEnum); System.out.println(source); Target target = SourceTargetMapper.INSTANCE.toTarget(source); System.out.println(target); } }
logSource [name=小明, age=18, birthday=2021-11-01, sourceEnum=MALE] Target [name=小明, age=18, birthday=2021-11-01, targetEnum=MAN]
使用装饰器自定义映射
Source
javapackage study.helloworld.mapstruct_samples.decorators; import java.time.LocalDate; public class Source { private String name; private Integer age; private LocalDate birthday; ... }
Target
javapackage study.helloworld.mapstruct_samples.decorators; import java.time.LocalDate; public class Target { private String name; private Integer age; private LocalDate birthday; private Boolean adult; ... }
Mapper
javapackage study.helloworld.mapstruct_samples.decorators; import org.mapstruct.DecoratedWith; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @DecoratedWith(SourceTargetDecorator.class) @Mapper public interface SourceTargetMapper { SourceTargetMapper INSTANCE = Mappers.getMapper(SourceTargetMapper.class); Target toTarget(Source source); }
Decorator
javapackage study.helloworld.mapstruct_samples.decorators; public abstract class SourceTargetDecorator implements SourceTargetMapper { private final SourceTargetMapper delegate; public SourceTargetDecorator(SourceTargetMapper delegate) { super(); this.delegate = delegate; } @Override public Target toTarget(Source source) { Target target = delegate.toTarget(source); Boolean adult = target.getAge() != null ? (target.getAge() >= 18 ? true : false) : null; target.setAdult(adult); return target; } }
Demo
javapackage study.helloworld.mapstruct_samples.decorators; import java.time.LocalDate; public class SameNameDemo { public static void main(String[] args) { Source source = new Source(); source.setName("小明"); source.setAge(18); source.setBirthday(LocalDate.now()); System.out.println(source); Target target = SourceTargetMapper.INSTANCE.toTarget(source); System.out.println(target); } }
logSource [name=小明, age=18, birthday=2021-11-02] Target [name=小明, age=18, birthday=2021-11-02, adult=true]