增加适配非Spring版本的,增加缓存等优化

This commit is contained in:
linpeilie 2023-02-22 23:30:04 +08:00
parent 88161fb531
commit 4e2864c7f5
58 changed files with 764 additions and 228 deletions

View File

@ -2,17 +2,16 @@
<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.linpeilie</groupId>
<artifactId>example</artifactId>
<packaging>pom</packaging>
<version>1.0.0</version>
<modules>
<module>quick-start</module>
<module>spring-boot</module>
</modules>
<properties>
<maven.compiler.source>8</maven.compiler.source>
@ -20,34 +19,35 @@
<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>
<spring-boot.version>2.7.0</spring-boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>${mapstruct-plus.version}</version>
</dependency>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus</artifactId>
<version>${mapstruct-plus.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>io.github.linpeilie</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>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.7.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
@ -69,7 +69,6 @@
<artifactId>mapstruct-plus-processor</artifactId>
<version>${mapstruct-plus.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>

View File

@ -0,0 +1,8 @@
package io.github.linpeilie;
import io.github.linpeilie.annotations.ComponentModelConfig;
import io.github.linpeilie.annotations.MapperConfig;
@ComponentModelConfig(componentModel = "default")
public class MapperConfiguration {
}

View File

@ -0,0 +1,20 @@
package io.github.linpeilie;
import io.github.linpeilie.model.Car;
import io.github.linpeilie.model.CarDto;
import io.github.linpeilie.model.CarType;
public class QuickStart {
private static Converter converter = new Converter();
public static void main(String[] args) {
final Car car = new Car();
car.setType(CarType.OTHER);
final CarDto carDto = converter.convert(car, CarDto.class);
System.out.println(carDto);
}
}

View File

@ -1,7 +1,7 @@
package io.github.linpl.mapstruct.dto;
package io.github.linpeilie.model;
import io.github.linpl.annotations.AutoMapper;
import io.github.linpl.annotations.AutoMapping;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMapping;
@AutoMapper(target = CarDto.class)
public class Car {

View File

@ -1,4 +1,4 @@
package io.github.linpl.mapstruct.dto;
package io.github.linpeilie.model;
import java.util.List;

View File

@ -1,4 +1,4 @@
package io.github.linpl.mapstruct.dto;
package io.github.linpeilie.model;
public enum CarType {
SPORTS, OTHER

View File

@ -1,6 +1,6 @@
package io.github.linpl.mapstruct.dto;
package io.github.linpeilie.model;
import io.github.linpl.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMapper;
@AutoMapper(target = SeatConfigurationDto.class)
public class SeatConfiguration {

View File

@ -1,4 +1,4 @@
package io.github.linpl.mapstruct.dto;
package io.github.linpeilie.model;
public class SeatConfigurationDto {
private int seatCount;

View File

@ -1,4 +1,4 @@
package io.github.linpl.mapstruct.dto;
package io.github.linpeilie.model;
public enum SeatMaterial {
LEATHER, FABRIC

View File

@ -1,6 +1,6 @@
package io.github.linpl.mapstruct.dto;
package io.github.linpeilie.model;
import io.github.linpl.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMapper;
import java.util.Objects;
@AutoMapper(target = WheelDto.class)

View File

@ -1,4 +1,4 @@
package io.github.linpl.mapstruct.dto;
package io.github.linpeilie.model;
import java.util.Objects;

View File

@ -1,4 +1,4 @@
package io.github.linpl.mapstruct.dto;
package io.github.linpeilie.model;
public enum WheelPosition {
LEFT_FRONT,

View File

@ -1,4 +1,4 @@
package io.github.linpl.mapstruct.dto;
package io.github.linpeilie.model;
import java.util.ArrayList;
import java.util.Iterator;

View File

@ -0,0 +1,32 @@
<?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>example</artifactId>
<groupId>io.github.linpeilie</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-boot</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.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,15 +1,11 @@
package io.github.linpl.mapstruct;
package io.github.linpeilie;
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);
}

View File

@ -0,0 +1,29 @@
package io.github.linpeilie;
import io.github.linpeilie.model.Car;
import io.github.linpeilie.model.CarDto;
import io.github.linpeilie.model.CarType;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class StartUp {
private Converter converter;
@Autowired
public void setConverter(final Converter converter) {
this.converter = converter;
}
@PostConstruct
public void start() {
final Car car = new Car();
car.setType(CarType.OTHER);
final CarDto carDto = converter.convert(car, CarDto.class);
System.out.println(carDto);
}
}

View File

@ -0,0 +1,47 @@
package io.github.linpeilie.model;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.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;
}
}

View File

@ -0,0 +1,52 @@
package io.github.linpeilie.model;
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 +
'}';
}
}

View File

@ -0,0 +1,5 @@
package io.github.linpeilie.model;
public enum CarType {
SPORTS, OTHER
}

View File

@ -0,0 +1,25 @@
package io.github.linpeilie.model;
import io.github.linpeilie.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;
}
}

View File

@ -0,0 +1,22 @@
package io.github.linpeilie.model;
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;
}
}

View File

@ -0,0 +1,5 @@
package io.github.linpeilie.model;
public enum SeatMaterial {
LEATHER, FABRIC
}

View File

@ -0,0 +1,39 @@
package io.github.linpeilie.model;
import io.github.linpeilie.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);
}
}

View File

@ -0,0 +1,37 @@
package io.github.linpeilie.model;
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);
}
}

View File

@ -0,0 +1,8 @@
package io.github.linpeilie.model;
public enum WheelPosition {
LEFT_FRONT,
RIGHT_FRONT,
LEFT_REAR,
RIGHT_REAR
}

View File

@ -0,0 +1,38 @@
package io.github.linpeilie.model;
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();
}
}

View File

@ -1,7 +0,0 @@
package io.github.linpl.mapstruct;
import io.github.linpl.annotations.MapperConfig;
@MapperConfig(mapperPackage = "io.github.linpl.mapstruct.convert")
public class MapstructConfiguration {
}

View File

@ -1,29 +0,0 @@
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;
}
}

View File

@ -1,35 +0,0 @@
package io.github.linpl.annotations;
import io.github.linpl.BaseMapper;
import io.github.linpl.ConverterFactory;
import org.apache.commons.lang3.ClassUtils;
import org.mapstruct.factory.Mappers;
import sun.misc.ClassLoaderUtil;
public class DefaultConverterFactory implements ConverterFactory {
private final String basePackage;
public DefaultConverterFactory() {
this("");
}
public DefaultConverterFactory(final String basePackage) {
this.basePackage = basePackage;
// load mapper package
if (basePackage == null || basePackage.isEmpty()) {
loadBasePackage();
}
}
private void loadBasePackage() {
}
@Override
public <S, T> BaseMapper<S, T> getMapper(final Class<S> sourceType, final Class<T> targetType) {
}
}

View File

@ -3,7 +3,7 @@
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>
<artifactId>mapstruct-plus-pom</artifactId>
<groupId>io.github.linpeilie</groupId>
<version>${mapstruct-plus.version}</version>
<relativePath>../pom.xml</relativePath>
@ -21,7 +21,7 @@
<dependencies>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-core</artifactId>
<artifactId>mapstruct-plus</artifactId>
</dependency>
<dependency>
<groupId>com.baidu.lbsyun</groupId>

View File

@ -0,0 +1,36 @@
package io.github.linpeilie.processor;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;
import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import javax.annotation.processing.ProcessingEnvironment;
import static javax.tools.Diagnostic.Kind.ERROR;
public abstract class AbstractAdapterMapperGenerator {
public void write(ProcessingEnvironment processingEnv, Collection<AdapterMethodMetadata> adapterMethods) {
// write Adapter
try (final Writer writer = processingEnv.getFiler()
.createSourceFile(adapterPackage() + "." + adapterClassName())
.openWriter()) {
JavaFile.builder(adapterPackage(), createTypeSpec(adapterMethods)).build().writeTo(writer);
} catch (IOException e) {
processingEnv.getMessager()
.printMessage(ERROR, "Error while opening " + adapterClassName() + " output file: " + e.getMessage());
}
}
protected abstract TypeSpec createTypeSpec(Collection<AdapterMethodMetadata> adapterMethods);
protected String adapterPackage() {
return AutoMapperProperties.getAdapterPackage();
}
protected String adapterClassName() {
return AutoMapperProperties.getAdapterClassName();
}
}

View File

@ -1,4 +1,4 @@
package io.github.linpl.processor;
package io.github.linpeilie.processor;
import com.squareup.javapoet.ClassName;

View File

@ -1,4 +1,4 @@
package io.github.linpl.processor;
package io.github.linpeilie.processor;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
@ -20,13 +20,13 @@ import java.util.stream.Collectors;
import javax.lang.model.element.Modifier;
import org.apache.commons.lang3.StringUtils;
import static io.github.linpl.processor.Constants.*;
import static io.github.linpeilie.processor.Constants.*;
public class AutoMapperGenerator {
public void write(AutoMapperMetadata metadata, Writer writer) {
try {
JavaFile.builder(AutoMapperProperties.getMapperPackage(), createTypeSpec(metadata)).build().writeTo(writer);
JavaFile.builder(metadata.mapperPackage(), createTypeSpec(metadata)).build().writeTo(writer);
} catch (IOException e) {
throw new UncheckedIOException(e);
} catch (Exception e) {
@ -72,10 +72,8 @@ public class AutoMapperGenerator {
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("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",
@ -94,7 +92,7 @@ public class AutoMapperGenerator {
// config
CodeBlock configCodeBlock = CodeBlock.builder()
.add("$T.class",
ClassName.get(AutoMapperProperties.getMapperPackage(), AutoMapperProperties.getConfigClassName()))
ClassName.get(AutoMapperProperties.getConfigPackage(), AutoMapperProperties.getConfigClassName()))
.build();
// uses

View File

@ -1,7 +1,8 @@
package io.github.linpl.processor;
package io.github.linpeilie.processor;
import com.squareup.javapoet.ClassName;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
public class AutoMapperMetadata {
@ -13,6 +14,11 @@ public class AutoMapperMetadata {
private List<AutoMappingMetadata> fieldMappingList;
public String mapperPackage() {
return StringUtils.isNotEmpty(AutoMapperProperties.getMapperPackage())
? AutoMapperProperties.getMapperPackage() : sourceClassName.packageName();
}
public String mapperName() {
return sourceClassName.simpleName() + "To" + targetClassName.simpleName() + "Mapper";
}

View File

@ -1,10 +1,11 @@
package io.github.linpl.processor;
package io.github.linpeilie.processor;
import com.squareup.javapoet.ClassName;
import io.github.linpl.annotations.AutoMapper;
import io.github.linpl.annotations.AutoMapping;
import io.github.linpl.annotations.ComponentModelConfig;
import io.github.linpl.annotations.MapperConfig;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMapping;
import io.github.linpeilie.annotations.ComponentModelConfig;
import io.github.linpeilie.annotations.MapperConfig;
import java.awt.Component;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
@ -27,10 +28,11 @@ import javax.lang.model.type.MirroredTypesException;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import org.apache.commons.lang3.StringUtils;
import org.mapstruct.MappingConstants;
import static io.github.linpl.processor.Constants.AUTO_MAPPER_ANNOTATION;
import static io.github.linpl.processor.Constants.COMPONENT_MODEL_CONFIG_ANNOTATION;
import static io.github.linpl.processor.Constants.MAPPER_CONFIG_ANNOTATION;
import static io.github.linpeilie.processor.Constants.AUTO_MAPPER_ANNOTATION;
import static io.github.linpeilie.processor.Constants.COMPONENT_MODEL_CONFIG_ANNOTATION;
import static io.github.linpeilie.processor.Constants.MAPPER_CONFIG_ANNOTATION;
import static javax.tools.Diagnostic.Kind.ERROR;
@SupportedAnnotationTypes({AUTO_MAPPER_ANNOTATION, MAPPER_CONFIG_ANNOTATION, COMPONENT_MODEL_CONFIG_ANNOTATION})
@ -38,7 +40,7 @@ public class AutoMapperProcessor extends AbstractProcessor {
private final AutoMapperGenerator mapperGenerator;
private final AdapterMapperGenerator adapterMapperGenerator;
private AbstractAdapterMapperGenerator adapterMapperGenerator;
private final MapperConfigGenerator mapperConfigGenerator;
@ -48,7 +50,6 @@ public class AutoMapperProcessor extends AbstractProcessor {
public AutoMapperProcessor() {
this.mapperGenerator = new AutoMapperGenerator();
this.adapterMapperGenerator = new AdapterMapperGenerator();
this.mapperConfigGenerator = new MapperConfigGenerator();
}
@ -72,6 +73,11 @@ public class AutoMapperProcessor extends AbstractProcessor {
}
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "start refresh properties");
refreshProperties(annotations, roundEnv);
this.adapterMapperGenerator = AutoMapperProperties.getComponentModel()
.contentEquals(
MappingConstants.ComponentModel.SPRING) ? new SpringAdapterMapperGenerator() : new DefaultAdapterMapperGenerator();
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "start write config class");
writeConfigClass();
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "start generate mapper class");
@ -157,7 +163,7 @@ public class AutoMapperProcessor extends AbstractProcessor {
}
private void writeAutoMapperClassFile(AutoMapperMetadata metadata) {
String mapperPackage = AutoMapperProperties.getMapperPackage();
String mapperPackage = metadata.mapperPackage();
String mapperClassName = metadata.mapperName();
try (final Writer writer = processingEnv.getFiler()
.createSourceFile(mapperPackage + "." + mapperClassName)
@ -221,6 +227,9 @@ public class AutoMapperProcessor extends AbstractProcessor {
metadata.setTarget(autoMapping.target());
metadata.setSource(ele.getSimpleName().toString());
metadata.setIgnore(autoMapping.ignore());
metadata.setExpression(autoMapping.expression());
metadata.setDateFormat(autoMapping.dateFormat());
metadata.setNumberFormat(autoMapping.numberFormat());
list.add(metadata);
}

View File

@ -1,32 +1,31 @@
package io.github.linpl.processor;
package io.github.linpeilie.processor;
import static io.github.linpl.processor.Constants.*;
import static io.github.linpeilie.processor.Constants.*;
public class AutoMapperProperties {
private static String mapperPackage = DEFAULT_MAPPER_PACKAGE;
private static String mapperPackage;
private static String componentModel = DEFAULT_COMPONENT_MODEL;
private static final String adapterClassName = DEFAULT_ADAPTER_CLASS_NAME;
private static final String configClassName = AUTO_MAPPER_CONFIG_CLASS_NAME;
public static String getMapperPackage() {
return mapperPackage;
}
public static String getAdapterPackage() {
return getMapperPackage();
return DEFAULT_BASE_PACKAGE;
}
public static String getAdapterClassName() {
return adapterClassName;
return DEFAULT_ADAPTER_CLASS_NAME;
}
public static String getConfigPackage() {
return DEFAULT_BASE_PACKAGE;
}
public static String getConfigClassName() {
return configClassName;
return AUTO_MAPPER_CONFIG_CLASS_NAME;
}
public static String getComponentModel() {

View File

@ -1,4 +1,4 @@
package io.github.linpl.processor;
package io.github.linpeilie.processor;
public class AutoMappingMetadata {

View File

@ -1,25 +1,25 @@
package io.github.linpl.processor;
package io.github.linpeilie.processor;
import org.mapstruct.MappingConstants;
public class Constants {
private static final String DEFAULT_BASE_PACKAGE = AutoMapperProcessor.class.getPackage().getName();
public static final String DEFAULT_BASE_PACKAGE = "io.github.linpeilie";
public static final String DEFAULT_MAPPER_PACKAGE = DEFAULT_BASE_PACKAGE + ".mappers";
public static final String DEFAULT_COMPONENT_MODEL = "default";
public static final String DEFAULT_COMPONENT_MODEL = MappingConstants.ComponentModel.SPRING;
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 AUTO_MAPPER_ANNOTATION = "io.github.linpeilie.annotations.AutoMapper";
public static final String MAPPER_CONFIG_ANNOTATION = "io.github.linpl.annotations.MapperConfig";
public static final String MAPPER_CONFIG_ANNOTATION = "io.github.linpeilie.annotations.MapperConfig";
public static final String COMPONENT_MODEL_CONFIG_ANNOTATION = "io.github.linpl.annotations.ComponentModelConfig";
public static final String COMPONENT_MODEL_CONFIG_ANNOTATION = "io.github.linpeilie.annotations.ComponentModelConfig";
public static final String BASE_MAPPER_PACKAGE = "io.github.linpl";
public static final String BASE_MAPPER_PACKAGE = "io.github.linpeilie";
public static final String BASE_MAPPER_CLASS_NAME = "BaseMapper";

View File

@ -0,0 +1,85 @@
package io.github.linpeilie.processor;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
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 org.mapstruct.MappingConstants;
import static javax.tools.Diagnostic.Kind.ERROR;
public class DefaultAdapterMapperGenerator extends AbstractAdapterMapperGenerator {
public TypeSpec createTypeSpec(Collection<AdapterMethodMetadata> adapterMethods) {
TypeSpec.Builder adapterBuilder = TypeSpec.classBuilder(
ClassName.get(AutoMapperProperties.getAdapterPackage(), AutoMapperProperties.getAdapterClassName()))
.addModifiers(Modifier.PUBLIC);
if (AutoMapperProperties.getComponentModel().contentEquals(MappingConstants.ComponentModel.SPRING)) {
adapterMethods.forEach(adapterMethod -> adapterBuilder.addField(buildMapperField(adapterMethod.getMapper()))
.addMethod(buildMapperSetterMethod(adapterMethod.getMapper()))
.addMethod(buildSpringProxyMethod(adapterMethod)));
} else {
adapterMethods.forEach(adapterMethod -> adapterBuilder.addMethod(buildDefaultProxyMethod(adapterMethod)));
}
return adapterBuilder.build();
}
private MethodSpec buildSpringProxyMethod(final 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()))
.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 buildDefaultProxyMethod(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 ($T.getMapper($T.class)).convert($N)",
ClassName.get("org.mapstruct.factory", "Mappers"), adapterMethodMetadata.getMapper(),
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())).build();
}
}

View File

@ -1,4 +1,4 @@
package io.github.linpl.processor;
package io.github.linpeilie.processor;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
@ -16,9 +16,9 @@ public class MapperConfigGenerator {
public void write(ProcessingEnvironment processingEnv) {
try (final Writer writer = processingEnv.getFiler()
.createSourceFile(AutoMapperProperties.getMapperPackage() + "." + AutoMapperProperties.getConfigClassName())
.createSourceFile(AutoMapperProperties.getConfigPackage() + "." + AutoMapperProperties.getConfigClassName())
.openWriter()) {
JavaFile.builder(AutoMapperProperties.getMapperPackage(), createConfigTypeSpec()).build().writeTo(writer);
JavaFile.builder(AutoMapperProperties.getConfigPackage(), createConfigTypeSpec()).build().writeTo(writer);
} catch (IOException e) {
processingEnv.getMessager()
.printMessage(ERROR,

View File

@ -1,40 +1,18 @@
package io.github.linpl.processor;
package io.github.linpeilie.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 SpringAdapterMapperGenerator extends AbstractAdapterMapperGenerator {
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) {
@Override
protected TypeSpec createTypeSpec(Collection<AdapterMethodMetadata> adapterMethods) {
TypeSpec.Builder adapterBuilder = TypeSpec.classBuilder(
ClassName.get(AutoMapperProperties.getAdapterPackage(), AutoMapperProperties.getAdapterClassName()))
.addModifiers(Modifier.PUBLIC)
@ -74,6 +52,9 @@ public class AdapterMapperGenerator {
return MethodSpec.methodBuilder("set" + mapper.simpleName())
.addModifiers(Modifier.PUBLIC)
.addParameter(parameterSpec)
.addAnnotation(AnnotationSpec.builder(
ClassName.get("org.springframework.beans.factory.annotation", "Autowired"))
.build())
.addStatement("this.$N = $N", buildMapperField(mapper), parameterSpec)
.build();
}
@ -81,7 +62,8 @@ public class AdapterMapperGenerator {
private ParameterSpec buildMapperSetterParameter(ClassName mapper) {
return ParameterSpec.builder(mapper,
firstWordToLower(mapper.simpleName()))
.addAnnotation(
AnnotationSpec.builder(ClassName.get("org.springframework.context.annotation", "Lazy")).build())
.build();
}
}

View File

@ -1 +1 @@
io.github.linpl.processor.AutoMapperProcessor
io.github.linpeilie.processor.AutoMapperProcessor

View File

@ -3,7 +3,7 @@
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>
<artifactId>mapstruct-plus-pom</artifactId>
<groupId>io.github.linpeilie</groupId>
<version>${mapstruct-plus.version}</version>
<relativePath>../pom.xml</relativePath>
@ -34,7 +34,7 @@
<dependencies>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-core</artifactId>
<artifactId>mapstruct-plus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -1,12 +1,14 @@
package io.github.linpl.mapstruct;
package io.github.linpeilie.mapstruct;
import io.github.linpl.Converter;
import io.github.linpl.ConverterFactory;
import io.github.linpeilie.Converter;
import io.github.linpeilie.ConverterFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "io.github.linpeilie")
public class MapstructAutoConfiguration {
@Bean

View File

@ -1,11 +1,11 @@
package io.github.linpl.mapstruct;
package io.github.linpeilie.mapstruct;
import io.github.linpl.BaseMapper;
import io.github.linpl.ConverterFactory;
import io.github.linpeilie.AbstractCachedConverterFactory;
import io.github.linpeilie.BaseMapper;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;
public class SpringConverterFactory implements ConverterFactory {
public class SpringConverterFactory extends AbstractCachedConverterFactory {
private final ApplicationContext applicationContext;
@ -14,7 +14,7 @@ public class SpringConverterFactory implements ConverterFactory {
}
@Override
public <S, T> BaseMapper<S, T> getMapper(final Class<S> sourceType, final Class<T> targetType) {
public <S, T> BaseMapper<S, T> findMapper(final Class<S> sourceType, final Class<T> targetType) {
ResolvableType type = ResolvableType.forClassWithGenerics(
BaseMapper.class, sourceType, targetType);
String[] beanNames = applicationContext.getBeanNamesForType(type);

View File

@ -1,6 +0,0 @@
package io.github.linpl.mapstruct;
import io.github.linpl.annotations.ComponentModelConfig;
@ComponentModelConfig(componentModel = "spring")
public class ComponentConfiguration {}

View File

@ -1 +1 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=io.github.linpl.mapstruct.MapstructAutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=io.github.linpeilie.mapstruct.MapstructAutoConfiguration

View File

@ -0,0 +1,30 @@
package io.github.linpeilie;
import java.util.concurrent.ConcurrentHashMap;
public abstract class AbstractCachedConverterFactory implements ConverterFactory {
private final ConcurrentHashMap<String, BaseMapper> mapperMap = new ConcurrentHashMap<>();
@Override
@SuppressWarnings("unchecked")
public <S, T> BaseMapper<S, T> getMapper(final Class<S> sourceType, final Class<T> targetType) {
final String key = key(sourceType, targetType);
if (mapperMap.contains(key)) {
return mapperMap.get(key);
}
final BaseMapper mapper = findMapper(sourceType, targetType);
if (mapper != null) {
mapperMap.put(key, mapper);
return mapper;
}
return null;
}
protected abstract <S, T> BaseMapper findMapper(final Class<S> source, final Class<T> target);
private String key(Class<?> source, Class<?> target) {
return source.getName() + "__" + target.getName();
}
}

View File

@ -1,4 +1,4 @@
package io.github.linpl;
package io.github.linpeilie;
import org.mapstruct.MappingTarget;

View File

@ -1,4 +1,4 @@
package io.github.linpl;
package io.github.linpeilie;
public class ConvertException extends RuntimeException {

View File

@ -1,4 +1,4 @@
package io.github.linpl;
package io.github.linpeilie;
import java.util.Collections;
import java.util.List;
@ -8,6 +8,10 @@ public class Converter {
private final ConverterFactory converterFactory;
public Converter() {
this.converterFactory = new DefaultConverterFactory();
}
public Converter(final ConverterFactory converterFactory) {
this.converterFactory = converterFactory;
}

View File

@ -1,4 +1,4 @@
package io.github.linpl;
package io.github.linpeilie;
public interface ConverterFactory {

View File

@ -0,0 +1,101 @@
package io.github.linpeilie;
import io.github.linpeilie.annotations.MapperConfig;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import org.mapstruct.factory.Mappers;
public class DefaultConverterFactory extends AbstractCachedConverterFactory {
private String basePackage;
public DefaultConverterFactory() {
this("");
}
public DefaultConverterFactory(final String basePackage) {
this.basePackage = basePackage;
// load mapper package
if (basePackage == null || basePackage.isEmpty()) {
loadBasePackage();
}
}
private void loadBasePackage() {
final ClassLoader classLoader = this.getClass().getClassLoader();
final Enumeration<URL> resources;
try {
resources = classLoader.getResources("");
} catch (IOException e) {
throw new RuntimeException(e);
}
List<Class<?>> classes = new ArrayList<>();
while (resources.hasMoreElements()) {
final URL url = resources.nextElement();
if (url.getProtocol().equals("file")) {
loadClasses(null, url.getPath(), classes, classLoader);
}
}
classes.stream().filter(clazz -> clazz.isAnnotationPresent(MapperConfig.class)).findFirst().ifPresent(clazz -> {
final MapperConfig mapperConfig = clazz.getAnnotation(MapperConfig.class);
basePackage = mapperConfig.mapperPackage();
});
}
private void loadClasses(String root,
final String path,
final List<Class<?>> classes,
final ClassLoader classLoader) {
final File file = new File(path);
if (root == null) {
root = file.getPath();
}
if (file.isFile()) {
if (!file.getName().endsWith(".class")) {
return;
}
try {
String classPath = file.getPath();
String className = classPath.substring(root.length() + 1, classPath.length() - 6).replaceAll("/", ".");
classes.add(classLoader.loadClass(className));
} catch (Exception e) {
e.printStackTrace();
}
} else {
final File[] files = file.listFiles();
if (files == null) {
return;
}
for (File f : files) {
loadClasses(root, f.getPath(), classes, classLoader);
}
}
}
private String getMapperClassName(Class<?> source, Class<?> target) {
return source.getSimpleName() + "To" + target.getSimpleName() + "Mapper";
}
private String getMapperPackage(Class<?> sourceType) {
return basePackage != null && !basePackage.isEmpty() ? basePackage
: sourceType.getPackage().getName();
}
@Override
@SuppressWarnings("unchecked")
public <S, T> BaseMapper<S, T> findMapper(final Class<S> sourceType, final Class<T> targetType) {
final String mapperClassName = getMapperClassName(sourceType, targetType);
try {
final Class<?> mapperClass = Class.forName(getMapperPackage(sourceType) + "." + mapperClassName);
return (BaseMapper<S, T>) Mappers.getMapper(mapperClass);
} catch (ClassNotFoundException e) {
return null;
}
}
}

View File

@ -1,4 +1,4 @@
package io.github.linpl.annotations;
package io.github.linpeilie.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package io.github.linpl.annotations;
package io.github.linpeilie.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@ -1,10 +1,9 @@
package io.github.linpl.annotations;
package io.github.linpeilie.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.mapstruct.MappingConstants;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)

View File

@ -1,4 +1,4 @@
package io.github.linpl.annotations;
package io.github.linpeilie.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@ -13,7 +13,7 @@ import java.lang.annotation.Target;
* @author linpl
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MapperConfig {
/**

View File

@ -5,11 +5,11 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus</artifactId>
<artifactId>mapstruct-plus-pom</artifactId>
<packaging>pom</packaging>
<version>${mapstruct-plus.version}</version>
<modules>
<module>mapstruct-plus-core</module>
<module>mapstruct-plus</module>
<module>mapstruct-plus-spring-boot-starter</module>
<module>mapstruct-plus-processor</module>
</modules>
@ -25,7 +25,7 @@
<dependencies>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-core</artifactId>
<artifactId>mapstruct-plus</artifactId>
<version>${mapstruct-plus.version}</version>
</dependency>
<dependency>