11package org .mapstruct .extensions .spring .converter ;
22
3+ import static java .lang .Boolean .TRUE ;
34import static java .time .format .DateTimeFormatter .ISO_INSTANT ;
45import static java .util .stream .Collectors .toList ;
6+ import static java .util .stream .Stream .concat ;
7+ import static javax .lang .model .SourceVersion .RELEASE_8 ;
58import static javax .lang .model .element .Modifier .*;
69import static javax .tools .Diagnostic .Kind .WARNING ;
10+ import static org .apache .commons .lang3 .StringUtils .isNotEmpty ;
711
812import com .squareup .javapoet .*;
913import java .io .IOException ;
1014import java .io .UncheckedIOException ;
1115import java .io .Writer ;
1216import java .time .Clock ;
1317import java .time .ZonedDateTime ;
14- import java .util .ArrayList ;
1518import java .util .Collection ;
16- import java .util .List ;
1719import java .util .Optional ;
1820import java .util .concurrent .atomic .AtomicReference ;
21+ import java .util .stream .Stream ;
1922import javax .annotation .processing .ProcessingEnvironment ;
20- import org .apache .commons .lang3 .StringUtils ;
2123import org .apache .commons .lang3 .tuple .Pair ;
2224
2325public class ConversionServiceAdapterGenerator {
24- private static final String CONVERSION_SERVICE_PACKAGE_NAME = "org.springframework.core.convert" ;
25- private static final String CONVERSION_SERVICE_CLASS_NAME = "ConversionService" ;
26+ private static final ClassName CONVERSION_SERVICE_CLASS_NAME =
27+ ClassName . get ( "org.springframework.core.convert" , "ConversionService" ) ;
2628 private static final String CONVERSION_SERVICE_FIELD_NAME = "conversionService" ;
27- private static final String QUALIFIER_ANNOTATION_PACKAGE_NAME =
28- "org.springframework.beans.factory.annotation" ;
29- private static final String QUALIFIER_ANNOTATION_CLASSS_NAME = "Qualifier" ;
30- private static final String LAZY_ANNOTATION_PACKAGE_NAME =
31- "org.springframework.context.annotation" ;
32- private static final String LAZY_ANNOTATION_CLASS_NAME = "Lazy" ;
33- private static final ClassName TYPE_DESCRIPTOR_CLASS_NAME = ClassName .get ("org.springframework.core.convert" , "TypeDescriptor" );
34-
29+ private static final ClassName QUALIFIER_ANNOTATION_CLASS_NAME =
30+ ClassName .get ("org.springframework.beans.factory.annotation" , "Qualifier" );
31+ private static final ClassName LAZY_ANNOTATION_CLASS_NAME =
32+ ClassName .get ("org.springframework.context.annotation" , "Lazy" );
33+ private static final ClassName TYPE_DESCRIPTOR_CLASS_NAME =
34+ ClassName .get ("org.springframework.core.convert" , "TypeDescriptor" );
35+ private static final String GENERATED_ANNOTATION_CLASS_NAME_STRING = "Generated" ;
36+ private static final String PRE_JAVA_9_ANNOTATION_GENERATED_PACKAGE = "javax.annotation" ;
37+ private static final ClassName PRE_JAVA_9_ANNOTATION_GENERATED_CLASS_NAME =
38+ ClassName .get (
39+ PRE_JAVA_9_ANNOTATION_GENERATED_PACKAGE , GENERATED_ANNOTATION_CLASS_NAME_STRING );
40+ private static final String JAVA_9_PLUS_ANNOTATION_GENERATED_PACKAGE =
41+ "javax.annotation.processing" ;
42+ private static final ClassName JAVA_9_PLUS_ANNOTATION_GENERATED_CLASS_NAME =
43+ ClassName .get (
44+ JAVA_9_PLUS_ANNOTATION_GENERATED_PACKAGE , GENERATED_ANNOTATION_CLASS_NAME_STRING );
45+ private static final String PRE_JAVA_9_ANNOTATION_GENERATED =
46+ String .format (
47+ "%s.%s" , PRE_JAVA_9_ANNOTATION_GENERATED_PACKAGE , GENERATED_ANNOTATION_CLASS_NAME_STRING );
48+ private static final String JAVA_9_PLUS_ANNOTATION_GENERATED =
49+ String .format (
50+ "%s.%s" ,
51+ JAVA_9_PLUS_ANNOTATION_GENERATED_PACKAGE , GENERATED_ANNOTATION_CLASS_NAME_STRING );
52+ private static final ClassName COMPONENT_ANNOTATION_CLASS_NAME =
53+ ClassName .get ("org.springframework.stereotype" , "Component" );
3554 private final Clock clock ;
3655
3756 private final AtomicReference <ProcessingEnvironment > processingEnvironment ;
@@ -64,10 +83,10 @@ private TypeSpec createConversionServiceTypeSpec(
6483 final FieldSpec conversionServiceFieldSpec = buildConversionServiceFieldSpec ();
6584 final TypeSpec .Builder adapterClassTypeSpec =
6685 TypeSpec .classBuilder (descriptor .getAdapterClassName ()).addModifiers (PUBLIC );
67- Optional .ofNullable (buildGeneratedAnnotationSpec (descriptor ))
86+ Optional .ofNullable (buildGeneratedAnnotationSpec ())
6887 .ifPresent (adapterClassTypeSpec ::addAnnotation );
6988 return adapterClassTypeSpec
70- .addAnnotation (ClassName . get ( "org.springframework.stereotype" , "Component" ) )
89+ .addAnnotation (COMPONENT_ANNOTATION_CLASS_NAME )
7190 .addField (conversionServiceFieldSpec )
7291 .addMethod (buildConstructorSpec (descriptor , conversionServiceFieldSpec ))
7392 .addMethods (buildMappingMethods (descriptor , conversionServiceFieldSpec ))
@@ -92,27 +111,24 @@ private static ParameterSpec buildConstructorParameterSpec(
92111 final ParameterSpec .Builder parameterBuilder =
93112 ParameterSpec .builder (
94113 conversionServiceFieldSpec .type , conversionServiceFieldSpec .name , FINAL );
95- if (StringUtils . isNotEmpty (descriptor .getConversionServiceBeanName ())) {
114+ if (isNotEmpty (descriptor .getConversionServiceBeanName ())) {
96115 parameterBuilder .addAnnotation (buildQualifierAnnotation (descriptor ));
97116 }
98- if (Boolean . TRUE .equals (descriptor .isLazyAnnotatedConversionServiceBean ())) {
117+ if (TRUE .equals (descriptor .isLazyAnnotatedConversionServiceBean ())) {
99118 parameterBuilder .addAnnotation (buildLazyAnnotation ());
100119 }
101120 return parameterBuilder .build ();
102121 }
103122
104123 private static AnnotationSpec buildQualifierAnnotation (
105- ConversionServiceAdapterDescriptor descriptor ) {
106- return AnnotationSpec .builder (
107- ClassName .get (QUALIFIER_ANNOTATION_PACKAGE_NAME , QUALIFIER_ANNOTATION_CLASSS_NAME ))
124+ final ConversionServiceAdapterDescriptor descriptor ) {
125+ return AnnotationSpec .builder (QUALIFIER_ANNOTATION_CLASS_NAME )
108126 .addMember ("value" , "$S" , descriptor .getConversionServiceBeanName ())
109127 .build ();
110128 }
111129
112130 private static AnnotationSpec buildLazyAnnotation () {
113- return AnnotationSpec .builder (
114- ClassName .get (LAZY_ANNOTATION_PACKAGE_NAME , LAZY_ANNOTATION_CLASS_NAME ))
115- .build ();
131+ return AnnotationSpec .builder (LAZY_ANNOTATION_CLASS_NAME ).build ();
116132 }
117133
118134 private String collectionOfMethodName (final ParameterizedTypeName parameterizedTypeName ) {
@@ -163,7 +179,7 @@ private static String simpleName(final TypeName typeName) {
163179 } else return String .valueOf (typeName );
164180 }
165181
166- private static String arraySimpleName (ArrayTypeName arrayTypeName ) {
182+ private static String arraySimpleName (final ArrayTypeName arrayTypeName ) {
167183 return "ArrayOf"
168184 + (arrayTypeName .componentType instanceof ArrayTypeName
169185 ? arraySimpleName ((ArrayTypeName ) arrayTypeName .componentType )
@@ -212,13 +228,15 @@ private Object[] allTypeDescriptorArguments(
212228 final FieldSpec injectedConversionServiceFieldSpec ,
213229 final ParameterSpec sourceParameterSpec ,
214230 final Pair <TypeName , TypeName > sourceTargetPair ) {
215- final var arguments = new ArrayList <>();
216- arguments .add (sourceTargetPair .getRight ());
217- arguments .add (injectedConversionServiceFieldSpec );
218- arguments .add (sourceParameterSpec );
219- arguments .addAll (typeDescriptorArguments (sourceTargetPair .getLeft ()));
220- arguments .addAll (typeDescriptorArguments (sourceTargetPair .getRight ()));
221- return arguments .toArray ();
231+ return concat (
232+ concat (
233+ Stream .of (
234+ sourceTargetPair .getRight (),
235+ injectedConversionServiceFieldSpec ,
236+ sourceParameterSpec ),
237+ typeDescriptorArguments (sourceTargetPair .getLeft ())),
238+ typeDescriptorArguments (sourceTargetPair .getRight ()))
239+ .toArray ();
222240 }
223241
224242 private String typeDescriptorFormat (final TypeName typeName ) {
@@ -231,20 +249,14 @@ && isCollectionWithGenericParameter((ParameterizedTypeName) typeName)) {
231249 return "$T.valueOf($T.class)" ;
232250 }
233251
234- private List <Object > typeDescriptorArguments (final TypeName typeName ) {
235- final List <Object > allArguments ;
236- if (typeName instanceof ParameterizedTypeName
237- && isCollectionWithGenericParameter ((ParameterizedTypeName ) typeName )) {
238- allArguments = new ArrayList <>();
239- allArguments .add (TYPE_DESCRIPTOR_CLASS_NAME );
240- allArguments .add (((ParameterizedTypeName ) typeName ).rawType );
241- allArguments .addAll (
242- typeDescriptorArguments (
243- ((ParameterizedTypeName ) typeName ).typeArguments .iterator ().next ()));
244- } else {
245- allArguments = List .of (TYPE_DESCRIPTOR_CLASS_NAME , rawType (typeName ));
246- }
247- return allArguments ;
252+ private Stream <Object > typeDescriptorArguments (final TypeName typeName ) {
253+ return typeName instanceof ParameterizedTypeName
254+ && isCollectionWithGenericParameter ((ParameterizedTypeName ) typeName )
255+ ? concat (
256+ Stream .of (TYPE_DESCRIPTOR_CLASS_NAME , ((ParameterizedTypeName ) typeName ).rawType ),
257+ typeDescriptorArguments (
258+ ((ParameterizedTypeName ) typeName ).typeArguments .iterator ().next ()))
259+ : Stream .of (TYPE_DESCRIPTOR_CLASS_NAME , rawType (typeName ));
248260 }
249261
250262 private static ParameterSpec buildSourceParameterSpec (final TypeName sourceClassName ) {
@@ -253,25 +265,12 @@ private static ParameterSpec buildSourceParameterSpec(final TypeName sourceClass
253265
254266 private static FieldSpec buildConversionServiceFieldSpec () {
255267 return FieldSpec .builder (
256- ClassName .get (CONVERSION_SERVICE_PACKAGE_NAME , CONVERSION_SERVICE_CLASS_NAME ),
257- CONVERSION_SERVICE_FIELD_NAME ,
258- PRIVATE ,
259- FINAL )
268+ CONVERSION_SERVICE_CLASS_NAME , CONVERSION_SERVICE_FIELD_NAME , PRIVATE , FINAL )
260269 .build ();
261270 }
262271
263- private AnnotationSpec buildGeneratedAnnotationSpec (
264- final ConversionServiceAdapterDescriptor descriptor ) {
265- final AnnotationSpec .Builder builder ;
266- if (descriptor .isSourceVersionAtLeast9 ()
267- && isTypeAvailable (descriptor , "javax.annotation.processing.Generated" )) {
268- builder = AnnotationSpec .builder (ClassName .get ("javax.annotation.processing" , "Generated" ));
269- } else if (isTypeAvailable (descriptor , "javax.annotation.Generated" )) {
270- builder = AnnotationSpec .builder (ClassName .get ("javax.annotation" , "Generated" ));
271- } else {
272- builder = null ;
273- }
274- return Optional .ofNullable (builder )
272+ private AnnotationSpec buildGeneratedAnnotationSpec () {
273+ return Optional .ofNullable (baseAnnotationSpecBuilder ())
275274 .map (
276275 build ->
277276 build .addMember ("value" , "$S" , ConversionServiceAdapterGenerator .class .getName ()))
@@ -280,9 +279,33 @@ && isTypeAvailable(descriptor, "javax.annotation.processing.Generated")) {
280279 .orElse (null );
281280 }
282281
283- private static boolean isTypeAvailable (
284- final ConversionServiceAdapterDescriptor descriptor , final String name ) {
285- return descriptor .getElementUtils ().getTypeElement (name ) != null ;
282+ private AnnotationSpec .Builder baseAnnotationSpecBuilder () {
283+ final AnnotationSpec .Builder builder ;
284+ if (isJava9PlusGeneratedAvailable ()) {
285+ builder = AnnotationSpec .builder (JAVA_9_PLUS_ANNOTATION_GENERATED_CLASS_NAME );
286+ } else if (isPreJava9GeneratedAvailable ()) {
287+ builder = AnnotationSpec .builder (PRE_JAVA_9_ANNOTATION_GENERATED_CLASS_NAME );
288+ } else {
289+ builder = null ;
290+ }
291+ return builder ;
292+ }
293+
294+ private boolean isPreJava9GeneratedAvailable () {
295+ return isTypeAvailable (PRE_JAVA_9_ANNOTATION_GENERATED );
296+ }
297+
298+ private boolean isJava9PlusGeneratedAvailable () {
299+ return isSourceVersionAtLeast9 ()
300+ && isTypeAvailable (JAVA_9_PLUS_ANNOTATION_GENERATED );
301+ }
302+
303+ private boolean isSourceVersionAtLeast9 () {
304+ return processingEnvironment .get ().getSourceVersion ().compareTo (RELEASE_8 ) > 0 ;
305+ }
306+
307+ private boolean isTypeAvailable (final String name ) {
308+ return processingEnvironment .get ().getElementUtils ().getTypeElement (name ) != null ;
286309 }
287310
288311 public void init (final ProcessingEnvironment processingEnv ) {
0 commit comments