Skip to content

Commit 9f6f0b8

Browse files
committed
#211 Remove methods should not be considered fluent setters.
1 parent 10966f3 commit 9f6f0b8

File tree

5 files changed

+87
-7
lines changed

5 files changed

+87
-7
lines changed

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ dependencies {
111111
testFramework( TestFrameworkType.Platform.INSTANCE )
112112
testFramework( TestFrameworkType.Bundled.INSTANCE )
113113
}
114-
implementation('org.mapstruct:mapstruct:1.5.3.Final')
114+
implementation('org.mapstruct:mapstruct:1.7.0-SNAPSHOT')
115115
testImplementation(platform('org.junit:junit-bom:5.11.0'))
116116
testImplementation('org.junit.platform:junit-platform-launcher')
117117
testImplementation('org.junit.jupiter:junit-jupiter-api')
@@ -130,7 +130,7 @@ tasks.register('libs', Sync) {
130130
include('mapstruct-intellij-*.jar')
131131
include('MapStruct-Intellij-*.jar')
132132
}
133-
rename('mapstruct-1.5.3.Final.jar', 'mapstruct.jar')
133+
rename('mapstruct-1.7.0-SNAPSHOT.jar', 'mapstruct.jar')
134134
}
135135

136136
tasks.register('testLibs', Sync) {

src/main/java/org/mapstruct/intellij/util/MapStructVersion.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,19 @@
1010
*/
1111
public enum MapStructVersion {
1212

13-
V1_2_O( false, false ),
14-
V1_3_O( true, false ),
15-
V1_4_O( true, true );
13+
V1_2_O( false, false, false ),
14+
V1_3_O( true, false, false ),
15+
V1_4_O( true, true, false ),
16+
V1_7_O( true, true, true ),;
1617

1718
private final boolean builderSupported;
1819
private final boolean constructorSupported;
20+
private final boolean ignoringRemovers;
1921

20-
MapStructVersion(boolean builderSupported, boolean constructorSupported) {
22+
MapStructVersion(boolean builderSupported, boolean constructorSupported, boolean ignoringRemovers) {
2123
this.builderSupported = builderSupported;
2224
this.constructorSupported = constructorSupported;
25+
this.ignoringRemovers = ignoringRemovers;
2326
}
2427

2528
public boolean isBuilderSupported() {
@@ -29,4 +32,8 @@ public boolean isBuilderSupported() {
2932
public boolean isConstructorSupported() {
3033
return constructorSupported;
3134
}
35+
36+
public boolean isIgnoringRemovers() {
37+
return ignoringRemovers;
38+
}
3239
}

src/main/java/org/mapstruct/intellij/util/MapstructUtil.java

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@
66
package org.mapstruct.intellij.util;
77

88
import java.beans.Introspector;
9+
import java.io.IOException;
10+
import java.io.InputStream;
911
import java.util.Collections;
1012
import java.util.HashMap;
1113
import java.util.List;
1214
import java.util.Map;
15+
import java.util.Optional;
1316
import java.util.function.Function;
17+
import java.util.jar.Manifest;
1418
import java.util.stream.Stream;
1519
import javax.swing.Icon;
1620

@@ -21,6 +25,8 @@
2125
import com.intellij.openapi.module.ModuleUtilCore;
2226
import com.intellij.openapi.roots.ProjectRootManager;
2327
import com.intellij.openapi.util.Pair;
28+
import com.intellij.openapi.util.Version;
29+
import com.intellij.openapi.vfs.JarFileSystem;
2430
import com.intellij.openapi.vfs.VirtualFile;
2531
import com.intellij.psi.CommonClassNames;
2632
import com.intellij.psi.EmptySubstitutor;
@@ -61,6 +67,7 @@
6167
import org.mapstruct.MappingTarget;
6268
import org.mapstruct.Mappings;
6369
import org.mapstruct.Named;
70+
//import org.mapstruct.PrimaryMappingSource;
6471
import org.mapstruct.ValueMapping;
6572
import org.mapstruct.ValueMappings;
6673
import org.mapstruct.factory.Mappers;
@@ -229,9 +236,15 @@ public boolean isFluentSetter(@NotNull PsiMethod method, PsiType psiType, @NotNu
229236
return !psiType.getCanonicalText().startsWith( "java.lang" ) &&
230237
method.getReturnType() != null &&
231238
!isAdderWithUpperCase4thCharacter( method ) &&
239+
!isIgnoredRemover( method ) &&
232240
isAssignableFromReturnTypeOrSuperTypes( psiType, substitutor.substitute( method.getReturnType() ) );
233241
}
234242

243+
private static boolean isIgnoredRemover(@NotNull PsiMethod method) {
244+
return isRemoverWithUpperCase7thCharacter( method )
245+
&& resolveMapStructProjectVersion( method.getContainingFile() ).isIgnoringRemovers();
246+
}
247+
235248
private static boolean isAssignableFromReturnTypeOrSuperTypes(PsiType psiType, @NotNull PsiType returnType) {
236249

237250
if ( isAssignableFrom( psiType, returnType ) ) {
@@ -260,6 +273,13 @@ private static boolean isAdderWithUpperCase4thCharacter(@NotNull PsiMethod metho
260273
Character.isUpperCase( methodName.charAt( 3 ) );
261274
}
262275

276+
private static boolean isRemoverWithUpperCase7thCharacter(@NotNull PsiMethod method) {
277+
String methodName = method.getName();
278+
return methodName.startsWith( "remove" ) &&
279+
methodName.length() > 6 &&
280+
Character.isUpperCase( methodName.charAt( 6 ) );
281+
}
282+
263283
/**
264284
* Checks if the {@code method} is a possible builder creation method.
265285
* <p>
@@ -567,7 +587,12 @@ public static MapStructVersion resolveMapStructProjectVersion(@NotNull PsiFile p
567587
}
568588
return CachedValuesManager.getManager( module.getProject() ).getCachedValue( module, () -> {
569589
MapStructVersion mapStructVersion;
570-
if ( JavaPsiFacade.getInstance( module.getProject() )
590+
591+
Version version = resolveImplementationVersion( module );
592+
if ( version != null && version.isOrGreaterThan( 1, 7 ) ) {
593+
mapStructVersion = MapStructVersion.V1_7_O;
594+
}
595+
else if ( JavaPsiFacade.getInstance( module.getProject() )
571596
.findClass( ENUM_MAPPING_ANNOTATION_FQN, module.getModuleRuntimeScope( false ) ) != null ) {
572597
mapStructVersion = MapStructVersion.V1_4_O;
573598
}
@@ -659,4 +684,39 @@ public static boolean isInheritInverseConfiguration(PsiMethod method) {
659684
return isAnnotated( method, INHERIT_INVERSE_CONFIGURATION_FQN, AnnotationUtil.CHECK_TYPE );
660685
}
661686

687+
@Nullable
688+
private static Version resolveImplementationVersion(Module module) {
689+
JarFileSystem jarFileSystem = JarFileSystem.getInstance();
690+
return Optional.ofNullable( JavaPsiFacade
691+
.getInstance( module.getProject() )
692+
.findClass( MAPPER_ANNOTATION_FQN, module.getModuleRuntimeScope( false ) ) )
693+
.map( PsiClass::getContainingFile )
694+
.map( PsiFile::getVirtualFile )
695+
.map( jarFileSystem::getVirtualFileForJar )
696+
.map( jarFileSystem::getJarRootForLocalFile )
697+
.map( jarRoot -> jarRoot.findFileByRelativePath( "META-INF/MANIFEST.MF" ) )
698+
.map( MapstructUtil::resolveManifest )
699+
.map( MapstructUtil::resolveVersionString )
700+
.map( Version::parseVersion )
701+
.orElse( null );
702+
}
703+
704+
private static @Nullable Manifest resolveManifest(VirtualFile manifestFile) {
705+
try ( InputStream is = manifestFile.getInputStream() ) {
706+
return new Manifest(is);
707+
}
708+
catch ( IOException e ) {
709+
return null;
710+
}
711+
}
712+
713+
private static @Nullable String resolveVersionString(Manifest manifest) {
714+
if ( manifest.getMainAttributes().containsKey( "Implementation-Version" ) ) {
715+
return manifest.getMainAttributes().getValue( "Implementation-Version" );
716+
}
717+
else {
718+
return manifest.getMainAttributes().getValue( "Bundle-Version" );
719+
}
720+
}
721+
662722
}

testData/mapping/dto/CarDto.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ public void addPassenger(PersonDto passenger) {
8383
this.passengers.add( passenger );
8484
}
8585

86+
public void removePassenger(PersonDTO passenger) {
87+
if ( this.passengers != null ) {
88+
this.passengers.remove( passenger );
89+
}
90+
}
91+
8692
public Long getPrice() {
8793
return price;
8894
}

testData/mapping/dto/FluentCarDto.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ public FluentCarDto addPassenger(PersonDto passenger) {
7575
return this;
7676
}
7777

78+
public FluentCarDto removePassenger(PersonDto passenger) {
79+
if ( this.passengers != null ) {
80+
this.passengers.remove( passenger );
81+
}
82+
return this;
83+
}
84+
7885
public Long getPrice() {
7986
return price;
8087
}

0 commit comments

Comments
 (0)