From efc62ec277b4c4e8519bec3d876db6056bbb1dbd Mon Sep 17 00:00:00 2001 From: Raimund Klein <770876+Chessray@users.noreply.github.com> Date: Thu, 9 Feb 2023 12:01:10 +0000 Subject: [PATCH 1/8] Next development version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5745964..8c68be8 100644 --- a/build.gradle +++ b/build.gradle @@ -55,7 +55,7 @@ subprojects { apply plugin: "jacoco" group = 'org.mapstruct.extensions.spring' - version = '1.0.0' + version = '1.0.1-SNAPSHOT' java { toolchain { From bdfb7c93fa38b46fbea0836764e4d7db23ae3082 Mon Sep 17 00:00:00 2001 From: Raimund Klein <770876+Chessray@users.noreply.github.com> Date: Sat, 18 Mar 2023 07:03:14 +0000 Subject: [PATCH 2/8] Katest Gradle + Dependencies (#68) --- gradle/libs.versions.toml | 6 +++--- gradle/wrapper/gradle-wrapper.jar | Bin 61574 -> 61608 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6dbcf73..9d79e9a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,17 +3,17 @@ asciidoctorPlugin = "3.3.2" assertj = "3.24.2" commons-io = "2.11.0" commons-lang3 = "3.12.0" -dependencyCheck = "8.0.2" +dependencyCheck = "8.1.2" guava = "31.1-jre" javapoet = "1.13.0" jsr250 = "1.0" jupiter = "5.9.2" mapstruct = "1.4.0.Final" -mockito = "5.1.1" +mockito = "5.2.0" spring = "5.0.0.RELEASE" springBoot = "2.7.7" springDependencyManagement = "1.1.0" -versionsPlugin = "0.45.0" +versionsPlugin = "0.46.0" [libraries] assertj = { group = "org.assertj", name = "assertj-core", version.ref = "assertj"} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 943f0cbfa754578e88a3dae77fce6e3dea56edbf..ccebba7710deaf9f98673a68957ea02138b60d0a 100644 GIT binary patch delta 5094 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 delta 5107 zcmY*d1zc0@|J{HQlai7V5+f#EN-H%&UP4MFm6QgFfuJK4DG4u#ARsbQL4i>MB1q|w zmWd#pqd~BR-yN@ieE-|$^W1aKIZtf&-p_fyw{(Uwc7_sWYDh^12cY!qXvcPQ!qF;q@b0nYU7 zP&ht}K7j%}P%%|ffm;4F0^i3P0R`a!2wm89L5P3Kfu;tTZJre<{N5}AzsH+E3DS`Q zJLIl`LRMf`JOTBLf(;IV(9(h{(}dXK!cPoSLm(o@fz8vRz}6fOw%3}3VYOsCczLF` za2RTsCWa2sS-uw(6|HLJg)Xf@S8#|+(Z5Y)ER+v+8;btfB3&9sWH6<=U}0)o-jIts zsi?Nko;No&JyZI%@1G&zsG5kKo^Zd7rk_9VIUao9;fC~nv(T0F&Af0&Rp`?x94EIS zUBPyBe5R5#okNiB1Xe--q4|hPyGzhJ?Lurt#Ci09BQ+}rlHpBhm;EmfLw{EbCz)sg zgseAE#f$met1jo;`Z6ihk?O1be3aa$IGV69{nzagziA!M*~E5lMc(Sp+NGm2IUjmn zql((DU9QP~Tn1pt6L`}|$Na-v(P+Zg&?6bAN@2u%KiB*Gmf}Z)R zMENRJgjKMqVbMpzPO{`!J~2Jyu7&xXnTDW?V?IJgy+-35q1)-J8T**?@_-2H`%X+6f5 zIRv`uLp&*?g7L~6+3O*saXT~gWsmhF*FNKw4X$29ePKi02G*)ysenhHv{u9-y?_do ztT(Cu04pk>51n}zu~=wgToY5Cx|MTlNw}GR>+`|6CAhQn=bh@S<7N)`w};;KTywDU z=QWO@RBj$WKOXSgCWg{BD`xl&DS!G}`Mm3$)=%3jzO_C+s+mfTFH5JL>}*(JKs@MqX|o2b#ZBX5P;p7;c)$F1y4HwvJ?KA938$rd)gn_U^CcUtmdaBW57 zlPph>Fz&L`cSScFjcj+7Jif3vxb20Ag~FPstm?9#OrD$e?Y~#1osDB0CFZ9Mu&%iE zSj~wZpFqu6!k%BT)}$F@Z%(d-Pqy07`N8ch2F7z^=S-!r-@j{#&{SM@a8O$P#SySx zZLD_z=I300OCA1YmKV0^lo@>^)THfZvW}s<$^w^#^Ce=kO5ymAnk>H7pK!+NJ-+F7 z1Bb6Y=r)0nZ+hRXUyD+BKAyecZxb+$JTHK5k(nWv*5%2a+u*GDt|rpReYQ}vft zXrIt#!kGO85o^~|9Oc-M5A!S@9Q)O$$&g8u>1=ew?T35h8B{-Z_S78oe=E(-YZhBPe@Y1sUt63A-Cdv>D1nIT~=Rub6$?8g>meFb7Ic@w^%@RN2z72oPZ#Ta%b(P1|&6I z61iO<8hT*)p19Bgd0JgXP{^c{P2~K@^DIXv=dF(u|DFfqD^dMIl8-x)xKIpJRZru@ zDxicyYJG}mh}=1Dfg%B$#H`CiAxPTj^;f4KRMZHUz-_x6)lEq!^mu%72*PI=t$6{Uql#dqm4 zClgaN63!&?v*enz4k1sbaM+yCqUf+i9rw$(YrY%ir1+%cWRB<;r}$8si!6QcNAk~J zk3?dejBaC`>=T<=y=>QVt*4kL>SwYwn$(4ES793qaH)>n(axyV3R5jdXDh#e-N0K- zuUgk|N^|3*D1!Wlz-!M*b}Zc5=;K6I+>1N$&Q%)&8LWUiTYi&aQIj(luA< zN5R<8Y8L#*i0xBio$jWcaiZ4S2w3#R@CGemesy~akKP)2GojQF6!$}!_RdUJPBevX zG#~uz%Yirb0@1wgQ;ayb=qD}6{=QXxjuZQ@@kxbN!QWhtEvuhS2yAZe8fZy6*4Inr zdSyR9Dec4HrE|I=z-U;IlH;_h#7e^Hq}gaJ<-z^}{*s!m^66wu2=(*EM0UaV*&u1q zJrq!K23TO8a(ecSQFdD$y+`xu)Xk36Z*;1i{hS=H2E<8<5yHuHG~22-S+Jq|3HMAw z%qBz3auT=M!=5F|Wqke|I^E8pmJ-}>_DwX5w%d3MSdC>xW%$ocm8w8HRdZ|^#cEt1 zM*I7S6sLQq;;Mecet(Q()+?s+&MeVLOvx}(MkvytkvLHl7h*N0AT1#AqC&(he(^%przH`KqA$z_dAvJJb409@F)fYwD$JW_{_Oie8!@VdJE zU>D$@B?LawAf5$;`AZ1E!krn=aAC%4+YQrzL!59yl1;|T2)u=RBYA8lk0Ek&gS!Rb zt0&hVuyhSa0}rpZGjTA>Gz}>Uv*4)F zf7S%D2nfA7x?gPEXZWk8DZimQs#xi0?So_k`2zb!UVQEAcbvjPLK9v>J~!awnxGpq zEh$EPOc4q&jywmglnC&D)1-P0DH!@)x;uJwMHdhPh>ZLWDw+p1pf52{X2dk{_|UOmakJa4MHu?CY`6Hhv!!d7=aNwiB5z zb*Wlq1zf^3iDlPf)b_SzI*{JCx2jN;*s~ra8NeB!PghqP!0po-ZL?0Jk;2~*~sCQ<%wU`mRImd)~!23RS?XJu|{u( ztFPy3*F=ZhJmBugTv48WX)4U*pNmm~4oD4}$*-92&<)n=R)5lT z-VpbEDk>(C1hoo#-H_u0`#%L6L$ zln(}h2*Cl(5(JtVM{YZ26@Fwmp;?Qt}9$_F%`?+-JHbC;bPZj8PLq9 zWo-KFw!i&r8WuA-!3F_m9!24Z(RhalAUR~_H#Ln=$%b5GY z)oB)zO%J5TY}&BXq^7#M>euVL%01Tzj4$6^ZOjT*7@zr~q@6GEjGi)nbwzSL`TiLN z{DVG~I$w@%^#tD{>1Ap@%=XogG_^Hvy_xiRn4yy?LKsC+ zU!S79X8orh&D%>1S`x2iyi&(iG&r#YT{}~iy(FIOo8?MZU#eo*c*(RjAGj@uDi zARJur)-*{n0PgW~&mFeg`MJ?(Kr;NUom)jh?ozZtyywN9bea6ikQlh}953Oul~N%4 z@Sx!@>?l1e7V*@HZMJx!gMo0TeXdU~#W6^n?YVQJ$)nuFRkvKbfwv_s*2g(!wPO|@ zvuXF=2MiPIX)A7x!|BthSa$GB%ECnuZe_Scx&AlnC z!~6C_SF24#@^VMIw)a-7{00}}Cr5NImPbW8OTIHoo6@NcxLVTna8<<;uy~YaaeMnd z;k_ynYc_8jQn9vW_W8QLkgaHtmwGC}wRcgZ^I^GPbz{lW)p#YYoinez1MjkY%6LBd z+Vr>j&^!?b-*Vk>8I!28o`r3w&^Lal8@=50zV4&9V9oXI{^r8;JmVeos&wf?O!;_o zk))^k*1fvYw9?WrS!sG2TcX`hH@Y3mF&@{i05;_AV{>Umi8{uZP_0W5_1V2yHU<)E z+qviK*7SJtnL;76{WK!?Pv$-!w$08<%8Qy|sB|P%GiV1<+dHw*sj!C~SjsB6+1L@so+Q~n# z+Uc5+Uz+mGmkR@>H7D*c?mm8WQz;3VOpktU_DeBi>3#@z zmLe;3gP<7KPy>~k47nEeT?G?7e2g6316Xdb_y+ja5C9Ayg6QTNr~&Kbs(1>7zp|f@le;9B z1e(+Ga%jPWR7oc}=XcB4$z?YD)l;%#U;}~gZzGViI=fwu9OAPCCK!0w>Ay^#$b49k zT&|M?JaIyRT<;@*t_jp1ifWPvL;{maf6o0T#X!#9YX;0Q;LTQ0}0tg^_Ru4pkSr4#P zmnW|D0`A#Ie6pEfBDv39=jN2;kiUoT6I&kChsbI!jMuY6zuZql5!&i%5!c zjsHlXtjT;NV?jAb`%vy)JOK_j1rponLqc>(2qgYlLPEs>|0QV<=Pw~C`fLFKJJitt zyC6003{rxCsmtGKjhB%W2W~*%vKH8l$pZoOFT*K@uL9%CD^3rh=ZtuTU1 zJpf4|%n^yjh#dKSSCJI8;YU*CD!8Wv20*e5`-fya^75@ADLU^RdHDg3Bk3k6)dGi7 z!!z;|O1h$8q!vO*w6 I6Xdi10eY*&F8}}l diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f398c33..bdc9a83 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 65dcd68..79a61d4 100755 --- a/gradlew +++ b/gradlew @@ -144,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac From e14522e1242377980334820e75da0c96edc75f52 Mon Sep 17 00:00:00 2001 From: Raimund Klein <770876+Chessray@users.noreply.github.com> Date: Fri, 14 Apr 2023 08:07:06 +0100 Subject: [PATCH 3/8] Fixes 70 (#72) --- docs/src/docs/asciidoc/chapter-2-set-up.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/docs/asciidoc/chapter-2-set-up.asciidoc b/docs/src/docs/asciidoc/chapter-2-set-up.asciidoc index e719cdf..f8b062a 100644 --- a/docs/src/docs/asciidoc/chapter-2-set-up.asciidoc +++ b/docs/src/docs/asciidoc/chapter-2-set-up.asciidoc @@ -1,7 +1,7 @@ [[setup]] == Set up -MapStruct Spring Extensions is a Java annotation processor based on http://www.jcp.org/en/jsr/detail?id=269[JSR 269] and as such can be used within command line builds (javac, Ant, Maven etc.) as well as from within your IDE. +MapStruct Spring Extensions is a Java annotation processor based on http://www.jcp.org/en/jsr/detail?id=269[JSR 269] and as such can be used within command line builds (javac, Ant, Maven etc.) as well as from within your IDE. The minimum JDK version is 11. IMPORTANT: Also, you will need MapStruct itself (at least version `1.4.0.Final`) in your project. From 02a33e2527f6069d87aba759b22f04adc45894f4 Mon Sep 17 00:00:00 2001 From: Raimund Klein <770876+Chessray@users.noreply.github.com> Date: Fri, 21 Apr 2023 23:03:53 +0100 Subject: [PATCH 4/8] 65 map lists (#73) * Fixes 65 --- .../chapter-3-mapper-as-converter.asciidoc | 8 +- .../ConversionServiceAdapterTest.java | 12 +- ...nversionServiceAdapterIntegrationTest.java | 5 + ...nversionServiceAdapterIntegrationTest.java | 5 + ...nversionServiceAdapterIntegrationTest.java | 5 + ...nversionServiceAdapterIntegrationTest.java | 5 + ...nversionServiceAdapterIntegrationTest.java | 8 +- .../ConversionServiceAdapterGenerator.java | 138 +++++++++++-- .../converter/ConverterMapperProcessor.java | 7 + ...ConversionServiceAdapterGeneratorTest.java | 194 ++++++++++-------- ...erviceAdapterCustomBeanJava8Generated.java | 8 +- ...ceAdapterCustomBeanJava9PlusGenerated.java | 8 +- ...onServiceAdapterCustomBeanNoGenerated.java | 8 +- ...onversionServiceAdapterJava8Generated.java | 8 +- ...rsionServiceAdapterJava9PlusGenerated.java | 8 +- .../ConversionServiceAdapterNoGenerated.java | 8 +- 16 files changed, 318 insertions(+), 117 deletions(-) diff --git a/docs/src/docs/asciidoc/chapter-3-mapper-as-converter.asciidoc b/docs/src/docs/asciidoc/chapter-3-mapper-as-converter.asciidoc index 7d6fb1c..5c0365e 100644 --- a/docs/src/docs/asciidoc/chapter-3-mapper-as-converter.asciidoc +++ b/docs/src/docs/asciidoc/chapter-3-mapper-as-converter.asciidoc @@ -29,7 +29,7 @@ This allows using the Mapper indirectly via the `ConversionService`: ---- ==== -All this can be achieved already with MapStruct's core functionality. However, when a Mapper wants to https://mapstruct.org/documentation/stable/reference/html/#invoking-other-mappers[invoke] another one, it can't take the route via the `ConversionService`, because the latter's `convert` method does not match the signature that MapStruct expects for a mapping method. Thus, the developer still has to add every invoked Mapper to the invoking Mapper's `uses` element. This creates (aside from a potentially long list) a tight coupling between Mappers that the `ConversionService` wants to avoid. +All this can be achieved already with MapStruct's core functionality. However, when a Mapper wants to https://mapstruct.org/documentation/stable/reference/html/#invoking-other-mappers[invoke] another one, it can't take the route via the `ConversionService`, because the latter's `convert` method does not match the signature that MapStruct expects for a mapping method. Thus, the developer still has to add every invoked Mapper to the invoking Mapper's `uses` element. This creates (aside from a potentially long list) a tight coupling between Mappers that the `ConversionService` is designed to avoid. This is where MapStruct Spring Extensions can help. Including the two artifacts in your build will generate an Adapter class that _can_ be used by an invoking Mapper. Let's say that the above CarMapper is accompanied by a SeatConfigurationMapper: @@ -61,12 +61,12 @@ public class ConversionServiceAdapter { } public CarDto mapCarToCarDto(final Car source) { - return conversionService.convert(source, CarDto.class); + return (CarDto) conversionService.convert(source, TypeDescriptor.valueOf(Car.class), TypeDescriptor.valueOf(CarDto.class)); } public SeatConfigurationDto mapSeatConfigurationToSeatConfigurationDto( final SeatConfiguration source) { - return conversionService.convert(source, SeatConfigurationDto.class); + return (SeatConfigurationDto) conversionService.convert(source, TypeDescriptor.valueOf(SeatConfiguration.class), TypeDescriptor.valueOf(SeatConfigurationDto.class)); } } ---- @@ -165,7 +165,7 @@ public class ConversionServiceAdapter { } public Locale mapStringToLocale(final String source) { - return conversionService.convert(source, Locale.class); + return (Locale) conversionService.convert(source, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Locale.class)); } } ---- diff --git a/examples/arrays/src/test/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterTest.java b/examples/arrays/src/test/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterTest.java index c02bb20..7530f7d 100644 --- a/examples/arrays/src/test/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterTest.java +++ b/examples/arrays/src/test/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterTest.java @@ -1,16 +1,16 @@ package org.mapstruct.extensions.spring.converter; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.mock; + +import java.sql.Blob; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.core.convert.ConversionService; - -import java.sql.Blob; - -import static org.mockito.BDDMockito.then; -import static org.mockito.Mockito.mock; +import org.springframework.core.convert.TypeDescriptor; @ExtendWith(MockitoExtension.class) class ConversionServiceAdapterTest { @@ -29,6 +29,6 @@ void shouldMapViaConversionServiceInGeneratedMethod() { conversionServiceAdapter.mapBlobToArrayOfbyte(blob); // Then - then(conversionService).should().convert(blob, byte[].class); + then(conversionService).should().convert(blob, TypeDescriptor.valueOf(Blob.class), TypeDescriptor.valueOf(byte[].class)); } } diff --git a/examples/classname/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java b/examples/classname/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java index f4732dd..817d852 100644 --- a/examples/classname/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java +++ b/examples/classname/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java @@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.stereotype.Component; @@ -64,6 +65,10 @@ void shouldKnowAllMappers() { then(conversionService.canConvert(Wheel.class, WheelDto.class)).isTrue(); then(conversionService.canConvert(Wheels.class, List.class)).isTrue(); then(conversionService.canConvert(List.class, Wheels.class)).isTrue(); + then(conversionService.canConvert( + TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(WheelDto.class)), + TypeDescriptor.valueOf((Wheels.class)))) + .isTrue(); } @Test diff --git a/examples/custom-conversion-service-bean/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java b/examples/custom-conversion-service-bean/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java index d79348d..c4a47cd 100644 --- a/examples/custom-conversion-service-bean/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java +++ b/examples/custom-conversion-service-bean/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java @@ -8,6 +8,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.stereotype.Component; @@ -73,6 +74,10 @@ void shouldKnowAllMappers() { then(conversionService.canConvert(Wheel.class, WheelDto.class)).isTrue(); then(conversionService.canConvert(Wheels.class, List.class)).isTrue(); then(conversionService.canConvert(List.class, Wheels.class)).isTrue(); + then(conversionService.canConvert( + TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(WheelDto.class)), + TypeDescriptor.valueOf((Wheels.class)))) + .isTrue(); } @Test diff --git a/examples/noconfig/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java b/examples/noconfig/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java index e434363..23bb0ea 100644 --- a/examples/noconfig/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java +++ b/examples/noconfig/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java @@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.stereotype.Component; @@ -64,6 +65,10 @@ void shouldKnowAllMappers() { then(conversionService.canConvert(Wheel.class, WheelDto.class)).isTrue(); then(conversionService.canConvert(Wheels.class, List.class)).isTrue(); then(conversionService.canConvert(List.class, Wheels.class)).isTrue(); + then(conversionService.canConvert( + TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(WheelDto.class)), + TypeDescriptor.valueOf((Wheels.class)))) + .isTrue(); } @Test diff --git a/examples/packagename-and-classname/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java b/examples/packagename-and-classname/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java index 58b554a..a02718a 100644 --- a/examples/packagename-and-classname/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java +++ b/examples/packagename-and-classname/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java @@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.stereotype.Component; @@ -64,6 +65,10 @@ void shouldKnowAllMappers() { then(conversionService.canConvert(Wheel.class, WheelDto.class)).isTrue(); then(conversionService.canConvert(Wheels.class, List.class)).isTrue(); then(conversionService.canConvert(List.class, Wheels.class)).isTrue(); + then(conversionService.canConvert( + TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(WheelDto.class)), + TypeDescriptor.valueOf((Wheels.class)))) + .isTrue(); } @Test diff --git a/examples/packagename/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java b/examples/packagename/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java index 43a226b..05a18ed 100644 --- a/examples/packagename/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java +++ b/examples/packagename/src/test/java/org/mapstruct/extensions/spring/example/ConversionServiceAdapterIntegrationTest.java @@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.stereotype.Component; @@ -60,10 +61,15 @@ void addMappersToConversionService() { @Test void shouldKnowAllMappers() { then(conversionService.canConvert(Car.class, CarDto.class)).isTrue(); - then(conversionService.canConvert(SeatConfiguration.class, SeatConfigurationDto.class)).isTrue(); + then(conversionService.canConvert(SeatConfiguration.class, SeatConfigurationDto.class)) + .isTrue(); then(conversionService.canConvert(Wheel.class, WheelDto.class)).isTrue(); then(conversionService.canConvert(Wheels.class, List.class)).isTrue(); then(conversionService.canConvert(List.class, Wheels.class)).isTrue(); + then(conversionService.canConvert( + TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(WheelDto.class)), + TypeDescriptor.valueOf((Wheels.class)))) + .isTrue(); } @Test diff --git a/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGenerator.java b/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGenerator.java index 7237417..a2fe0d1 100644 --- a/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGenerator.java +++ b/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGenerator.java @@ -1,19 +1,24 @@ package org.mapstruct.extensions.spring.converter; -import com.squareup.javapoet.*; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.Pair; +import static java.time.format.DateTimeFormatter.ISO_INSTANT; +import static java.util.stream.Collectors.toList; +import static javax.lang.model.element.Modifier.*; +import static javax.tools.Diagnostic.Kind.WARNING; +import com.squareup.javapoet.*; import java.io.IOException; import java.io.UncheckedIOException; import java.io.Writer; import java.time.Clock; import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.util.Optional; - -import static java.time.format.DateTimeFormatter.ISO_INSTANT; -import static java.util.stream.Collectors.toList; -import static javax.lang.model.element.Modifier.*; +import java.util.concurrent.atomic.AtomicReference; +import javax.annotation.processing.ProcessingEnvironment; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; public class ConversionServiceAdapterGenerator { private static final String CONVERSION_SERVICE_PACKAGE_NAME = "org.springframework.core.convert"; @@ -25,13 +30,22 @@ public class ConversionServiceAdapterGenerator { private static final String LAZY_ANNOTATION_PACKAGE_NAME = "org.springframework.context.annotation"; private static final String LAZY_ANNOTATION_CLASS_NAME = "Lazy"; + private static final ClassName TYPE_DESCRIPTOR_CLASS_NAME = ClassName.get("org.springframework.core.convert", "TypeDescriptor"); private final Clock clock; + private final AtomicReference processingEnvironment; + public ConversionServiceAdapterGenerator(final Clock clock) { this.clock = clock; + processingEnvironment = new AtomicReference<>(); } + + ProcessingEnvironment getProcessingEnvironment() { + return processingEnvironment.get(); + } + public void writeConversionServiceAdapter( final ConversionServiceAdapterDescriptor descriptor, final Writer out) { try { @@ -101,6 +115,45 @@ private static AnnotationSpec buildLazyAnnotation() { .build(); } + private String collectionOfMethodName(final ParameterizedTypeName parameterizedTypeName) { + if (isCollectionWithGenericParameter(parameterizedTypeName)) { + return simpleName(parameterizedTypeName) + + "Of" + + collectionOfNameIfApplicable(parameterizedTypeName.typeArguments.iterator().next()); + } + + return simpleName(parameterizedTypeName); + } + + private boolean isCollectionWithGenericParameter(final ParameterizedTypeName parameterizedTypeName) { + return parameterizedTypeName.typeArguments != null + && parameterizedTypeName.typeArguments.size() > 0 + && isCollection(parameterizedTypeName); + } + + private boolean isCollection(final ParameterizedTypeName parameterizedTypeName) { + try { + return Collection.class.isAssignableFrom( + Class.forName(parameterizedTypeName.rawType.canonicalName())); + } catch (ClassNotFoundException e) { + processingEnvironment + .get() + .getMessager() + .printMessage( + WARNING, + "Caught ClassNotFoundException when trying to resolve parameterized type: " + + e.getMessage()); + return false; + } + } + + private String collectionOfNameIfApplicable(final TypeName typeName) { + if (typeName instanceof ParameterizedTypeName) { + return collectionOfMethodName((ParameterizedTypeName) typeName); + } + return simpleName(typeName); + } + private static String simpleName(final TypeName typeName) { final TypeName rawType = rawType(typeName); if (rawType instanceof ArrayTypeName) { @@ -124,9 +177,9 @@ private static TypeName rawType(final TypeName typeName) { return typeName; } - private static Iterable buildMappingMethods( - final ConversionServiceAdapterDescriptor descriptor, - final FieldSpec injectedConversionServiceFieldSpec) { + private Iterable buildMappingMethods( + final ConversionServiceAdapterDescriptor descriptor, + final FieldSpec injectedConversionServiceFieldSpec) { return descriptor.getFromToMappings().stream() .map( sourceTargetPair -> @@ -134,25 +187,66 @@ private static Iterable buildMappingMethods( .collect(toList()); } - private static MethodSpec toMappingMethodSpec( - final FieldSpec injectedConversionServiceFieldSpec, - final Pair sourceTargetPair) { + private MethodSpec toMappingMethodSpec( + final FieldSpec injectedConversionServiceFieldSpec, + final Pair sourceTargetPair) { final ParameterSpec sourceParameterSpec = buildSourceParameterSpec(sourceTargetPair.getLeft()); return MethodSpec.methodBuilder( String.format( "map%sTo%s", - simpleName(sourceTargetPair.getLeft()), simpleName(sourceTargetPair.getRight()))) + collectionOfNameIfApplicable(sourceTargetPair.getLeft()), + collectionOfNameIfApplicable(sourceTargetPair.getRight()))) .addParameter(sourceParameterSpec) .addModifiers(PUBLIC) .returns(sourceTargetPair.getRight()) .addStatement( - "return $N.convert($N, $T.class)", - injectedConversionServiceFieldSpec, - sourceParameterSpec, - rawType(sourceTargetPair.getRight())) + String.format( + "return ($T) $N.convert($N, %s, %s)", + typeDescriptorFormat(sourceTargetPair.getLeft()), + typeDescriptorFormat(sourceTargetPair.getRight())), + allTypeDescriptorArguments(injectedConversionServiceFieldSpec, sourceParameterSpec, sourceTargetPair)) .build(); } + private Object[] allTypeDescriptorArguments( + final FieldSpec injectedConversionServiceFieldSpec, + final ParameterSpec sourceParameterSpec, + final Pair sourceTargetPair) { + final var arguments = new ArrayList<>(); + arguments.add(sourceTargetPair.getRight()); + arguments.add(injectedConversionServiceFieldSpec); + arguments.add(sourceParameterSpec); + arguments.addAll(typeDescriptorArguments(sourceTargetPair.getLeft())); + arguments.addAll(typeDescriptorArguments(sourceTargetPair.getRight())); + return arguments.toArray(); + } + + private String typeDescriptorFormat(final TypeName typeName) { + if (typeName instanceof ParameterizedTypeName + && isCollectionWithGenericParameter((ParameterizedTypeName) typeName)) { + return String.format( + "$T.collection($T.class, %s)", + typeDescriptorFormat(((ParameterizedTypeName) typeName).typeArguments.iterator().next())); + } + return "$T.valueOf($T.class)"; + } + + private List typeDescriptorArguments(final TypeName typeName) { + final List allArguments; + if (typeName instanceof ParameterizedTypeName + && isCollectionWithGenericParameter((ParameterizedTypeName) typeName)) { + allArguments = new ArrayList<>(); + allArguments.add(TYPE_DESCRIPTOR_CLASS_NAME); + allArguments.add(((ParameterizedTypeName) typeName).rawType); + allArguments.addAll( + typeDescriptorArguments( + ((ParameterizedTypeName) typeName).typeArguments.iterator().next())); + } else { + allArguments = List.of(TYPE_DESCRIPTOR_CLASS_NAME, rawType(typeName)); + } + return allArguments; + } + private static ParameterSpec buildSourceParameterSpec(final TypeName sourceClassName) { return ParameterSpec.builder(sourceClassName, "source", FINAL).build(); } @@ -167,7 +261,7 @@ private static FieldSpec buildConversionServiceFieldSpec() { } private AnnotationSpec buildGeneratedAnnotationSpec( - ConversionServiceAdapterDescriptor descriptor) { + final ConversionServiceAdapterDescriptor descriptor) { final AnnotationSpec.Builder builder; if (descriptor.isSourceVersionAtLeast9() && isTypeAvailable(descriptor, "javax.annotation.processing.Generated")) { @@ -190,4 +284,10 @@ private static boolean isTypeAvailable( final ConversionServiceAdapterDescriptor descriptor, final String name) { return descriptor.getElementUtils().getTypeElement(name) != null; } + + public void init(final ProcessingEnvironment processingEnv) { + if (!this.processingEnvironment.compareAndSet(null, processingEnv)) { + throw new IllegalStateException("ProcessingEnvironment already set."); + } + } } diff --git a/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConverterMapperProcessor.java b/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConverterMapperProcessor.java index a8f3968..b0c12a4 100644 --- a/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConverterMapperProcessor.java +++ b/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConverterMapperProcessor.java @@ -8,6 +8,7 @@ import org.mapstruct.extensions.spring.SpringMapperConfig; import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.lang.model.SourceVersion; @@ -50,6 +51,12 @@ public ConverterMapperProcessor() { this.adapterGenerator = adapterGenerator; } + @Override + public synchronized void init(final ProcessingEnvironment processingEnv) { + super.init(processingEnv); + adapterGenerator.init(processingEnv); + } + @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); diff --git a/extensions/src/test/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGeneratorTest.java b/extensions/src/test/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGeneratorTest.java index 8d9b195..c432e09 100644 --- a/extensions/src/test/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGeneratorTest.java +++ b/extensions/src/test/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGeneratorTest.java @@ -1,6 +1,23 @@ package org.mapstruct.extensions.spring.converter; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.commons.io.IOUtils.resourceToString; +import static org.assertj.core.api.BDDAssertions.then; +import static org.assertj.core.api.BDDAssertions.thenIllegalStateException; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.ParameterizedTypeName; +import java.io.IOException; +import java.io.StringWriter; +import java.time.Clock; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.List; +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; @@ -9,21 +26,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; -import java.io.IOException; -import java.io.StringWriter; -import java.time.Clock; -import java.time.ZoneId; -import java.time.ZonedDateTime; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static java.util.Collections.singletonList; -import static org.apache.commons.io.IOUtils.resourceToString; -import static org.assertj.core.api.BDDAssertions.then; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - @ExtendWith(MockitoExtension.class) class ConversionServiceAdapterGeneratorTest { @Mock private Elements elements; @@ -35,73 +37,76 @@ class ConversionServiceAdapterGeneratorTest { ZonedDateTime.of(2020, 3, 29, 15, 21, 34, (int) (236 * Math.pow(10, 6)), ZoneId.of("Z")) .toInstant(), ZoneId.of("Z")); - private final ConversionServiceAdapterGenerator generator = + private final ConversionServiceAdapterGenerator underTest = new ConversionServiceAdapterGenerator(FIXED_CLOCK); @Nested - class Java8Generated { - @BeforeEach - void initElements() { - isAtLeastJava9 = false; - given(elements.getTypeElement("javax.annotation.Generated")) - .willReturn(mock(TypeElement.class)); + class DefaultProcessingEnvironment { + @Nested + class Java8Generated { + @BeforeEach + void initElements() { + isAtLeastJava9 = false; + given(elements.getTypeElement("javax.annotation.Generated")) + .willReturn(mock(TypeElement.class)); + } + + @Test + void shouldGenerateMatchingOutput() throws IOException { + ConversionServiceAdapterGeneratorTest.this.shouldGenerateMatchingOutput( + "ConversionServiceAdapterJava8Generated.java"); + } + + @Test + void shouldGenerateMatchingOutputWhenUsingCustomConversionService() throws IOException { + ConversionServiceAdapterGeneratorTest.this + .shouldGenerateMatchingOutputWhenUsingCustomConversionService( + "ConversionServiceAdapterCustomBeanJava8Generated.java"); + } } - @Test - void shouldGenerateMatchingOutput() throws IOException { - ConversionServiceAdapterGeneratorTest.this.shouldGenerateMatchingOutput( - "ConversionServiceAdapterJava8Generated.java"); + @Nested + class Java9PlusGenerated { + @BeforeEach + void initElements() { + isAtLeastJava9 = true; + given(elements.getTypeElement("javax.annotation.processing.Generated")) + .willReturn(mock(TypeElement.class)); + } + + @Test + void shouldGenerateMatchingOutput() throws IOException { + ConversionServiceAdapterGeneratorTest.this.shouldGenerateMatchingOutput( + "ConversionServiceAdapterJava9PlusGenerated.java"); + } + + @Test + void shouldGenerateMatchingOutputWhenUsingCustomConversionService() throws IOException { + ConversionServiceAdapterGeneratorTest.this + .shouldGenerateMatchingOutputWhenUsingCustomConversionService( + "ConversionServiceAdapterCustomBeanJava9PlusGenerated.java"); + } } - @Test - void shouldGenerateMatchingOutputWhenUsingCustomConversionService() throws IOException { - ConversionServiceAdapterGeneratorTest.this - .shouldGenerateMatchingOutputWhenUsingCustomConversionService( - "ConversionServiceAdapterCustomBeanJava8Generated.java"); - } - } - - @Nested - class Java9PlusGenerated { - @BeforeEach - void initElements() { - isAtLeastJava9 = true; - given(elements.getTypeElement("javax.annotation.processing.Generated")) - .willReturn(mock(TypeElement.class)); - } - - @Test - void shouldGenerateMatchingOutput() throws IOException { - ConversionServiceAdapterGeneratorTest.this.shouldGenerateMatchingOutput( - "ConversionServiceAdapterJava9PlusGenerated.java"); - } - - @Test - void shouldGenerateMatchingOutputWhenUsingCustomConversionService() throws IOException { - ConversionServiceAdapterGeneratorTest.this - .shouldGenerateMatchingOutputWhenUsingCustomConversionService( - "ConversionServiceAdapterCustomBeanJava9PlusGenerated.java"); - } - } - - @Nested - class NoGenerated { - @BeforeEach - void initElements() { - isAtLeastJava9 = false; - } - - @Test - void shouldGenerateMatchingOutput() throws IOException { - ConversionServiceAdapterGeneratorTest.this.shouldGenerateMatchingOutput( - "ConversionServiceAdapterNoGenerated.java"); - } - - @Test - void shouldGenerateMatchingOutputWhenUsingCustomConversionService() throws IOException { - ConversionServiceAdapterGeneratorTest.this - .shouldGenerateMatchingOutputWhenUsingCustomConversionService( - "ConversionServiceAdapterCustomBeanNoGenerated.java"); + @Nested + class NoGenerated { + @BeforeEach + void initElements() { + isAtLeastJava9 = false; + } + + @Test + void shouldGenerateMatchingOutput() throws IOException { + ConversionServiceAdapterGeneratorTest.this.shouldGenerateMatchingOutput( + "ConversionServiceAdapterNoGenerated.java"); + } + + @Test + void shouldGenerateMatchingOutputWhenUsingCustomConversionService() throws IOException { + ConversionServiceAdapterGeneratorTest.this + .shouldGenerateMatchingOutputWhenUsingCustomConversionService( + "ConversionServiceAdapterCustomBeanNoGenerated.java"); + } } } @@ -114,15 +119,20 @@ void shouldGenerateMatchingOutput(final String expectedContentFileName) throws I ConversionServiceAdapterGeneratorTest.class.getPackage().getName(), "ConversionServiceAdapter")) .fromToMappings( - singletonList( - Pair.of(ClassName.get("test", "Car"), ClassName.get("test", "CarDto")))) + List.of( + Pair.of(ClassName.get("test", "Car"), ClassName.get("test", "CarDto")), + Pair.of( + ParameterizedTypeName.get( + ClassName.get(List.class), ClassName.get("test", "Car")), + ParameterizedTypeName.get( + ClassName.get(List.class), ClassName.get("test", "CarDto"))))) .lazyAnnotatedConversionServiceBean(true) .elementUtils(elements) .sourceVersionAtLeast9(isAtLeastJava9); final StringWriter outputWriter = new StringWriter(); // When - generator.writeConversionServiceAdapter(descriptor, outputWriter); + underTest.writeConversionServiceAdapter(descriptor, outputWriter); // Then then(outputWriter.toString()) @@ -140,18 +150,40 @@ void shouldGenerateMatchingOutputWhenUsingCustomConversionService( "ConversionServiceAdapter")) .conversionServiceBeanName("myConversionService") .fromToMappings( - singletonList( - Pair.of(ClassName.get("test", "Car"), ClassName.get("test", "CarDto")))) + List.of( + Pair.of(ClassName.get("test", "Car"), ClassName.get("test", "CarDto")), + Pair.of( + ParameterizedTypeName.get( + ClassName.get(List.class), ClassName.get("test", "Car")), + ParameterizedTypeName.get( + ClassName.get(List.class), ClassName.get("test", "CarDto"))))) .lazyAnnotatedConversionServiceBean(true) .elementUtils(elements) .sourceVersionAtLeast9(isAtLeastJava9); final StringWriter outputWriter = new StringWriter(); // When - generator.writeConversionServiceAdapter(descriptor, outputWriter); + underTest.writeConversionServiceAdapter(descriptor, outputWriter); // Then then(outputWriter.toString()) .isEqualToIgnoringWhitespace(resourceToString('/' + expectedContentFileName, UTF_8)); } + + @Nested + class Init { + @Test + void shouldInitWithProcessingEnvironment() { + final var processingEnv = mock(ProcessingEnvironment.class); + underTest.init(processingEnv); + then(underTest.getProcessingEnvironment()).isEqualTo(processingEnv); + } + + @Test + void shouldThrowIllegalStateExceptionWhenCalledRepeatedly() { + final var processingEnv = mock(ProcessingEnvironment.class); + underTest.init(processingEnv); + thenIllegalStateException().isThrownBy(() -> underTest.init(processingEnv)); + } + } } diff --git a/extensions/src/test/resources/ConversionServiceAdapterCustomBeanJava8Generated.java b/extensions/src/test/resources/ConversionServiceAdapterCustomBeanJava8Generated.java index a0168fc..07eed4e 100644 --- a/extensions/src/test/resources/ConversionServiceAdapterCustomBeanJava8Generated.java +++ b/extensions/src/test/resources/ConversionServiceAdapterCustomBeanJava8Generated.java @@ -1,9 +1,11 @@ package org.mapstruct.extensions.spring.converter; +import java.util.List; import javax.annotation.Generated; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Lazy; import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.stereotype.Component; import test.Car; import test.CarDto; @@ -21,6 +23,10 @@ public ConversionServiceAdapter( } public CarDto mapCarToCarDto(final Car source) { - return conversionService.convert(source, CarDto.class); + return (CarDto) conversionService.convert(source, TypeDescriptor.valueOf(Car.class), TypeDescriptor.valueOf(CarDto.class)); + } + + public List mapListOfCarToListOfCarDto(final List source) { + return (List) conversionService.convert(source, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Car.class)), TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(CarDto.class))); } } diff --git a/extensions/src/test/resources/ConversionServiceAdapterCustomBeanJava9PlusGenerated.java b/extensions/src/test/resources/ConversionServiceAdapterCustomBeanJava9PlusGenerated.java index 54a9eea..f57685b 100644 --- a/extensions/src/test/resources/ConversionServiceAdapterCustomBeanJava9PlusGenerated.java +++ b/extensions/src/test/resources/ConversionServiceAdapterCustomBeanJava9PlusGenerated.java @@ -1,9 +1,11 @@ package org.mapstruct.extensions.spring.converter; +import java.util.List; import javax.annotation.processing.Generated; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Lazy; import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.stereotype.Component; import test.Car; import test.CarDto; @@ -21,6 +23,10 @@ public ConversionServiceAdapter( } public CarDto mapCarToCarDto(final Car source) { - return conversionService.convert(source, CarDto.class); + return (CarDto) conversionService.convert(source, TypeDescriptor.valueOf(Car.class), TypeDescriptor.valueOf(CarDto.class)); + } + + public List mapListOfCarToListOfCarDto(final List source) { + return (List) conversionService.convert(source, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Car.class)), TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(CarDto.class))); } } diff --git a/extensions/src/test/resources/ConversionServiceAdapterCustomBeanNoGenerated.java b/extensions/src/test/resources/ConversionServiceAdapterCustomBeanNoGenerated.java index 452ffee..4dbdc84 100644 --- a/extensions/src/test/resources/ConversionServiceAdapterCustomBeanNoGenerated.java +++ b/extensions/src/test/resources/ConversionServiceAdapterCustomBeanNoGenerated.java @@ -1,8 +1,10 @@ package org.mapstruct.extensions.spring.converter; +import java.util.List; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Lazy; import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.stereotype.Component; import test.Car; import test.CarDto; @@ -17,6 +19,10 @@ public ConversionServiceAdapter( } public CarDto mapCarToCarDto(final Car source) { - return conversionService.convert(source, CarDto.class); + return (CarDto) conversionService.convert(source, TypeDescriptor.valueOf(Car.class), TypeDescriptor.valueOf(CarDto.class)); + } + + public List mapListOfCarToListOfCarDto(final List source) { + return (List) conversionService.convert(source, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Car.class)), TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(CarDto.class))); } } diff --git a/extensions/src/test/resources/ConversionServiceAdapterJava8Generated.java b/extensions/src/test/resources/ConversionServiceAdapterJava8Generated.java index d2c027a..664a3b6 100644 --- a/extensions/src/test/resources/ConversionServiceAdapterJava8Generated.java +++ b/extensions/src/test/resources/ConversionServiceAdapterJava8Generated.java @@ -1,8 +1,10 @@ package org.mapstruct.extensions.spring.converter; +import java.util.List; import javax.annotation.Generated; import org.springframework.context.annotation.Lazy; import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.stereotype.Component; import test.Car; import test.CarDto; @@ -19,6 +21,10 @@ public ConversionServiceAdapter(@Lazy final ConversionService conversionService) } public CarDto mapCarToCarDto(final Car source) { - return conversionService.convert(source, CarDto.class); + return (CarDto) conversionService.convert(source, TypeDescriptor.valueOf(Car.class), TypeDescriptor.valueOf(CarDto.class)); + } + + public List mapListOfCarToListOfCarDto(final List source) { + return (List) conversionService.convert(source, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Car.class)), TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(CarDto.class))); } } diff --git a/extensions/src/test/resources/ConversionServiceAdapterJava9PlusGenerated.java b/extensions/src/test/resources/ConversionServiceAdapterJava9PlusGenerated.java index 6972a38..eec5416 100644 --- a/extensions/src/test/resources/ConversionServiceAdapterJava9PlusGenerated.java +++ b/extensions/src/test/resources/ConversionServiceAdapterJava9PlusGenerated.java @@ -1,8 +1,10 @@ package org.mapstruct.extensions.spring.converter; +import java.util.List; import javax.annotation.processing.Generated; import org.springframework.context.annotation.Lazy; import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.stereotype.Component; import test.Car; import test.CarDto; @@ -19,6 +21,10 @@ public ConversionServiceAdapter(@Lazy final ConversionService conversionService) } public CarDto mapCarToCarDto(final Car source) { - return conversionService.convert(source, CarDto.class); + return (CarDto) conversionService.convert(source, TypeDescriptor.valueOf(Car.class), TypeDescriptor.valueOf(CarDto.class)); + } + + public List mapListOfCarToListOfCarDto(final List source) { + return (List) conversionService.convert(source, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Car.class)), TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(CarDto.class))); } } diff --git a/extensions/src/test/resources/ConversionServiceAdapterNoGenerated.java b/extensions/src/test/resources/ConversionServiceAdapterNoGenerated.java index 8f99a9f..526eb92 100644 --- a/extensions/src/test/resources/ConversionServiceAdapterNoGenerated.java +++ b/extensions/src/test/resources/ConversionServiceAdapterNoGenerated.java @@ -1,7 +1,9 @@ package org.mapstruct.extensions.spring.converter; +import java.util.List; import org.springframework.context.annotation.Lazy; import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.stereotype.Component; import test.Car; import test.CarDto; @@ -15,6 +17,10 @@ public ConversionServiceAdapter(@Lazy final ConversionService conversionService) } public CarDto mapCarToCarDto(final Car source) { - return conversionService.convert(source, CarDto.class); + return (CarDto) conversionService.convert(source, TypeDescriptor.valueOf(Car.class), TypeDescriptor.valueOf(CarDto.class)); + } + + public List mapListOfCarToListOfCarDto(final List source) { + return (List) conversionService.convert(source, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Car.class)), TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(CarDto.class))); } } From 862da1cd52b659a3a097ff2f07777e888c0fc3a3 Mon Sep 17 00:00:00 2001 From: Raimund Klein <770876+Chessray@users.noreply.github.com> Date: Sun, 23 Apr 2023 09:36:22 +0100 Subject: [PATCH 5/8] Latest Gradle + Dependencies --- gradle/libs.versions.toml | 4 ++-- gradle/wrapper/gradle-wrapper.jar | Bin 61608 -> 62076 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 7 ++++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9d79e9a..08ba3e2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,13 +3,13 @@ asciidoctorPlugin = "3.3.2" assertj = "3.24.2" commons-io = "2.11.0" commons-lang3 = "3.12.0" -dependencyCheck = "8.1.2" +dependencyCheck = "8.2.1" guava = "31.1-jre" javapoet = "1.13.0" jsr250 = "1.0" jupiter = "5.9.2" mapstruct = "1.4.0.Final" -mockito = "5.2.0" +mockito = "5.3.1" spring = "5.0.0.RELEASE" springBoot = "2.7.7" springDependencyManagement = "1.1.0" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index ccebba7710deaf9f98673a68957ea02138b60d0a..c1962a79e29d3e0ab67b14947c167a862655af9b 100644 GIT binary patch delta 8979 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 F{TFmrHLU;u delta 8469 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 Date: Sun, 23 Apr 2023 10:27:48 +0100 Subject: [PATCH 6/8] Latest JaCoCo --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8c68be8..0b37051 100644 --- a/build.gradle +++ b/build.gradle @@ -69,7 +69,7 @@ subprojects { } jacoco { - toolVersion = "0.8.8" + toolVersion = "0.8.9" } jacocoTestReport { From 3635699dd3a343fc04b168105c35e61acadd0cc7 Mon Sep 17 00:00:00 2001 From: Raimund Klein <770876+Chessray@users.noreply.github.com> Date: Sun, 23 Apr 2023 16:17:54 +0100 Subject: [PATCH 7/8] Some housekeeping refactorings before next release (#74) --- .../ConversionServiceAdapterDescriptor.java | 25 +-- .../ConversionServiceAdapterGenerator.java | 151 ++++++++++-------- .../converter/ConverterMapperProcessor.java | 75 ++++----- ...ConversionServiceAdapterGeneratorTest.java | 28 +++- 4 files changed, 145 insertions(+), 134 deletions(-) diff --git a/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterDescriptor.java b/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterDescriptor.java index ed0c816..180275d 100644 --- a/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterDescriptor.java +++ b/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterDescriptor.java @@ -2,10 +2,8 @@ import com.squareup.javapoet.ClassName; import com.squareup.javapoet.TypeName; -import org.apache.commons.lang3.tuple.Pair; - -import javax.lang.model.util.Elements; import java.util.List; +import org.apache.commons.lang3.tuple.Pair; public class ConversionServiceAdapterDescriptor { private ClassName adapterClassName; @@ -13,27 +11,6 @@ public class ConversionServiceAdapterDescriptor { private List> fromToMappings; private boolean lazyAnnotatedConversionServiceBean; - public Elements getElementUtils() { - return elementUtils; - } - - public ConversionServiceAdapterDescriptor elementUtils(Elements elementUtils) { - this.elementUtils = elementUtils; - return this; - } - - private Elements elementUtils; - public boolean isSourceVersionAtLeast9() { - return sourceVersionAtLeast9; - } - - public ConversionServiceAdapterDescriptor sourceVersionAtLeast9(boolean sourceVersionAtLeast9) { - this.sourceVersionAtLeast9 = sourceVersionAtLeast9; - return this; - } - - private boolean sourceVersionAtLeast9; - public ClassName getAdapterClassName() { return adapterClassName; } diff --git a/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGenerator.java b/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGenerator.java index a2fe0d1..ee8b666 100644 --- a/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGenerator.java +++ b/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGenerator.java @@ -1,9 +1,13 @@ package org.mapstruct.extensions.spring.converter; +import static java.lang.Boolean.TRUE; import static java.time.format.DateTimeFormatter.ISO_INSTANT; import static java.util.stream.Collectors.toList; +import static java.util.stream.Stream.concat; +import static javax.lang.model.SourceVersion.RELEASE_8; import static javax.lang.model.element.Modifier.*; import static javax.tools.Diagnostic.Kind.WARNING; +import static org.apache.commons.lang3.StringUtils.isNotEmpty; import com.squareup.javapoet.*; import java.io.IOException; @@ -11,27 +15,42 @@ import java.io.Writer; import java.time.Clock; import java.time.ZonedDateTime; -import java.util.ArrayList; import java.util.Collection; -import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; import javax.annotation.processing.ProcessingEnvironment; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; public class ConversionServiceAdapterGenerator { - private static final String CONVERSION_SERVICE_PACKAGE_NAME = "org.springframework.core.convert"; - private static final String CONVERSION_SERVICE_CLASS_NAME = "ConversionService"; + private static final ClassName CONVERSION_SERVICE_CLASS_NAME = + ClassName.get("org.springframework.core.convert", "ConversionService"); private static final String CONVERSION_SERVICE_FIELD_NAME = "conversionService"; - private static final String QUALIFIER_ANNOTATION_PACKAGE_NAME = - "org.springframework.beans.factory.annotation"; - private static final String QUALIFIER_ANNOTATION_CLASSS_NAME = "Qualifier"; - private static final String LAZY_ANNOTATION_PACKAGE_NAME = - "org.springframework.context.annotation"; - private static final String LAZY_ANNOTATION_CLASS_NAME = "Lazy"; - private static final ClassName TYPE_DESCRIPTOR_CLASS_NAME = ClassName.get("org.springframework.core.convert", "TypeDescriptor"); - + private static final ClassName QUALIFIER_ANNOTATION_CLASS_NAME = + ClassName.get("org.springframework.beans.factory.annotation", "Qualifier"); + private static final ClassName LAZY_ANNOTATION_CLASS_NAME = + ClassName.get("org.springframework.context.annotation", "Lazy"); + private static final ClassName TYPE_DESCRIPTOR_CLASS_NAME = + ClassName.get("org.springframework.core.convert", "TypeDescriptor"); + private static final String GENERATED_ANNOTATION_CLASS_NAME_STRING = "Generated"; + private static final String PRE_JAVA_9_ANNOTATION_GENERATED_PACKAGE = "javax.annotation"; + private static final ClassName PRE_JAVA_9_ANNOTATION_GENERATED_CLASS_NAME = + ClassName.get( + PRE_JAVA_9_ANNOTATION_GENERATED_PACKAGE, GENERATED_ANNOTATION_CLASS_NAME_STRING); + private static final String JAVA_9_PLUS_ANNOTATION_GENERATED_PACKAGE = + "javax.annotation.processing"; + private static final ClassName JAVA_9_PLUS_ANNOTATION_GENERATED_CLASS_NAME = + ClassName.get( + JAVA_9_PLUS_ANNOTATION_GENERATED_PACKAGE, GENERATED_ANNOTATION_CLASS_NAME_STRING); + private static final String PRE_JAVA_9_ANNOTATION_GENERATED = + String.format( + "%s.%s", PRE_JAVA_9_ANNOTATION_GENERATED_PACKAGE, GENERATED_ANNOTATION_CLASS_NAME_STRING); + private static final String JAVA_9_PLUS_ANNOTATION_GENERATED = + String.format( + "%s.%s", + JAVA_9_PLUS_ANNOTATION_GENERATED_PACKAGE, GENERATED_ANNOTATION_CLASS_NAME_STRING); + private static final ClassName COMPONENT_ANNOTATION_CLASS_NAME = + ClassName.get("org.springframework.stereotype", "Component"); private final Clock clock; private final AtomicReference processingEnvironment; @@ -64,10 +83,10 @@ private TypeSpec createConversionServiceTypeSpec( final FieldSpec conversionServiceFieldSpec = buildConversionServiceFieldSpec(); final TypeSpec.Builder adapterClassTypeSpec = TypeSpec.classBuilder(descriptor.getAdapterClassName()).addModifiers(PUBLIC); - Optional.ofNullable(buildGeneratedAnnotationSpec(descriptor)) + Optional.ofNullable(buildGeneratedAnnotationSpec()) .ifPresent(adapterClassTypeSpec::addAnnotation); return adapterClassTypeSpec - .addAnnotation(ClassName.get("org.springframework.stereotype", "Component")) + .addAnnotation(COMPONENT_ANNOTATION_CLASS_NAME) .addField(conversionServiceFieldSpec) .addMethod(buildConstructorSpec(descriptor, conversionServiceFieldSpec)) .addMethods(buildMappingMethods(descriptor, conversionServiceFieldSpec)) @@ -92,27 +111,24 @@ private static ParameterSpec buildConstructorParameterSpec( final ParameterSpec.Builder parameterBuilder = ParameterSpec.builder( conversionServiceFieldSpec.type, conversionServiceFieldSpec.name, FINAL); - if (StringUtils.isNotEmpty(descriptor.getConversionServiceBeanName())) { + if (isNotEmpty(descriptor.getConversionServiceBeanName())) { parameterBuilder.addAnnotation(buildQualifierAnnotation(descriptor)); } - if (Boolean.TRUE.equals(descriptor.isLazyAnnotatedConversionServiceBean())) { + if (TRUE.equals(descriptor.isLazyAnnotatedConversionServiceBean())) { parameterBuilder.addAnnotation(buildLazyAnnotation()); } return parameterBuilder.build(); } private static AnnotationSpec buildQualifierAnnotation( - ConversionServiceAdapterDescriptor descriptor) { - return AnnotationSpec.builder( - ClassName.get(QUALIFIER_ANNOTATION_PACKAGE_NAME, QUALIFIER_ANNOTATION_CLASSS_NAME)) + final ConversionServiceAdapterDescriptor descriptor) { + return AnnotationSpec.builder(QUALIFIER_ANNOTATION_CLASS_NAME) .addMember("value", "$S", descriptor.getConversionServiceBeanName()) .build(); } private static AnnotationSpec buildLazyAnnotation() { - return AnnotationSpec.builder( - ClassName.get(LAZY_ANNOTATION_PACKAGE_NAME, LAZY_ANNOTATION_CLASS_NAME)) - .build(); + return AnnotationSpec.builder(LAZY_ANNOTATION_CLASS_NAME).build(); } private String collectionOfMethodName(final ParameterizedTypeName parameterizedTypeName) { @@ -163,7 +179,7 @@ private static String simpleName(final TypeName typeName) { } else return String.valueOf(typeName); } - private static String arraySimpleName(ArrayTypeName arrayTypeName) { + private static String arraySimpleName(final ArrayTypeName arrayTypeName) { return "ArrayOf" + (arrayTypeName.componentType instanceof ArrayTypeName ? arraySimpleName((ArrayTypeName) arrayTypeName.componentType) @@ -212,13 +228,15 @@ private Object[] allTypeDescriptorArguments( final FieldSpec injectedConversionServiceFieldSpec, final ParameterSpec sourceParameterSpec, final Pair sourceTargetPair) { - final var arguments = new ArrayList<>(); - arguments.add(sourceTargetPair.getRight()); - arguments.add(injectedConversionServiceFieldSpec); - arguments.add(sourceParameterSpec); - arguments.addAll(typeDescriptorArguments(sourceTargetPair.getLeft())); - arguments.addAll(typeDescriptorArguments(sourceTargetPair.getRight())); - return arguments.toArray(); + return concat( + concat( + Stream.of( + sourceTargetPair.getRight(), + injectedConversionServiceFieldSpec, + sourceParameterSpec), + typeDescriptorArguments(sourceTargetPair.getLeft())), + typeDescriptorArguments(sourceTargetPair.getRight())) + .toArray(); } private String typeDescriptorFormat(final TypeName typeName) { @@ -231,20 +249,14 @@ && isCollectionWithGenericParameter((ParameterizedTypeName) typeName)) { return "$T.valueOf($T.class)"; } - private List typeDescriptorArguments(final TypeName typeName) { - final List allArguments; - if (typeName instanceof ParameterizedTypeName - && isCollectionWithGenericParameter((ParameterizedTypeName) typeName)) { - allArguments = new ArrayList<>(); - allArguments.add(TYPE_DESCRIPTOR_CLASS_NAME); - allArguments.add(((ParameterizedTypeName) typeName).rawType); - allArguments.addAll( - typeDescriptorArguments( - ((ParameterizedTypeName) typeName).typeArguments.iterator().next())); - } else { - allArguments = List.of(TYPE_DESCRIPTOR_CLASS_NAME, rawType(typeName)); - } - return allArguments; + private Stream typeDescriptorArguments(final TypeName typeName) { + return typeName instanceof ParameterizedTypeName + && isCollectionWithGenericParameter((ParameterizedTypeName) typeName) + ? concat( + Stream.of(TYPE_DESCRIPTOR_CLASS_NAME, ((ParameterizedTypeName) typeName).rawType), + typeDescriptorArguments( + ((ParameterizedTypeName) typeName).typeArguments.iterator().next())) + : Stream.of(TYPE_DESCRIPTOR_CLASS_NAME, rawType(typeName)); } private static ParameterSpec buildSourceParameterSpec(final TypeName sourceClassName) { @@ -253,25 +265,12 @@ private static ParameterSpec buildSourceParameterSpec(final TypeName sourceClass private static FieldSpec buildConversionServiceFieldSpec() { return FieldSpec.builder( - ClassName.get(CONVERSION_SERVICE_PACKAGE_NAME, CONVERSION_SERVICE_CLASS_NAME), - CONVERSION_SERVICE_FIELD_NAME, - PRIVATE, - FINAL) + CONVERSION_SERVICE_CLASS_NAME, CONVERSION_SERVICE_FIELD_NAME, PRIVATE, FINAL) .build(); } - private AnnotationSpec buildGeneratedAnnotationSpec( - final ConversionServiceAdapterDescriptor descriptor) { - final AnnotationSpec.Builder builder; - if (descriptor.isSourceVersionAtLeast9() - && isTypeAvailable(descriptor, "javax.annotation.processing.Generated")) { - builder = AnnotationSpec.builder(ClassName.get("javax.annotation.processing", "Generated")); - } else if (isTypeAvailable(descriptor, "javax.annotation.Generated")) { - builder = AnnotationSpec.builder(ClassName.get("javax.annotation", "Generated")); - } else { - builder = null; - } - return Optional.ofNullable(builder) + private AnnotationSpec buildGeneratedAnnotationSpec() { + return Optional.ofNullable(baseAnnotationSpecBuilder()) .map( build -> build.addMember("value", "$S", ConversionServiceAdapterGenerator.class.getName())) @@ -280,9 +279,33 @@ && isTypeAvailable(descriptor, "javax.annotation.processing.Generated")) { .orElse(null); } - private static boolean isTypeAvailable( - final ConversionServiceAdapterDescriptor descriptor, final String name) { - return descriptor.getElementUtils().getTypeElement(name) != null; + private AnnotationSpec.Builder baseAnnotationSpecBuilder() { + final AnnotationSpec.Builder builder; + if (isJava9PlusGeneratedAvailable()) { + builder = AnnotationSpec.builder(JAVA_9_PLUS_ANNOTATION_GENERATED_CLASS_NAME); + } else if (isPreJava9GeneratedAvailable()) { + builder = AnnotationSpec.builder(PRE_JAVA_9_ANNOTATION_GENERATED_CLASS_NAME); + } else { + builder = null; + } + return builder; + } + + private boolean isPreJava9GeneratedAvailable() { + return isTypeAvailable(PRE_JAVA_9_ANNOTATION_GENERATED); + } + + private boolean isJava9PlusGeneratedAvailable() { + return isSourceVersionAtLeast9() + && isTypeAvailable(JAVA_9_PLUS_ANNOTATION_GENERATED); + } + + private boolean isSourceVersionAtLeast9() { + return processingEnvironment.get().getSourceVersion().compareTo(RELEASE_8) > 0; + } + + private boolean isTypeAvailable(final String name) { + return processingEnvironment.get().getElementUtils().getTypeElement(name) != null; } public void init(final ProcessingEnvironment processingEnv) { diff --git a/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConverterMapperProcessor.java b/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConverterMapperProcessor.java index b0c12a4..cd5b44a 100644 --- a/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConverterMapperProcessor.java +++ b/extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConverterMapperProcessor.java @@ -1,12 +1,19 @@ package org.mapstruct.extensions.spring.converter; +import static java.lang.Boolean.TRUE; +import static java.util.Collections.emptyList; +import static java.util.stream.Collectors.toCollection; +import static java.util.stream.Collectors.toList; +import static javax.lang.model.type.TypeKind.DECLARED; +import static javax.tools.Diagnostic.Kind.ERROR; + import com.squareup.javapoet.ClassName; import com.squareup.javapoet.TypeName; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.MutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.mapstruct.extensions.spring.SpringMapperConfig; - +import java.io.IOException; +import java.io.Writer; +import java.time.Clock; +import java.util.*; +import java.util.Map.Entry; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; @@ -15,19 +22,10 @@ import javax.lang.model.element.*; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; -import java.io.IOException; -import java.io.Writer; -import java.time.Clock; -import java.util.*; -import java.util.Map.Entry; - -import static java.lang.Boolean.TRUE; -import static java.util.Collections.emptyList; -import static java.util.stream.Collectors.toCollection; -import static java.util.stream.Collectors.toList; -import static javax.lang.model.SourceVersion.RELEASE_8; -import static javax.lang.model.type.TypeKind.DECLARED; -import static javax.tools.Diagnostic.Kind.ERROR; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.mapstruct.extensions.spring.SpringMapperConfig; @SupportedAnnotationTypes({ ConverterMapperProcessor.MAPPER, @@ -76,29 +74,26 @@ private ConversionServiceAdapterDescriptor buildDescriptor( final Set annotations, final RoundEnvironment roundEnv) { return new ConversionServiceAdapterDescriptor() .adapterClassName(getAdapterClassName(annotations, roundEnv)) - .conversionServiceBeanName(getConversionServiceName(annotations, roundEnv)) + .conversionServiceBeanName(getConversionServiceBeanName(annotations, roundEnv)) .lazyAnnotatedConversionServiceBean( getLazyAnnotatedConversionServiceBean(annotations, roundEnv)) - .fromToMappings(getExternalConversionMappings(annotations, roundEnv)) - .elementUtils(processingEnv.getElementUtils()) - .sourceVersionAtLeast9(processingEnv.getSourceVersion().compareTo(RELEASE_8) > 0); + .fromToMappings(getExternalConversionMappings(annotations, roundEnv)); } private List> getExternalConversionMappings( final Set annotations, final RoundEnvironment roundEnv) { - final Optional>> pairs = - annotations.stream() - .filter(ConverterMapperProcessor::isSpringMapperConfigAnnotation) - .findFirst() - .flatMap(annotation -> findFirstElementAnnotatedWith(roundEnv, annotation)) - .flatMap(this::toSpringMapperConfigMirror) - .map(AnnotationMirror::getElementValues) - .flatMap(this::extractExternalConversions) - .map(Entry::getValue) - .map(AnnotationValue::getValue) - .map(List.class::cast) - .map(this::toSourceTargetTypeNamePairs); - return pairs.orElse(emptyList()); + return annotations.stream() + .filter(ConverterMapperProcessor::isSpringMapperConfigAnnotation) + .findFirst() + .flatMap(annotation -> findFirstElementAnnotatedWith(roundEnv, annotation)) + .flatMap(this::toSpringMapperConfigMirror) + .map(AnnotationMirror::getElementValues) + .flatMap(this::extractExternalConversions) + .map(Entry::getValue) + .map(AnnotationValue::getValue) + .map(List.class::cast) + .map(this::toSourceTargetTypeNamePairs) + .orElse(emptyList()); } private List> toSourceTargetTypeNamePairs( @@ -262,13 +257,13 @@ private String getPackageName(Element element) { return String.valueOf(processingEnv.getElementUtils().getPackageOf(element).getQualifiedName()); } - private String getConversionServiceName( + private static String getConversionServiceBeanName( final Set annotations, final RoundEnvironment roundEnv) { return annotations.stream() .filter(ConverterMapperProcessor::isSpringMapperConfigAnnotation) .findFirst() .flatMap(annotation -> findFirstElementAnnotatedWith(roundEnv, annotation)) - .map(this::toSpringMapperConfig) + .map(ConverterMapperProcessor::toSpringMapperConfig) .map(SpringMapperConfig::conversionServiceBeanName) .orElse(null); } @@ -278,7 +273,7 @@ private static Optional findFirstElementAnnotatedWith( return roundEnv.getElementsAnnotatedWith(annotation).stream().findFirst(); } - private SpringMapperConfig toSpringMapperConfig(final Element element) { + private static SpringMapperConfig toSpringMapperConfig(final Element element) { return element.getAnnotation(SpringMapperConfig.class); } @@ -296,13 +291,13 @@ private boolean isSpringMapperConfigMirror(final AnnotationMirror annotationMirr .equals(annotationMirror.getAnnotationType().asElement().asType()); } - private boolean getLazyAnnotatedConversionServiceBean( + private static boolean getLazyAnnotatedConversionServiceBean( final Set annotations, final RoundEnvironment roundEnv) { return annotations.stream() .filter(ConverterMapperProcessor::isSpringMapperConfigAnnotation) .findFirst() .flatMap(annotation -> findFirstElementAnnotatedWith(roundEnv, annotation)) - .map(this::toSpringMapperConfig) + .map(ConverterMapperProcessor::toSpringMapperConfig) .map(SpringMapperConfig::lazyAnnotatedConversionServiceBean) .orElse(TRUE); } diff --git a/extensions/src/test/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGeneratorTest.java b/extensions/src/test/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGeneratorTest.java index c432e09..2b56c4f 100644 --- a/extensions/src/test/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGeneratorTest.java +++ b/extensions/src/test/java/org/mapstruct/extensions/spring/converter/ConversionServiceAdapterGeneratorTest.java @@ -1,6 +1,8 @@ package org.mapstruct.extensions.spring.converter; import static java.nio.charset.StandardCharsets.UTF_8; +import static javax.lang.model.SourceVersion.RELEASE_8; +import static javax.lang.model.SourceVersion.RELEASE_9; import static org.apache.commons.io.IOUtils.resourceToString; import static org.assertj.core.api.BDDAssertions.then; import static org.assertj.core.api.BDDAssertions.thenIllegalStateException; @@ -16,6 +18,7 @@ import java.time.ZonedDateTime; import java.util.List; import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.SourceVersion; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; import org.apache.commons.lang3.tuple.Pair; @@ -25,6 +28,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.stubbing.Answer; @ExtendWith(MockitoExtension.class) class ConversionServiceAdapterGeneratorTest { @@ -42,6 +46,22 @@ class ConversionServiceAdapterGeneratorTest { @Nested class DefaultProcessingEnvironment { + @BeforeEach + void initWithProcessingEnvironment() { + final var processingEnvironment = mock(ProcessingEnvironment.class); + given(processingEnvironment.getElementUtils()).willReturn(elements); + given(processingEnvironment.getSourceVersion()) + .will((Answer) + (invocation) -> { + if (isAtLeastJava9) { + return RELEASE_9; + } else { + return RELEASE_8; + } + }); + underTest.init(processingEnvironment); + } + @Nested class Java8Generated { @BeforeEach @@ -126,9 +146,7 @@ void shouldGenerateMatchingOutput(final String expectedContentFileName) throws I ClassName.get(List.class), ClassName.get("test", "Car")), ParameterizedTypeName.get( ClassName.get(List.class), ClassName.get("test", "CarDto"))))) - .lazyAnnotatedConversionServiceBean(true) - .elementUtils(elements) - .sourceVersionAtLeast9(isAtLeastJava9); + .lazyAnnotatedConversionServiceBean(true); final StringWriter outputWriter = new StringWriter(); // When @@ -157,9 +175,7 @@ void shouldGenerateMatchingOutputWhenUsingCustomConversionService( ClassName.get(List.class), ClassName.get("test", "Car")), ParameterizedTypeName.get( ClassName.get(List.class), ClassName.get("test", "CarDto"))))) - .lazyAnnotatedConversionServiceBean(true) - .elementUtils(elements) - .sourceVersionAtLeast9(isAtLeastJava9); + .lazyAnnotatedConversionServiceBean(true); final StringWriter outputWriter = new StringWriter(); // When From e052290953b3d7ec0087f803c28002d2fbedceea Mon Sep 17 00:00:00 2001 From: Raimund Klein <770876+Chessray@users.noreply.github.com> Date: Sun, 23 Apr 2023 16:30:39 +0100 Subject: [PATCH 8/8] Release 1.0.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0b37051..8803ce3 100644 --- a/build.gradle +++ b/build.gradle @@ -55,7 +55,7 @@ subprojects { apply plugin: "jacoco" group = 'org.mapstruct.extensions.spring' - version = '1.0.1-SNAPSHOT' + version = '1.0.1' java { toolchain {