mirror of
https://gitee.com/easii/mapstruct-plus.git
synced 2025-12-07 01:28:31 +08:00
init project
This commit is contained in:
commit
03b6ae2491
40
.gitignore
vendored
Normal file
40
.gitignore
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea/modules.xml
|
||||||
|
.idea/jarRepositories.xml
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/libraries/
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### Mac OS ###
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
.idea
|
||||||
79
example/pom.xml
Normal file
79
example/pom.xml
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.6.7</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>io.github.linpl</groupId>
|
||||||
|
<artifactId>example</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<mapstruct.version>1.5.1.Final</mapstruct.version>
|
||||||
|
<mapstruct-plus.version>1.0.0</mapstruct-plus.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.linpl</groupId>
|
||||||
|
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
|
||||||
|
<version>${mapstruct-plus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct</artifactId>
|
||||||
|
<version>${mapstruct.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.linpl</groupId>
|
||||||
|
<artifactId>mapstruct-plus-processor</artifactId>
|
||||||
|
<version>${mapstruct-plus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-processor</artifactId>
|
||||||
|
<version>${mapstruct.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<path>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-processor</artifactId>
|
||||||
|
<version>${mapstruct.version}</version>
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<groupId>io.github.linpl</groupId>
|
||||||
|
<artifactId>mapstruct-plus-processor</artifactId>
|
||||||
|
<version>${mapstruct-plus.version}</version>
|
||||||
|
</path>
|
||||||
|
|
||||||
|
</annotationProcessorPaths>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package io.github.linpl.mapstruct;
|
||||||
|
|
||||||
|
import io.github.linpl.annotations.AutoMapping;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.core.convert.ConversionService;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class Application {
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(Application.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package io.github.linpl.mapstruct;
|
||||||
|
|
||||||
|
import io.github.linpl.annotations.MapperConfig;
|
||||||
|
|
||||||
|
@MapperConfig(mapperPackage = "io.github.linpl.mapstruct.convert")
|
||||||
|
public class MapstructConfiguration {
|
||||||
|
}
|
||||||
29
example/src/main/java/io/github/linpl/mapstruct/Startup.java
Normal file
29
example/src/main/java/io/github/linpl/mapstruct/Startup.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package io.github.linpl.mapstruct;
|
||||||
|
|
||||||
|
import io.github.linpl.Converter;
|
||||||
|
import io.github.linpl.mapstruct.dto.Car;
|
||||||
|
import io.github.linpl.mapstruct.dto.CarDto;
|
||||||
|
import io.github.linpl.mapstruct.dto.CarType;
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.convert.ConversionService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class Startup {
|
||||||
|
|
||||||
|
private Converter converter;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void start() {
|
||||||
|
Car car = new Car();
|
||||||
|
car.setType(CarType.OTHER);
|
||||||
|
CarDto catDto = converter.convert(car, CarDto.class);
|
||||||
|
System.out.println(catDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setConverter(final Converter converter) {
|
||||||
|
this.converter = converter;
|
||||||
|
}
|
||||||
|
}
|
||||||
47
example/src/main/java/io/github/linpl/mapstruct/dto/Car.java
Normal file
47
example/src/main/java/io/github/linpl/mapstruct/dto/Car.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package io.github.linpl.mapstruct.dto;
|
||||||
|
|
||||||
|
import io.github.linpl.annotations.AutoMapper;
|
||||||
|
import io.github.linpl.annotations.AutoMapping;
|
||||||
|
|
||||||
|
@AutoMapper(target = CarDto.class)
|
||||||
|
public class Car {
|
||||||
|
|
||||||
|
private String make;
|
||||||
|
private SeatConfiguration seatConfiguration;
|
||||||
|
private CarType type;
|
||||||
|
|
||||||
|
@AutoMapping(target = "wheels", ignore = true)
|
||||||
|
private Wheels wheels;
|
||||||
|
|
||||||
|
public String getMake() {
|
||||||
|
return make;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMake(final String make) {
|
||||||
|
this.make = make;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SeatConfiguration getSeatConfiguration() {
|
||||||
|
return seatConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeatConfiguration(final SeatConfiguration seatConfiguration) {
|
||||||
|
this.seatConfiguration = seatConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CarType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(final CarType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Wheels getWheels() {
|
||||||
|
return wheels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWheels(Wheels wheels) {
|
||||||
|
this.wheels = wheels;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
package io.github.linpl.mapstruct.dto;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CarDto {
|
||||||
|
private String make;
|
||||||
|
private SeatConfigurationDto seatConfiguration;
|
||||||
|
private String type;
|
||||||
|
private List<WheelDto> wheels;
|
||||||
|
|
||||||
|
public String getMake() {
|
||||||
|
return make;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMake(final String make) {
|
||||||
|
this.make = make;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SeatConfigurationDto getSeatConfiguration() {
|
||||||
|
return seatConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeatConfiguration(final SeatConfigurationDto seatConfiguration) {
|
||||||
|
this.seatConfiguration = seatConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(final String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<WheelDto> getWheels() {
|
||||||
|
return wheels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWheels(List<WheelDto> wheels) {
|
||||||
|
this.wheels = wheels;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CarDto{" +
|
||||||
|
"make='" + make + '\'' +
|
||||||
|
", seats=" + seatConfiguration +
|
||||||
|
", type='" + type + '\'' +
|
||||||
|
", wheels=" + wheels +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package io.github.linpl.mapstruct.dto;
|
||||||
|
|
||||||
|
public enum CarType {
|
||||||
|
SPORTS, OTHER
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package io.github.linpl.mapstruct.dto;
|
||||||
|
|
||||||
|
import io.github.linpl.annotations.AutoMapper;
|
||||||
|
|
||||||
|
@AutoMapper(target = SeatConfigurationDto.class)
|
||||||
|
public class SeatConfiguration {
|
||||||
|
private int numberOfSeats;
|
||||||
|
private SeatMaterial seatMaterial;
|
||||||
|
|
||||||
|
public SeatMaterial getSeatMaterial() {
|
||||||
|
return seatMaterial;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeatMaterial(final SeatMaterial seatMaterial) {
|
||||||
|
this.seatMaterial = seatMaterial;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfSeats() {
|
||||||
|
return numberOfSeats;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumberOfSeats(final int numberOfSeats) {
|
||||||
|
this.numberOfSeats = numberOfSeats;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package io.github.linpl.mapstruct.dto;
|
||||||
|
|
||||||
|
public class SeatConfigurationDto {
|
||||||
|
private int seatCount;
|
||||||
|
private String material;
|
||||||
|
|
||||||
|
public int getSeatCount() {
|
||||||
|
return seatCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeatCount(final int seatCount) {
|
||||||
|
this.seatCount = seatCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMaterial() {
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaterial(final String material) {
|
||||||
|
this.material = material;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package io.github.linpl.mapstruct.dto;
|
||||||
|
|
||||||
|
public enum SeatMaterial {
|
||||||
|
LEATHER, FABRIC
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package io.github.linpl.mapstruct.dto;
|
||||||
|
|
||||||
|
import io.github.linpl.annotations.AutoMapper;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@AutoMapper(target = WheelDto.class)
|
||||||
|
public class Wheel {
|
||||||
|
private WheelPosition position;
|
||||||
|
private int diameter;
|
||||||
|
|
||||||
|
public WheelPosition getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPosition(WheelPosition position) {
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDiameter() {
|
||||||
|
return diameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDiameter(int diameter) {
|
||||||
|
this.diameter = diameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Wheel wheel = (Wheel) o;
|
||||||
|
return diameter == wheel.diameter && position == wheel.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(position, diameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package io.github.linpl.mapstruct.dto;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class WheelDto {
|
||||||
|
private String position;
|
||||||
|
private int diameter;
|
||||||
|
|
||||||
|
public void setDiameter(int diameter) {
|
||||||
|
this.diameter = diameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPosition(String position) {
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDiameter() {
|
||||||
|
return diameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
WheelDto wheelDto = (WheelDto) o;
|
||||||
|
return diameter == wheelDto.diameter && Objects.equals(position, wheelDto.position);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(position, diameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package io.github.linpl.mapstruct.dto;
|
||||||
|
|
||||||
|
public enum WheelPosition {
|
||||||
|
LEFT_FRONT,
|
||||||
|
RIGHT_FRONT,
|
||||||
|
LEFT_REAR,
|
||||||
|
RIGHT_REAR
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
package io.github.linpl.mapstruct.dto;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Spliterator;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class Wheels implements Iterable<Wheel> {
|
||||||
|
private List<Wheel> wheelsList = new ArrayList<>();
|
||||||
|
|
||||||
|
public List<Wheel> getWheelsList() {
|
||||||
|
return wheelsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWheelsList(List<Wheel> wheelsList) {
|
||||||
|
this.wheelsList = wheelsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(final Wheel wheel) {
|
||||||
|
wheelsList.add(wheel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Wheel> iterator() {
|
||||||
|
return getWheelsList().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEach(Consumer<? super Wheel> action) {
|
||||||
|
getWheelsList().forEach(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Spliterator<Wheel> spliterator() {
|
||||||
|
return getWheelsList().spliterator();
|
||||||
|
}
|
||||||
|
}
|
||||||
29
mapstruct-plus-core/pom.xml
Normal file
29
mapstruct-plus-core/pom.xml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>mapstruct-plus</artifactId>
|
||||||
|
<groupId>io.github.linpl</groupId>
|
||||||
|
<version>${mapstruct-plus.version}</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>mapstruct-plus-core</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package io.github.linpl;
|
||||||
|
|
||||||
|
import org.mapstruct.MappingTarget;
|
||||||
|
|
||||||
|
public interface BaseMapper<S, T> {
|
||||||
|
|
||||||
|
T convert(S source);
|
||||||
|
|
||||||
|
T convert(S source, @MappingTarget T target);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package io.github.linpl;
|
||||||
|
|
||||||
|
public class ConvertException extends RuntimeException {
|
||||||
|
|
||||||
|
public ConvertException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConvertException(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package io.github.linpl;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class Converter {
|
||||||
|
|
||||||
|
private final ConverterFactory converterFactory;
|
||||||
|
|
||||||
|
public Converter(final ConverterFactory converterFactory) {
|
||||||
|
this.converterFactory = converterFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <S, T> T convert(S source, Class<T> targetType) {
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
BaseMapper<S, T> mapper = (BaseMapper<S, T>) converterFactory.getMapper(source.getClass(), targetType);
|
||||||
|
if (mapper != null) {
|
||||||
|
return mapper.convert(source);
|
||||||
|
}
|
||||||
|
throw new ConvertException(
|
||||||
|
"cannot find converter from " + source.getClass().getSimpleName() + " to " + targetType.getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <S, T> T convert(S source, T target) {
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (target == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
BaseMapper<S, T> mapper = (BaseMapper<S, T>) converterFactory.getMapper(source.getClass(), target.getClass());
|
||||||
|
if (mapper != null) {
|
||||||
|
return mapper.convert(source);
|
||||||
|
}
|
||||||
|
throw new ConvertException("cannot find converter from " + source.getClass().getSimpleName() + " to " +
|
||||||
|
target.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public <S, T> List<T> convert(List<S> source, Class<T> targetType) {
|
||||||
|
if (source == null || source.size() == 0) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return source.stream().map(item -> convert(item, targetType)).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package io.github.linpl;
|
||||||
|
|
||||||
|
public interface ConverterFactory {
|
||||||
|
|
||||||
|
<S, T> BaseMapper<S, T> getMapper(Class<S> sourceType, Class<T> targetType);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package io.github.linpl.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
public @interface AutoMapper {
|
||||||
|
|
||||||
|
Class<?> target();
|
||||||
|
|
||||||
|
Class<?>[] uses() default {};
|
||||||
|
|
||||||
|
Class<?>[] imports() default {};
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package io.github.linpl.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
public @interface AutoMapping {
|
||||||
|
|
||||||
|
String target();
|
||||||
|
|
||||||
|
String dateFormat() default "";
|
||||||
|
|
||||||
|
String numberFormat() default "";
|
||||||
|
|
||||||
|
String constant() default "";
|
||||||
|
|
||||||
|
String expression() default "";
|
||||||
|
|
||||||
|
boolean ignore() default false;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package io.github.linpl.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在一个类或者接口上添加该注释,作为自动生成 Mapper 的配置类。在一个模块中,只能有一个有该注释的类。
|
||||||
|
* Marks a class or interface as configuration source. There can be only one annotated type in
|
||||||
|
* each compiled module.
|
||||||
|
*
|
||||||
|
* @author linpl
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface MapperConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所生成的 Mapper 接口的包
|
||||||
|
*/
|
||||||
|
String mapperPackage() default "";
|
||||||
|
|
||||||
|
}
|
||||||
52
mapstruct-plus-processor/pom.xml
Normal file
52
mapstruct-plus-processor/pom.xml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>mapstruct-plus</artifactId>
|
||||||
|
<groupId>io.github.linpl</groupId>
|
||||||
|
<version>${mapstruct-plus.version}</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>mapstruct-plus-processor</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.linpl</groupId>
|
||||||
|
<artifactId>mapstruct-plus-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baidu.lbsyun</groupId>
|
||||||
|
<artifactId>javapoet</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
<proc>none</proc>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
package io.github.linpl.processor;
|
||||||
|
|
||||||
|
import com.squareup.javapoet.AnnotationSpec;
|
||||||
|
import com.squareup.javapoet.ClassName;
|
||||||
|
import com.squareup.javapoet.FieldSpec;
|
||||||
|
import com.squareup.javapoet.JavaFile;
|
||||||
|
import com.squareup.javapoet.MethodSpec;
|
||||||
|
import com.squareup.javapoet.ParameterSpec;
|
||||||
|
import com.squareup.javapoet.TypeSpec;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.Collection;
|
||||||
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
|
import javax.lang.model.element.Modifier;
|
||||||
|
|
||||||
|
import static javax.tools.Diagnostic.Kind.ERROR;
|
||||||
|
|
||||||
|
public class AdapterMapperGenerator {
|
||||||
|
|
||||||
|
public void write(ProcessingEnvironment processingEnv, Collection<AdapterMethodMetadata> adapterMethods) {
|
||||||
|
// write Adapter
|
||||||
|
try (final Writer writer = processingEnv.getFiler()
|
||||||
|
.createSourceFile(
|
||||||
|
AutoMapperProperties.getAdapterPackage() + "." + AutoMapperProperties.getAdapterClassName())
|
||||||
|
.openWriter()) {
|
||||||
|
JavaFile.builder(AutoMapperProperties.getAdapterPackage(), createTypeSpec(adapterMethods))
|
||||||
|
.build()
|
||||||
|
.writeTo(writer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
processingEnv.getMessager()
|
||||||
|
.printMessage(ERROR,
|
||||||
|
"Error while opening " + AutoMapperProperties.getAdapterClassName() + " output file: " +
|
||||||
|
e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeSpec createTypeSpec(Collection<AdapterMethodMetadata> adapterMethods) {
|
||||||
|
TypeSpec.Builder adapterBuilder = TypeSpec.classBuilder(
|
||||||
|
ClassName.get(AutoMapperProperties.getAdapterPackage(), AutoMapperProperties.getAdapterClassName()))
|
||||||
|
.addModifiers(Modifier.PUBLIC)
|
||||||
|
.addAnnotation(ClassName.get("org.springframework.stereotype", "Component"));
|
||||||
|
|
||||||
|
adapterMethods.forEach(adapterMethod -> adapterBuilder.addField(buildMapperField(adapterMethod.getMapper()))
|
||||||
|
.addMethod(buildMapperSetterMethod(adapterMethod.getMapper()))
|
||||||
|
.addMethod(buildProxyMethod(adapterMethod)));
|
||||||
|
|
||||||
|
return adapterBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private FieldSpec buildMapperField(ClassName mapper) {
|
||||||
|
return FieldSpec.builder(mapper,
|
||||||
|
firstWordToLower(mapper.simpleName()), Modifier.PRIVATE).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String firstWordToLower(String str) {
|
||||||
|
return str.substring(0, 1).toLowerCase() + str.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodSpec buildProxyMethod(AdapterMethodMetadata adapterMethodMetadata) {
|
||||||
|
ParameterSpec parameterSpec = ParameterSpec.builder(adapterMethodMetadata.getSource(),
|
||||||
|
firstWordToLower(adapterMethodMetadata.getSource().simpleName())).build();
|
||||||
|
return MethodSpec.methodBuilder(firstWordToLower(adapterMethodMetadata.getSource().simpleName()) + "To" +
|
||||||
|
adapterMethodMetadata.getTarget().simpleName())
|
||||||
|
.addModifiers(Modifier.PUBLIC)
|
||||||
|
.addParameter(parameterSpec)
|
||||||
|
.returns(adapterMethodMetadata.getTarget())
|
||||||
|
.addStatement("return $N.convert($N)", firstWordToLower(adapterMethodMetadata.getMapper().simpleName()),
|
||||||
|
firstWordToLower(adapterMethodMetadata.getSource().simpleName()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodSpec buildMapperSetterMethod(ClassName mapper) {
|
||||||
|
ParameterSpec parameterSpec = buildMapperSetterParameter(mapper);
|
||||||
|
return MethodSpec.methodBuilder("set" + mapper.simpleName())
|
||||||
|
.addModifiers(Modifier.PUBLIC)
|
||||||
|
.addParameter(parameterSpec)
|
||||||
|
.addStatement("this.$N = $N", buildMapperField(mapper), parameterSpec)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ParameterSpec buildMapperSetterParameter(ClassName mapper) {
|
||||||
|
return ParameterSpec.builder(mapper,
|
||||||
|
firstWordToLower(mapper.simpleName()))
|
||||||
|
.addAnnotation(
|
||||||
|
AnnotationSpec.builder(ClassName.get("org.springframework.context.annotation", "Lazy")).build())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package io.github.linpl.processor;
|
||||||
|
|
||||||
|
import com.squareup.javapoet.ClassName;
|
||||||
|
|
||||||
|
public class AdapterMethodMetadata {
|
||||||
|
|
||||||
|
private AdapterMethodMetadata(final ClassName source, final ClassName target, ClassName mapper) {
|
||||||
|
this.source = source;
|
||||||
|
this.target = target;
|
||||||
|
this.mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ClassName source;
|
||||||
|
|
||||||
|
private final ClassName target;
|
||||||
|
|
||||||
|
private final ClassName mapper;
|
||||||
|
|
||||||
|
public static AdapterMethodMetadata newInstance(ClassName source, ClassName target, ClassName mapper) {
|
||||||
|
return new AdapterMethodMetadata(source, target, mapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMethodName() {
|
||||||
|
return source.simpleName().substring(0, 1).toLowerCase() + source.simpleName().substring(1) + "To" +
|
||||||
|
target.simpleName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassName getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassName getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassName getMapper() {
|
||||||
|
return mapper;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,112 @@
|
|||||||
|
package io.github.linpl.processor;
|
||||||
|
|
||||||
|
import com.squareup.javapoet.AnnotationSpec;
|
||||||
|
import com.squareup.javapoet.ClassName;
|
||||||
|
import com.squareup.javapoet.CodeBlock;
|
||||||
|
import com.squareup.javapoet.JavaFile;
|
||||||
|
import com.squareup.javapoet.MethodSpec;
|
||||||
|
import com.squareup.javapoet.ParameterSpec;
|
||||||
|
import com.squareup.javapoet.ParameterizedTypeName;
|
||||||
|
import com.squareup.javapoet.TypeSpec;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import javax.lang.model.element.Modifier;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import static io.github.linpl.processor.Constants.*;
|
||||||
|
|
||||||
|
public class AutoMapperGenerator {
|
||||||
|
|
||||||
|
public void write(AutoMapperMetadata metadata, Writer writer) {
|
||||||
|
try {
|
||||||
|
JavaFile.builder(AutoMapperProperties.getMapperPackage(), createTypeSpec(metadata)).build().writeTo(writer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeSpec createTypeSpec(AutoMapperMetadata metadata) {
|
||||||
|
ParameterizedTypeName converterName =
|
||||||
|
ParameterizedTypeName.get(ClassName.get(BASE_MAPPER_PACKAGE, BASE_MAPPER_CLASS_NAME),
|
||||||
|
metadata.getSourceClassName(), metadata.getTargetClassName());
|
||||||
|
|
||||||
|
TypeSpec.Builder builder = TypeSpec.interfaceBuilder(metadata.mapperName())
|
||||||
|
.addSuperinterface(converterName)
|
||||||
|
.addModifiers(Modifier.PUBLIC)
|
||||||
|
.addAnnotation(buildGeneratedMapperAnnotationSpec(metadata));
|
||||||
|
if (metadata.getFieldMappingList() != null && !metadata.getFieldMappingList().isEmpty()) {
|
||||||
|
final ParameterSpec source = ParameterSpec.builder(metadata.getSourceClassName(), "source").build();
|
||||||
|
final ParameterSpec target = ParameterSpec.builder(metadata.getTargetClassName(), "target")
|
||||||
|
.addAnnotation(AnnotationSpec.builder(ClassName.get("org.mapstruct", "MappingTarget")).build())
|
||||||
|
.build();
|
||||||
|
builder.addMethod(addConvertMethodSpec(Collections.singletonList(source), metadata.getFieldMappingList(),
|
||||||
|
metadata.getTargetClassName()));
|
||||||
|
builder.addMethod(addConvertMethodSpec(Arrays.asList(source, target), metadata.getFieldMappingList(),
|
||||||
|
metadata.getTargetClassName()));
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodSpec addConvertMethodSpec(List<ParameterSpec> parameterSpecs,
|
||||||
|
List<AutoMappingMetadata> autoMappingMetadataList,
|
||||||
|
ClassName target) {
|
||||||
|
return MethodSpec.methodBuilder("convert")
|
||||||
|
.addParameters(parameterSpecs)
|
||||||
|
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
|
||||||
|
.addAnnotations(buildMappingAnnotations(autoMappingMetadataList))
|
||||||
|
.returns(target)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<AnnotationSpec> buildMappingAnnotations(final List<AutoMappingMetadata> autoMappingMetadataList) {
|
||||||
|
return autoMappingMetadataList.stream().map(autoMappingMetadata -> {
|
||||||
|
final AnnotationSpec.Builder builder = AnnotationSpec.builder(ClassName.get("org.mapstruct", "Mapping"))
|
||||||
|
.addMember("target", CodeBlock.builder().add("$S", autoMappingMetadata.getTarget()).build())
|
||||||
|
|
||||||
|
.addMember("dateFormat",
|
||||||
|
CodeBlock.builder().add("$S", autoMappingMetadata.getDateFormat()).build())
|
||||||
|
.addMember("numberFormat",
|
||||||
|
CodeBlock.builder().add("$S", autoMappingMetadata.getNumberFormat()).build())
|
||||||
|
.addMember("ignore", CodeBlock.builder().add(String.valueOf(autoMappingMetadata.isIgnore())).build());
|
||||||
|
if (StringUtils.isNoneEmpty(autoMappingMetadata.getExpression())) {
|
||||||
|
builder.addMember("expression",
|
||||||
|
CodeBlock.builder().add("$S", autoMappingMetadata.getExpression()).build());
|
||||||
|
} else {
|
||||||
|
builder.addMember("source", CodeBlock.builder().add("$S", autoMappingMetadata.getSource()).build());
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnnotationSpec buildGeneratedMapperAnnotationSpec(AutoMapperMetadata metadata) {
|
||||||
|
List<ClassName> usesClassNameList =
|
||||||
|
Optional.ofNullable(metadata.getUsesClassNameList()).orElse(new ArrayList<>());
|
||||||
|
|
||||||
|
// config
|
||||||
|
CodeBlock configCodeBlock = CodeBlock.builder()
|
||||||
|
.add("$T.class",
|
||||||
|
ClassName.get(AutoMapperProperties.getMapperPackage(), AutoMapperProperties.getConfigClassName()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// uses
|
||||||
|
CodeBlock.Builder usesCodeBuilder = CodeBlock.builder().add("{");
|
||||||
|
usesClassNameList.forEach(item -> usesCodeBuilder.add("$T.class", item));
|
||||||
|
CodeBlock usesCodeBlock = usesCodeBuilder.add("}").build();
|
||||||
|
|
||||||
|
AnnotationSpec.Builder builder =
|
||||||
|
AnnotationSpec.builder(ClassName.get(MAPSTRUCT_MAPPER_PACKAGE, MAPSTRUCT_MAPPER_CLASS_NAME))
|
||||||
|
.addMember("config", configCodeBlock)
|
||||||
|
.addMember("uses", usesCodeBlock);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
package io.github.linpl.processor;
|
||||||
|
|
||||||
|
import com.squareup.javapoet.ClassName;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AutoMapperMetadata {
|
||||||
|
|
||||||
|
private ClassName sourceClassName;
|
||||||
|
|
||||||
|
private ClassName targetClassName;
|
||||||
|
|
||||||
|
private List<ClassName> usesClassNameList;
|
||||||
|
|
||||||
|
private List<AutoMappingMetadata> fieldMappingList;
|
||||||
|
|
||||||
|
public String mapperName() {
|
||||||
|
return sourceClassName.simpleName() + "To" + targetClassName.simpleName() + "Mapper";
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassName getSourceClassName() {
|
||||||
|
return sourceClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AutoMapperMetadata setSourceClassName(final ClassName sourceClassName) {
|
||||||
|
this.sourceClassName = sourceClassName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassName getTargetClassName() {
|
||||||
|
return targetClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AutoMapperMetadata setTargetClassName(final ClassName targetClassName) {
|
||||||
|
this.targetClassName = targetClassName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ClassName> getUsesClassNameList() {
|
||||||
|
return usesClassNameList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AutoMapperMetadata setUsesClassNameList(final List<ClassName> usesClassNameList) {
|
||||||
|
this.usesClassNameList = usesClassNameList;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AutoMappingMetadata> getFieldMappingList() {
|
||||||
|
return fieldMappingList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AutoMapperMetadata setFieldMappingList(final List<AutoMappingMetadata> fieldMappingList) {
|
||||||
|
this.fieldMappingList = fieldMappingList;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,238 @@
|
|||||||
|
package io.github.linpl.processor;
|
||||||
|
|
||||||
|
import com.squareup.javapoet.ClassName;
|
||||||
|
import io.github.linpl.annotations.AutoMapper;
|
||||||
|
import io.github.linpl.annotations.AutoMapping;
|
||||||
|
import io.github.linpl.annotations.MapperConfig;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import javax.annotation.processing.AbstractProcessor;
|
||||||
|
import javax.annotation.processing.RoundEnvironment;
|
||||||
|
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.ElementKind;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.lang.model.type.MirroredTypeException;
|
||||||
|
import javax.lang.model.type.MirroredTypesException;
|
||||||
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
import javax.tools.Diagnostic;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import static io.github.linpl.processor.Constants.AUTO_MAPPER_ANNOTATION;
|
||||||
|
import static io.github.linpl.processor.Constants.MAPPER_CONFIG_ANNOTATION;
|
||||||
|
import static javax.tools.Diagnostic.Kind.ERROR;
|
||||||
|
|
||||||
|
@SupportedAnnotationTypes({AUTO_MAPPER_ANNOTATION, MAPPER_CONFIG_ANNOTATION})
|
||||||
|
public class AutoMapperProcessor extends AbstractProcessor {
|
||||||
|
|
||||||
|
private final AutoMapperGenerator mapperGenerator;
|
||||||
|
|
||||||
|
private final AdapterMapperGenerator adapterMapperGenerator;
|
||||||
|
|
||||||
|
private final MapperConfigGenerator mapperConfigGenerator;
|
||||||
|
|
||||||
|
private final Map<String, AdapterMethodMetadata> methodMap = new HashMap<>();
|
||||||
|
|
||||||
|
private final Set<String> mapperSet = new HashSet<>();
|
||||||
|
|
||||||
|
public AutoMapperProcessor() {
|
||||||
|
this.mapperGenerator = new AutoMapperGenerator();
|
||||||
|
this.adapterMapperGenerator = new AdapterMapperGenerator();
|
||||||
|
this.mapperConfigGenerator = new MapperConfigGenerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAutoMapperAnnotation(TypeElement annotation) {
|
||||||
|
return AUTO_MAPPER_ANNOTATION.contentEquals(annotation.getQualifiedName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMapperConfigAnnotation(TypeElement annotation) {
|
||||||
|
return MAPPER_CONFIG_ANNOTATION.contentEquals(annotation.getQualifiedName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
|
||||||
|
boolean hasAutoMapper = annotations.stream().anyMatch(this::isAutoMapperAnnotation);
|
||||||
|
if (!hasAutoMapper) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "start refresh properties");
|
||||||
|
refreshProperties(annotations, roundEnv);
|
||||||
|
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "start write config class");
|
||||||
|
writeConfigClass();
|
||||||
|
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "start generate mapper class");
|
||||||
|
annotations.stream()
|
||||||
|
.filter(this::isAutoMapperAnnotation)
|
||||||
|
.forEach(annotation -> processAutoMapperAnnotation(roundEnv, annotation));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshProperties(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
|
||||||
|
annotations.stream()
|
||||||
|
.filter(this::isMapperConfigAnnotation)
|
||||||
|
.findFirst()
|
||||||
|
.flatMap(annotation -> roundEnv.getElementsAnnotatedWith(annotation).stream().findFirst())
|
||||||
|
.ifPresent(element -> {
|
||||||
|
final MapperConfig mapperConfig = element.getAnnotation(MapperConfig.class);
|
||||||
|
String mapperPackage = StringUtils.isEmpty(mapperConfig.mapperPackage()) ? getPackageName(element)
|
||||||
|
: mapperConfig.mapperPackage();
|
||||||
|
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "mapper package " + mapperPackage);
|
||||||
|
AutoMapperProperties.setMapperPackage(mapperPackage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPackageName(Element element) {
|
||||||
|
return String.valueOf(processingEnv.getElementUtils().getPackageOf(element).getQualifiedName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeConfigClass() {
|
||||||
|
mapperConfigGenerator.write(processingEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processAutoMapperAnnotation(final RoundEnvironment roundEnv, final TypeElement annotation) {
|
||||||
|
final List<AutoMapperMetadata> autoMapperMetadataList = roundEnv.getElementsAnnotatedWith(annotation)
|
||||||
|
.stream()
|
||||||
|
.map(this::buildAutoMapperMetadata)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
autoMapperMetadataList.forEach(autoMapperMetadata -> mapperSet.add(autoMapperMetadata.mapperName()));
|
||||||
|
|
||||||
|
List<AutoMapperMetadata> reverseMapperMetadataList = new ArrayList<>();
|
||||||
|
|
||||||
|
autoMapperMetadataList.forEach(autoMapperMetadata -> {
|
||||||
|
final AutoMapperMetadata reverseMapperMetadata = reverseMapper(autoMapperMetadata);
|
||||||
|
if (!mapperSet.add(reverseMapperMetadata.mapperName())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reverseMapperMetadataList.add(reverseMapperMetadata);
|
||||||
|
});
|
||||||
|
|
||||||
|
autoMapperMetadataList.addAll(reverseMapperMetadataList);
|
||||||
|
|
||||||
|
autoMapperMetadataList.forEach(this::writeAutoMapperClassFile);
|
||||||
|
|
||||||
|
adapterMapperGenerator.write(processingEnv, methodMap.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
private AutoMapperMetadata reverseMapper(AutoMapperMetadata autoMapperMetadata) {
|
||||||
|
AutoMapperMetadata reverseMapperMetadata = new AutoMapperMetadata();
|
||||||
|
reverseMapperMetadata.setSourceClassName(autoMapperMetadata.getTargetClassName());
|
||||||
|
reverseMapperMetadata.setTargetClassName(autoMapperMetadata.getSourceClassName());
|
||||||
|
// 需要继承的属性
|
||||||
|
final List<AutoMappingMetadata> fieldMetadataList = autoMapperMetadata.getFieldMappingList().stream()
|
||||||
|
.map(fieldMapping -> {
|
||||||
|
final AutoMappingMetadata autoMappingMetadata = new AutoMappingMetadata();
|
||||||
|
autoMappingMetadata.setSource(fieldMapping.getTarget());
|
||||||
|
autoMappingMetadata.setTarget(fieldMapping.getSource());
|
||||||
|
return autoMappingMetadata;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
reverseMapperMetadata.setFieldMappingList(fieldMetadataList);
|
||||||
|
return reverseMapperMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeAutoMapperClassFile(AutoMapperMetadata metadata) {
|
||||||
|
String mapperPackage = AutoMapperProperties.getMapperPackage();
|
||||||
|
String mapperClassName = metadata.mapperName();
|
||||||
|
try (final Writer writer = processingEnv.getFiler()
|
||||||
|
.createSourceFile(mapperPackage + "." + mapperClassName)
|
||||||
|
.openWriter()) {
|
||||||
|
mapperGenerator.write(metadata, writer);
|
||||||
|
addAdapterMethod(metadata.getSourceClassName(), metadata.getTargetClassName(),
|
||||||
|
ClassName.get(mapperPackage, mapperClassName));
|
||||||
|
} catch (IOException e) {
|
||||||
|
processingEnv.getMessager()
|
||||||
|
.printMessage(ERROR,
|
||||||
|
"Error while opening " + metadata.mapperName() + " output file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAdapterMethod(ClassName source, ClassName target, ClassName mapper) {
|
||||||
|
AdapterMethodMetadata adapterMethodMetadata = AdapterMethodMetadata.newInstance(source, target, mapper);
|
||||||
|
methodMap.put(adapterMethodMetadata.getMethodName(), adapterMethodMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AutoMapperMetadata buildAutoMapperMetadata(final Element ele) {
|
||||||
|
AutoMapper autoMapperAnnotation = ele.getAnnotation(AutoMapper.class);
|
||||||
|
if (autoMapperAnnotation == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassName source = ClassName.get((TypeElement) ele);
|
||||||
|
ClassName target = transToClassName(autoMapperAnnotation::target);
|
||||||
|
if (target == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<ClassName> uses = transToClassNameList(autoMapperAnnotation::uses);
|
||||||
|
List<AutoMappingMetadata> autoMappingMetadataList = buildFieldMappingMetadata((TypeElement) ele);
|
||||||
|
|
||||||
|
AutoMapperMetadata metadata = new AutoMapperMetadata();
|
||||||
|
|
||||||
|
metadata.setSourceClassName(source);
|
||||||
|
metadata.setTargetClassName(target);
|
||||||
|
metadata.setUsesClassNameList(uses);
|
||||||
|
metadata.setFieldMappingList(autoMappingMetadataList);
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<AutoMappingMetadata> buildFieldMappingMetadata(final TypeElement autoMapperEle) {
|
||||||
|
List<AutoMappingMetadata> list = new ArrayList<>();
|
||||||
|
|
||||||
|
if (!autoMapperEle.getKind().isClass()) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Element ele : autoMapperEle.getEnclosedElements()) {
|
||||||
|
if (ele.getKind() != ElementKind.FIELD) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
AutoMapping autoMapping = ele.getAnnotation(AutoMapping.class);
|
||||||
|
if (autoMapping == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoMappingMetadata metadata = new AutoMappingMetadata();
|
||||||
|
metadata.setTarget(autoMapping.target());
|
||||||
|
metadata.setSource(ele.getSimpleName().toString());
|
||||||
|
metadata.setIgnore(autoMapping.ignore());
|
||||||
|
list.add(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClassName transToClassName(Supplier<Class<?>> classSupplier) {
|
||||||
|
TypeMirror typeMirror = null;
|
||||||
|
try {
|
||||||
|
Class<?> targetClass = classSupplier.get();
|
||||||
|
} catch (MirroredTypeException e) {
|
||||||
|
typeMirror = e.getTypeMirror();
|
||||||
|
}
|
||||||
|
if (typeMirror == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (ClassName) ClassName.get(typeMirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ClassName> transToClassNameList(Supplier<Class<?>[]> classSuppler) {
|
||||||
|
List<? extends TypeMirror> typeMirrors = null;
|
||||||
|
try {
|
||||||
|
Class<?>[] classes = classSuppler.get();
|
||||||
|
} catch (MirroredTypesException e) {
|
||||||
|
typeMirrors = e.getTypeMirrors();
|
||||||
|
}
|
||||||
|
return typeMirrors.stream()
|
||||||
|
.map(typeMirror -> (ClassName) ClassName.get(typeMirror))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package io.github.linpl.processor;
|
||||||
|
|
||||||
|
import static io.github.linpl.processor.Constants.*;
|
||||||
|
|
||||||
|
public class AutoMapperProperties {
|
||||||
|
|
||||||
|
|
||||||
|
private static String mapperPackage = DEFAULT_MAPPER_PACKAGE;
|
||||||
|
|
||||||
|
private static String adapterPackage = mapperPackage;
|
||||||
|
|
||||||
|
private static String adapterClassName = DEFAULT_ADAPTER_CLASS_NAME;
|
||||||
|
|
||||||
|
private static String configClassName = AUTO_MAPPER_CONFIG_CLASS_NAME;
|
||||||
|
|
||||||
|
public static String getMapperPackage() {
|
||||||
|
return mapperPackage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getAdapterPackage() {
|
||||||
|
return getMapperPackage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getAdapterClassName() {
|
||||||
|
return adapterClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getConfigClassName() {
|
||||||
|
return configClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setMapperPackage(final String mapperPackage) {
|
||||||
|
AutoMapperProperties.mapperPackage = mapperPackage;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
package io.github.linpl.processor;
|
||||||
|
|
||||||
|
public class AutoMappingMetadata {
|
||||||
|
|
||||||
|
private String target = "";
|
||||||
|
|
||||||
|
private String source = "";
|
||||||
|
|
||||||
|
private String dateFormat = "";
|
||||||
|
|
||||||
|
private String numberFormat = "";
|
||||||
|
|
||||||
|
private String expression = "";
|
||||||
|
|
||||||
|
private boolean ignore = false;
|
||||||
|
|
||||||
|
public String getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTarget(final String target) {
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSource(final String source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDateFormat() {
|
||||||
|
return dateFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateFormat(final String dateFormat) {
|
||||||
|
this.dateFormat = dateFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNumberFormat() {
|
||||||
|
return numberFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumberFormat(final String numberFormat) {
|
||||||
|
this.numberFormat = numberFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExpression() {
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpression(final String expression) {
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIgnore() {
|
||||||
|
return ignore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIgnore(final boolean ignore) {
|
||||||
|
this.ignore = ignore;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package io.github.linpl.processor;
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
|
||||||
|
private static final String DEFAULT_BASE_PACKAGE = AutoMapperProcessor.class.getPackage().getName();
|
||||||
|
|
||||||
|
public static final String DEFAULT_MAPPER_PACKAGE = DEFAULT_BASE_PACKAGE + ".mappers";
|
||||||
|
|
||||||
|
public static final String DEFAULT_ADAPTER_CLASS_NAME = "ConvertMapperAdapter";
|
||||||
|
|
||||||
|
|
||||||
|
public static final String AUTO_MAPPER_CONFIG_CLASS_NAME = "AutoMapperConfig";
|
||||||
|
|
||||||
|
public static final String AUTO_MAPPER_ANNOTATION = "io.github.linpl.annotations.AutoMapper";
|
||||||
|
|
||||||
|
public static final String MAPPER_CONFIG_ANNOTATION = "io.github.linpl.annotations.MapperConfig";
|
||||||
|
|
||||||
|
public static final String BASE_MAPPER_PACKAGE = "io.github.linpl";
|
||||||
|
|
||||||
|
public static final String BASE_MAPPER_CLASS_NAME = "BaseMapper";
|
||||||
|
|
||||||
|
public static final String MAPSTRUCT_MAPPER_PACKAGE = "org.mapstruct";
|
||||||
|
|
||||||
|
public static final String MAPSTRUCT_MAPPER_CLASS_NAME = "Mapper";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
package io.github.linpl.processor;
|
||||||
|
|
||||||
|
import com.squareup.javapoet.AnnotationSpec;
|
||||||
|
import com.squareup.javapoet.ClassName;
|
||||||
|
import com.squareup.javapoet.CodeBlock;
|
||||||
|
import com.squareup.javapoet.JavaFile;
|
||||||
|
import com.squareup.javapoet.TypeSpec;
|
||||||
|
import io.github.linpl.annotations.AutoMapper;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
|
import javax.annotation.processing.RoundEnvironment;
|
||||||
|
import javax.lang.model.element.Modifier;
|
||||||
|
|
||||||
|
import static javax.tools.Diagnostic.Kind.ERROR;
|
||||||
|
|
||||||
|
public class MapperConfigGenerator {
|
||||||
|
|
||||||
|
public void write(ProcessingEnvironment processingEnv) {
|
||||||
|
try (final Writer writer = processingEnv.getFiler()
|
||||||
|
.createSourceFile(AutoMapperProperties.getMapperPackage() + "." + AutoMapperProperties.getConfigClassName())
|
||||||
|
.openWriter()) {
|
||||||
|
JavaFile.builder(AutoMapperProperties.getMapperPackage(), createConfigTypeSpec()).build().writeTo(writer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
processingEnv.getMessager()
|
||||||
|
.printMessage(ERROR,
|
||||||
|
"Error while opening " + AutoMapperProperties.getConfigClassName() + " output file: " +
|
||||||
|
e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeSpec createConfigTypeSpec() {
|
||||||
|
return TypeSpec.interfaceBuilder(AutoMapperProperties.getConfigClassName())
|
||||||
|
.addModifiers(Modifier.PUBLIC)
|
||||||
|
.addAnnotation(buildMapperConfigAnnotationSpec())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnnotationSpec buildMapperConfigAnnotationSpec() {
|
||||||
|
CodeBlock.Builder usesCodeBuilder = CodeBlock.builder().add("{");
|
||||||
|
usesCodeBuilder.add("$T.class",
|
||||||
|
ClassName.get(AutoMapperProperties.getAdapterPackage(), AutoMapperProperties.getAdapterClassName()));
|
||||||
|
CodeBlock usesCodeBlock = usesCodeBuilder.add("}").build();
|
||||||
|
return AnnotationSpec.builder(ClassName.get("org.mapstruct", "MapperConfig"))
|
||||||
|
.addMember("componentModel", "\"spring\"")
|
||||||
|
.addMember("uses", usesCodeBlock)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
io.github.linpl.processor.AutoMapperProcessor
|
||||||
49
mapstruct-plus-spring-boot-starter/pom.xml
Normal file
49
mapstruct-plus-spring-boot-starter/pom.xml
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>mapstruct-plus</artifactId>
|
||||||
|
<groupId>io.github.linpl</groupId>
|
||||||
|
<version>${mapstruct-plus.version}</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<spring-boot.version>2.4.5</spring-boot.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-dependencies</artifactId>
|
||||||
|
<version>${spring-boot.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.linpl</groupId>
|
||||||
|
<artifactId>mapstruct-plus-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package io.github.linpl.mapstruct;
|
||||||
|
|
||||||
|
import io.github.linpl.Converter;
|
||||||
|
import io.github.linpl.ConverterFactory;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class MapstructAutoConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ConverterFactory converterFactory(ApplicationContext applicationContext) {
|
||||||
|
return new SpringConverterFactory(applicationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Converter converter(ConverterFactory converterFactory) {
|
||||||
|
return new Converter(converterFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package io.github.linpl.mapstruct;
|
||||||
|
|
||||||
|
import io.github.linpl.BaseMapper;
|
||||||
|
import io.github.linpl.ConverterFactory;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.core.ResolvableType;
|
||||||
|
|
||||||
|
public class SpringConverterFactory implements ConverterFactory {
|
||||||
|
|
||||||
|
private final ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
public SpringConverterFactory(final ApplicationContext applicationContext) {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <S, T> BaseMapper<S, T> getMapper(final Class<S> sourceType, final Class<T> targetType) {
|
||||||
|
ResolvableType type = ResolvableType.forClassWithGenerics(
|
||||||
|
BaseMapper.class, sourceType, targetType);
|
||||||
|
String[] beanNames = applicationContext.getBeanNamesForType(type);
|
||||||
|
if (beanNames.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (BaseMapper<S, T>) applicationContext.getBean(beanNames[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=io.github.linpl.mapstruct.MapstructAutoConfiguration
|
||||||
98
pom.xml
Normal file
98
pom.xml
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>io.github.linpl</groupId>
|
||||||
|
<artifactId>mapstruct-plus</artifactId>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<version>${mapstruct-plus.version}</version>
|
||||||
|
<modules>
|
||||||
|
<module>mapstruct-plus-core</module>
|
||||||
|
<module>mapstruct-plus-spring-boot-starter</module>
|
||||||
|
<module>mapstruct-plus-processor</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<mapstruct-plus.version>1.0.0</mapstruct-plus.version>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.linpl</groupId>
|
||||||
|
<artifactId>mapstruct-plus-core</artifactId>
|
||||||
|
<version>${mapstruct-plus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.linpl</groupId>
|
||||||
|
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
|
||||||
|
<version>${mapstruct-plus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baidu.lbsyun</groupId>
|
||||||
|
<artifactId>javapoet</artifactId>
|
||||||
|
<version>1.9.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.12.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct</artifactId>
|
||||||
|
<version>1.5.1.Final</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-core</artifactId>
|
||||||
|
<version>5.3.23</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>flatten-maven-plugin</artifactId>
|
||||||
|
<version>1.1.0</version>
|
||||||
|
<configuration>
|
||||||
|
<updatePomFile>true</updatePomFile>
|
||||||
|
<flattenMode>resolveCiFriendliesOnly</flattenMode>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>flatten</id>
|
||||||
|
<phase>process-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>flatten</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>flatten.clean</id>
|
||||||
|
<phase>clean</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>clean</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>flatten-maven-plugin</artifactId>
|
||||||
|
<version>1.1.0</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
Loading…
x
Reference in New Issue
Block a user