Skip to content

Commit b55b2e0

Browse files
committed
#33 Align the way property names are determined with the DefaultAccessorNamingStrategy
1 parent 633c8e9 commit b55b2e0

File tree

8 files changed

+219
-98
lines changed

8 files changed

+219
-98
lines changed

src/main/java/org/mapstruct/intellij/codeinsight/references/MapstructSourceReference.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.jetbrains.annotations.Nullable;
2626
import org.mapstruct.intellij.util.MapstructUtil;
2727

28+
import static org.mapstruct.intellij.util.MapstructUtil.asLookup;
2829
import static org.mapstruct.intellij.util.MapstructUtil.isPublic;
2930
import static org.mapstruct.intellij.util.SourceUtils.getParameterType;
3031
import static org.mapstruct.intellij.util.SourceUtils.publicReadAccessors;
@@ -95,9 +96,7 @@ PsiElement resolveInternal(@NotNull String value, @NotNull PsiMethod mappingMeth
9596
@NotNull
9697
@Override
9798
Object[] getVariantsInternal(@NotNull PsiType psiType) {
98-
return publicReadAccessors( psiType )
99-
.map( pair -> MapstructUtil.asLookup( pair, MapstructSourceReference::memberPsiType ) )
100-
.toArray();
99+
return asLookup( publicReadAccessors( psiType ), MapstructSourceReference::memberPsiType );
101100
}
102101

103102
@NotNull

src/main/java/org/mapstruct/intellij/codeinsight/references/MapstructTargetReference.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.jetbrains.annotations.Nullable;
2727
import org.mapstruct.intellij.util.MapstructUtil;
2828

29+
import static org.mapstruct.intellij.util.MapstructUtil.asLookup;
2930
import static org.mapstruct.intellij.util.MapstructUtil.isPublicModifiable;
3031
import static org.mapstruct.intellij.util.TargetUtils.getRelevantType;
3132
import static org.mapstruct.intellij.util.TargetUtils.publicWriteAccessors;
@@ -111,9 +112,10 @@ PsiElement resolveInternal(@NotNull String value, @NotNull PsiMethod mappingMeth
111112
@NotNull
112113
@Override
113114
Object[] getVariantsInternal(@NotNull PsiType psiType) {
114-
return publicWriteAccessors( psiType, builderSupportPresent )
115-
.map( pair -> MapstructUtil.asLookup( pair, MapstructTargetReference::memberPsiType ) )
116-
.toArray();
115+
return asLookup(
116+
publicWriteAccessors( psiType, builderSupportPresent ),
117+
MapstructTargetReference::memberPsiType
118+
);
117119
}
118120

119121
@NotNull

src/main/java/org/mapstruct/intellij/inspection/UnmappedTargetPropertiesInspection.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,15 @@ public void visitMethod(PsiMethod method) {
6969
return;
7070
}
7171

72-
Set<String> allTargetProperties = findAllTargetProperties( targetType, builderSupportPresent )
73-
.collect( Collectors.toSet() );
72+
Set<String> allTargetProperties = findAllTargetProperties( targetType, builderSupportPresent );
7473

7574
// find and remove all defined mapping targets
7675
Set<String> definedTargets = TargetUtils.findAllDefinedMappingTargets( method )
7776
.collect( Collectors.toSet() );
7877
allTargetProperties.removeAll( definedTargets );
7978

8079
//TODO maybe we need to improve this by more granular extraction
81-
Set<String> sourceProperties = findAllSourceProperties( method )
82-
.collect( Collectors.toSet() );
80+
Set<String> sourceProperties = findAllSourceProperties( method );
8381
allTargetProperties.removeAll( sourceProperties );
8482

8583
int missingTargetProperties = allTargetProperties.size();

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

Lines changed: 32 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
package org.mapstruct.intellij.util;
77

88
import java.beans.Introspector;
9-
import java.util.ArrayList;
109
import java.util.Collections;
10+
import java.util.HashMap;
1111
import java.util.List;
12+
import java.util.Map;
1213
import java.util.function.Function;
1314
import java.util.stream.Stream;
1415

@@ -91,12 +92,34 @@ public final class MapstructUtil {
9192
private MapstructUtil() {
9293
}
9394

94-
public static <T extends PsiMember> LookupElement asLookup(@NotNull Pair<T, PsiSubstitutor> pair,
95-
Function<T, PsiType> typeMapper) {
96-
T member = pair.getFirst();
95+
public static LookupElement[] asLookup(Map<String, Pair<? extends PsiMember, PsiSubstitutor>> accessors,
96+
Function<PsiMember, PsiType> typeMapper) {
97+
if ( !accessors.isEmpty() ) {
98+
LookupElement[] lookupElements = new LookupElement[accessors.size()];
99+
int index = 0;
100+
for ( Map.Entry<String, Pair<? extends PsiMember, PsiSubstitutor>> entry :
101+
accessors.entrySet() ) {
102+
String propertyName = entry.getKey();
103+
Pair<? extends PsiMember, PsiSubstitutor> pair = entry.getValue();
104+
lookupElements[index++] = asLookup(
105+
propertyName,
106+
pair,
107+
typeMapper
108+
);
109+
}
110+
return lookupElements;
111+
}
112+
else {
113+
return LookupElement.EMPTY_ARRAY;
114+
}
115+
116+
}
117+
118+
public static LookupElement asLookup(String propertyName, @NotNull Pair<? extends PsiMember, PsiSubstitutor> pair,
119+
Function<PsiMember, PsiType> typeMapper) {
120+
PsiMember member = pair.getFirst();
97121
PsiSubstitutor substitutor = pair.getSecond();
98122

99-
String propertyName = getPropertyName( member );
100123
LookupElementBuilder builder = LookupElementBuilder.create( member, propertyName )
101124
.withIcon( PlatformIcons.VARIABLE_ICON )
102125
.withPresentableText( propertyName )
@@ -144,25 +167,6 @@ public static boolean isPublicModifiable(@NotNull PsiField field) {
144167
!field.hasModifierProperty( PsiModifier.STATIC );
145168
}
146169

147-
public static boolean isSetter(@NotNull PsiMethod method) {
148-
if ( method.getParameterList().getParametersCount() != 1 ) {
149-
return false;
150-
}
151-
//TODO if we can use the AccessorNamingStrategy it would be awesome
152-
String methodName = method.getName();
153-
return methodName.startsWith( "set" );
154-
}
155-
156-
public static boolean isSetterOrFluentSetter(@NotNull PsiMethod method, PsiType psiType) {
157-
if ( method.getParameterList().getParametersCount() != 1 ) {
158-
return false;
159-
}
160-
161-
//TODO if we can use the AccessorNamingStrategy it would be awesome
162-
String methodName = method.getName();
163-
return methodName.startsWith( "set" ) && methodName.length() > 3 || isFluentSetter( method, psiType );
164-
}
165-
166170
public static boolean isFluentSetter(@NotNull PsiMethod method, PsiType psiType) {
167171
return !psiType.getCanonicalText().startsWith( "java.lang" ) &&
168172
method.getReturnType() != null &&
@@ -177,15 +181,6 @@ private static boolean isAdderWithUpperCase4thCharacter(@NotNull PsiMethod metho
177181
Character.isUpperCase( methodName.charAt( 3 ) );
178182
}
179183

180-
public static boolean isGetter(@NotNull PsiMethod method) {
181-
if ( method.getParameterList().getParametersCount() != 0 ) {
182-
return false;
183-
}
184-
//TODO if we can use the AccessorNamingStrategy it would be awesome
185-
String methodName = method.getName();
186-
return ( methodName.startsWith( "get" ) && !methodName.equals( "getClass" )) || methodName.startsWith( "is" );
187-
}
188-
189184
/**
190185
* Checks if the {@code method} is a possible builder creation method.
191186
* <p>
@@ -231,17 +226,6 @@ public static boolean isBuildMethod(@NotNull PsiMethod buildMethod, @NotNull Psi
231226
TypeConversionUtil.isAssignable( typeToBuild, buildMethod.getReturnType() );
232227
}
233228

234-
@NotNull
235-
@NonNls
236-
public static String getPropertyName(@NotNull PsiMember psiMember) {
237-
if ( psiMember instanceof PsiMethod ) {
238-
return getPropertyName( (PsiMethod) psiMember );
239-
}
240-
else {
241-
return psiMember.getName() == null ? "" : psiMember.getName();
242-
}
243-
}
244-
245229
@NotNull
246230
@NonNls
247231
public static String getPropertyName(@NotNull PsiMethod method) {
@@ -373,22 +357,22 @@ public static PsiParameter[] getSourceParameters(@NotNull PsiMethod mappingMetho
373357
.toArray( PsiParameter[]::new );
374358
}
375359

376-
public static List<Pair<PsiField, PsiSubstitutor>> publicFields(PsiClass psiClass) {
360+
public static Map<String, Pair<PsiField, PsiSubstitutor>> publicFields(PsiClass psiClass) {
377361
List<Pair<PsiField, PsiSubstitutor>> fieldPairs = PsiClassImplUtil.getAllWithSubstitutorsByMap(
378362
psiClass,
379363
PsiClassImplUtil.MemberType.FIELD
380364
);
381365

382366
if ( fieldPairs.isEmpty() ) {
383-
return Collections.emptyList();
367+
return Collections.emptyMap();
384368
}
385369

386-
List<Pair<PsiField, PsiSubstitutor>> publicFields = new ArrayList<>( fieldPairs.size() );
370+
Map<String, Pair<PsiField, PsiSubstitutor>> publicFields = new HashMap<>();
387371

388372
for ( Pair<PsiField, PsiSubstitutor> fieldPair : fieldPairs ) {
389373
PsiField field = fieldPair.getFirst();
390374
if ( MapstructUtil.isPublic( field ) ) {
391-
publicFields.add( fieldPair );
375+
publicFields.put( field.getName(), fieldPair );
392376
}
393377
}
394378

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

Lines changed: 57 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55
*/
66
package org.mapstruct.intellij.util;
77

8-
import java.util.ArrayList;
8+
import java.beans.Introspector;
99
import java.util.Arrays;
10+
import java.util.Collections;
11+
import java.util.HashMap;
1012
import java.util.HashSet;
11-
import java.util.List;
12-
import java.util.Objects;
13+
import java.util.Map;
1314
import java.util.Set;
15+
import java.util.stream.Collectors;
1416
import java.util.stream.Stream;
1517

1618
import com.intellij.openapi.util.Pair;
19+
import com.intellij.psi.CommonClassNames;
1720
import com.intellij.psi.PsiClass;
1821
import com.intellij.psi.PsiMember;
1922
import com.intellij.psi.PsiMethod;
@@ -46,19 +49,16 @@ private SourceUtils() {
4649
*
4750
* @return see description
4851
*/
49-
public static Stream<String> findAllSourceProperties(@NotNull PsiMethod method) {
52+
public static Set<String> findAllSourceProperties(@NotNull PsiMethod method) {
5053
PsiParameter[] sourceParameters = getSourceParameters( method );
5154
if ( sourceParameters.length == 1 ) {
52-
return Stream.of( sourceParameters[0] )
53-
.map( SourceUtils::getParameterType )
54-
.filter( Objects::nonNull )
55-
.flatMap( SourceUtils::publicReadAccessors )
56-
.map( pair -> pair.getFirst() )
57-
.map( MapstructUtil::getPropertyName );
55+
PsiType parameterType = SourceUtils.getParameterType( sourceParameters[0] );
56+
return SourceUtils.publicReadAccessors( parameterType ).keySet();
5857
}
5958

6059
return Stream.of( sourceParameters )
61-
.map( PsiParameter::getName );
60+
.map( PsiParameter::getName )
61+
.collect( Collectors.toSet() );
6262
}
6363

6464
/**
@@ -94,18 +94,19 @@ public static PsiType getParameterType(@NotNull PsiParameter parameter) {
9494
*
9595
* @return a stream that holds all public read accessors for the given {@code psiType}
9696
*/
97-
public static Stream<Pair<? extends PsiMember, PsiSubstitutor>> publicReadAccessors(@NotNull PsiType psiType) {
97+
public static Map<String, Pair<? extends PsiMember, PsiSubstitutor>> publicReadAccessors(
98+
@Nullable PsiType psiType) {
9899
PsiClass psiClass = PsiUtil.resolveClassInType( psiType );
99100
if ( psiClass == null ) {
100-
return Stream.empty();
101+
return Collections.emptyMap();
101102
}
102103

103-
List<Pair<? extends PsiMember, PsiSubstitutor>> publicReadAccessors = new ArrayList<>();
104+
Map<String, Pair<? extends PsiMember, PsiSubstitutor>> publicReadAccessors = new HashMap<>();
104105

105-
publicReadAccessors.addAll( publicGetters( psiClass ) );
106-
publicReadAccessors.addAll( publicFields( psiClass ) );
106+
publicReadAccessors.putAll( publicGetters( psiClass ) );
107+
publicReadAccessors.putAll( publicFields( psiClass ) );
107108

108-
return publicReadAccessors.stream();
109+
return publicReadAccessors;
109110
}
110111

111112
/**
@@ -115,19 +116,54 @@ public static Stream<Pair<? extends PsiMember, PsiSubstitutor>> publicReadAccess
115116
*
116117
* @return a list that holds all public getters for the given {@code psiClass}
117118
*/
118-
private static List<Pair<PsiMethod, PsiSubstitutor>> publicGetters(@NotNull PsiClass psiClass) {
119+
private static Map<String, Pair<PsiMethod, PsiSubstitutor>> publicGetters(@NotNull PsiClass psiClass) {
119120
Set<PsiMethod> overriddenMethods = new HashSet<>();
120-
List<Pair<PsiMethod, PsiSubstitutor>> publicGetters = new ArrayList<>();
121+
Map<String, Pair<PsiMethod, PsiSubstitutor>> publicGetters = new HashMap<>();
121122
for ( Pair<PsiMethod, PsiSubstitutor> pair : psiClass.getAllMethodsAndTheirSubstitutors() ) {
122123
PsiMethod method = pair.getFirst();
123-
if ( MapstructUtil.isGetter( method ) && MapstructUtil.isPublic( method ) &&
124+
String propertyName = extractPublicGetterPropertyName( method );
125+
if ( propertyName != null &&
124126
!overriddenMethods.contains( method ) ) {
125127
// If this is a public getter then populate its overridden methods and use it
126128
overriddenMethods.addAll( Arrays.asList( method.findSuperMethods() ) );
127-
publicGetters.add( pair );
129+
publicGetters.put( propertyName, pair );
128130
}
129131
}
130132

131133
return publicGetters;
132134
}
135+
136+
@Nullable
137+
private static String extractPublicGetterPropertyName(PsiMethod method) {
138+
if ( method.getParameterList().getParametersCount() != 0 || !MapstructUtil.isPublic( method ) ) {
139+
return null;
140+
}
141+
// This logic is aligned with the DefaultAccessorNamingStrategy
142+
143+
PsiType returnType = method.getReturnType();
144+
if ( returnType == null || PsiType.VOID.equals( returnType ) ) {
145+
return null;
146+
}
147+
148+
String methodName = method.getName();
149+
if ( methodName.startsWith( "get" ) ) {
150+
if ( !methodName.equals( "getClass" ) ) {
151+
return Introspector.decapitalize( methodName.substring( 3 ) );
152+
}
153+
else {
154+
return null;
155+
}
156+
}
157+
else if ( methodName.startsWith( "is" ) && (
158+
PsiType.BOOLEAN.equals( returnType ) ||
159+
returnType.equalsToText( CommonClassNames.JAVA_LANG_BOOLEAN ) )
160+
) {
161+
// boolean getter
162+
return Introspector.decapitalize( methodName.substring( 2 ) );
163+
}
164+
else {
165+
return null;
166+
}
167+
168+
}
133169
}

0 commit comments

Comments
 (0)