Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ dependencies {
testFramework( TestFrameworkType.Platform.INSTANCE )
testFramework( TestFrameworkType.Bundled.INSTANCE )
}
implementation('org.mapstruct:mapstruct:1.5.3.Final')
implementation('org.mapstruct:mapstruct:1.7.0-SNAPSHOT')
testImplementation(platform('org.junit:junit-bom:5.11.0'))
testImplementation('org.junit.platform:junit-platform-launcher')
testImplementation('org.junit.jupiter:junit-jupiter-api')
Expand All @@ -130,7 +130,7 @@ tasks.register('libs', Sync) {
include('mapstruct-intellij-*.jar')
include('MapStruct-Intellij-*.jar')
}
rename('mapstruct-1.5.3.Final.jar', 'mapstruct.jar')
rename('mapstruct-1.7.0-SNAPSHOT.jar', 'mapstruct.jar')
}

tasks.register('testLibs', Sync) {
Expand Down
15 changes: 11 additions & 4 deletions src/main/java/org/mapstruct/intellij/util/MapStructVersion.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@
*/
public enum MapStructVersion {

V1_2_O( false, false ),
V1_3_O( true, false ),
V1_4_O( true, true );
V1_2_O( false, false, false ),
V1_3_O( true, false, false ),
V1_4_O( true, true, false ),
V1_7_O( true, true, true ),;

private final boolean builderSupported;
private final boolean constructorSupported;
private final boolean ignoringRemovers;

MapStructVersion(boolean builderSupported, boolean constructorSupported) {
MapStructVersion(boolean builderSupported, boolean constructorSupported, boolean ignoringRemovers) {
this.builderSupported = builderSupported;
this.constructorSupported = constructorSupported;
this.ignoringRemovers = ignoringRemovers;
}

public boolean isBuilderSupported() {
Expand All @@ -29,4 +32,8 @@ public boolean isBuilderSupported() {
public boolean isConstructorSupported() {
return constructorSupported;
}

public boolean isIgnoringRemovers() {
return ignoringRemovers;
}
}
62 changes: 61 additions & 1 deletion src/main/java/org/mapstruct/intellij/util/MapstructUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@
package org.mapstruct.intellij.util;

import java.beans.Introspector;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.jar.Manifest;
import java.util.stream.Stream;
import javax.swing.Icon;

Expand All @@ -21,6 +25,8 @@
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Version;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.EmptySubstitutor;
Expand Down Expand Up @@ -61,6 +67,7 @@
import org.mapstruct.MappingTarget;
import org.mapstruct.Mappings;
import org.mapstruct.Named;
//import org.mapstruct.PrimaryMappingSource;
import org.mapstruct.ValueMapping;
import org.mapstruct.ValueMappings;
import org.mapstruct.factory.Mappers;
Expand Down Expand Up @@ -229,9 +236,15 @@ public boolean isFluentSetter(@NotNull PsiMethod method, PsiType psiType, @NotNu
return !psiType.getCanonicalText().startsWith( "java.lang" ) &&
method.getReturnType() != null &&
!isAdderWithUpperCase4thCharacter( method ) &&
!isIgnoredRemover( method ) &&
isAssignableFromReturnTypeOrSuperTypes( psiType, substitutor.substitute( method.getReturnType() ) );
}

private static boolean isIgnoredRemover(@NotNull PsiMethod method) {
return isRemoverWithUpperCase7thCharacter( method )
&& resolveMapStructProjectVersion( method.getContainingFile() ).isIgnoringRemovers();
}

private static boolean isAssignableFromReturnTypeOrSuperTypes(PsiType psiType, @NotNull PsiType returnType) {

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

private static boolean isRemoverWithUpperCase7thCharacter(@NotNull PsiMethod method) {
String methodName = method.getName();
return methodName.startsWith( "remove" ) &&
methodName.length() > 6 &&
Character.isUpperCase( methodName.charAt( 6 ) );
}

/**
* Checks if the {@code method} is a possible builder creation method.
* <p>
Expand Down Expand Up @@ -567,7 +587,12 @@ public static MapStructVersion resolveMapStructProjectVersion(@NotNull PsiFile p
}
return CachedValuesManager.getManager( module.getProject() ).getCachedValue( module, () -> {
MapStructVersion mapStructVersion;
if ( JavaPsiFacade.getInstance( module.getProject() )

Version version = resolveImplementationVersion( module );
if ( version != null && version.isOrGreaterThan( 1, 7 ) ) {
mapStructVersion = MapStructVersion.V1_7_O;
}
else if ( JavaPsiFacade.getInstance( module.getProject() )
.findClass( ENUM_MAPPING_ANNOTATION_FQN, module.getModuleRuntimeScope( false ) ) != null ) {
mapStructVersion = MapStructVersion.V1_4_O;
}
Expand Down Expand Up @@ -659,4 +684,39 @@ public static boolean isInheritInverseConfiguration(PsiMethod method) {
return isAnnotated( method, INHERIT_INVERSE_CONFIGURATION_FQN, AnnotationUtil.CHECK_TYPE );
}

@Nullable
private static Version resolveImplementationVersion(Module module) {
JarFileSystem jarFileSystem = JarFileSystem.getInstance();
return Optional.ofNullable( JavaPsiFacade
.getInstance( module.getProject() )
.findClass( MAPPER_ANNOTATION_FQN, module.getModuleRuntimeScope( false ) ) )
.map( PsiClass::getContainingFile )
.map( PsiFile::getVirtualFile )
.map( jarFileSystem::getVirtualFileForJar )
.map( jarFileSystem::getJarRootForLocalFile )
.map( jarRoot -> jarRoot.findFileByRelativePath( "META-INF/MANIFEST.MF" ) )
.map( MapstructUtil::resolveManifest )
.map( MapstructUtil::resolveVersionString )
.map( Version::parseVersion )
.orElse( null );
}

private static @Nullable Manifest resolveManifest(VirtualFile manifestFile) {
try ( InputStream is = manifestFile.getInputStream() ) {
return new Manifest(is);
}
catch ( IOException e ) {
return null;
}
}

private static @Nullable String resolveVersionString(Manifest manifest) {
if ( manifest.getMainAttributes().containsKey( "Implementation-Version" ) ) {
return manifest.getMainAttributes().getValue( "Implementation-Version" );
}
else {
return manifest.getMainAttributes().getValue( "Bundle-Version" );
}
}

}
6 changes: 6 additions & 0 deletions testData/mapping/dto/CarDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ public void addPassenger(PersonDto passenger) {
this.passengers.add( passenger );
}

public void removePassenger(PersonDTO passenger) {
if ( this.passengers != null ) {
this.passengers.remove( passenger );
}
}

public Long getPrice() {
return price;
}
Expand Down
7 changes: 7 additions & 0 deletions testData/mapping/dto/FluentCarDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ public FluentCarDto addPassenger(PersonDto passenger) {
return this;
}

public FluentCarDto removePassenger(PersonDto passenger) {
if ( this.passengers != null ) {
this.passengers.remove( passenger );
}
return this;
}

public Long getPrice() {
return price;
}
Expand Down