Skip to content

Commit 496370a

Browse files
committed
Add support for code completion in BeanMappingignoreUnmappedSourceProperties
Closes #77
1 parent 100a425 commit 496370a

14 files changed

+268
-4
lines changed

change-notes.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<html>
22
<h2>1.3.0</h2>
33
<ul>
4+
<li>Support code completion in <code>BeanMapping#ignoreUnmappedSourceProperties</code></li>
45
<li>Quick Fix: support for configuring the order of source and target in <code>@Mapping</code> for "Add unmapped property" fix</li>
56
</ul>
67
<h2>1.2.4</h2>

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,16 +145,17 @@ private static ElementManipulator<PsiElement> getManipulator(PsiElement psiEleme
145145
*
146146
* @param psiElement the literal that contain
147147
* @param creator The creator that should be used to create new references
148+
* @param supportsNested whether the target value can have nested references
148149
* @param <T> the type of the reference that needs to be created
149150
*
150151
* @return the array of all the references
151152
*/
152153
static <T extends MapstructBaseReference> PsiReference[] create(PsiElement psiElement,
153-
ReferenceCreator<T> creator) {
154+
ReferenceCreator<T> creator, boolean supportsNested) {
154155
ElementManipulator<PsiElement> manipulator = getManipulator( psiElement );
155156
TextRange rangeInElement = manipulator.getRangeInElement( psiElement );
156157
String targetValue = rangeInElement.substring( psiElement.getText() );
157-
String[] parts = targetValue.split( "\\." );
158+
String[] parts = supportsNested ? targetValue.split( "\\." ) : new String[] { targetValue };
158159
if ( parts.length == 0 ) {
159160
return PsiReference.EMPTY_ARRAY;
160161
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.intellij.psi.PsiReferenceRegistrar;
1010
import org.jetbrains.annotations.NotNull;
1111

12+
import static org.mapstruct.intellij.util.MapstructKotlinElementUtils.beanMappingElementPattern;
1213
import static org.mapstruct.intellij.util.MapstructKotlinElementUtils.mappingElementPattern;
1314
import static org.mapstruct.intellij.util.MapstructKotlinElementUtils.valueMappingElementPattern;
1415

@@ -30,6 +31,10 @@ public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar)
3031
mappingElementPattern( "source" ),
3132
new MappingTargetReferenceProvider( MapstructSourceReference::create )
3233
);
34+
registrar.registerReferenceProvider(
35+
beanMappingElementPattern( "ignoreUnmappedSourceProperties" ),
36+
new MappingTargetReferenceProvider( MapstructSourceReference::createNonNested )
37+
);
3338
registrar.registerReferenceProvider(
3439
valueMappingElementPattern( "target" ),
3540
new MappingTargetReferenceProvider( ValueMappingSourceReference::create )

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.intellij.psi.PsiReferenceRegistrar;
1010
import org.jetbrains.annotations.NotNull;
1111

12+
import static org.mapstruct.intellij.util.MapstructElementUtils.beanMappingElementPattern;
1213
import static org.mapstruct.intellij.util.MapstructElementUtils.mappingElementPattern;
1314
import static org.mapstruct.intellij.util.MapstructElementUtils.valueMappingElementPattern;
1415

@@ -30,6 +31,11 @@ public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar)
3031
new MappingTargetReferenceProvider( MapstructSourceReference::create )
3132
);
3233

34+
registrar.registerReferenceProvider(
35+
beanMappingElementPattern( "ignoreUnmappedSourceProperties" ),
36+
new MappingTargetReferenceProvider( MapstructSourceReference::createNonNested )
37+
);
38+
3339
registrar.registerReferenceProvider(
3440
valueMappingElementPattern( "source" ),
3541
new MappingTargetReferenceProvider( ValueMappingSourceReference::create )

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,16 @@ else if ( element instanceof PsiParameter ) {
131131
* @return the references for the given {@code psiLiteral}
132132
*/
133133
static PsiReference[] create(PsiElement psiElement) {
134-
return MapstructBaseReference.create( psiElement, MapstructSourceReference::new );
134+
return MapstructBaseReference.create( psiElement, MapstructSourceReference::new, true );
135+
}
136+
137+
/**
138+
* @param psiElement the literal for which references need to be created
139+
*
140+
* @return the references for the given {@code psiLiteral}
141+
*/
142+
static PsiReference[] createNonNested(PsiElement psiElement) {
143+
return MapstructBaseReference.create( psiElement, MapstructSourceReference::new, false );
135144
}
136145

137146
private static PsiType memberPsiType(PsiElement psiMember) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ else if ( element instanceof PsiParameter ) {
158158
* @return the references for the given {@code psiLiteral}
159159
*/
160160
static PsiReference[] create(PsiElement psiElement) {
161-
return MapstructBaseReference.create( psiElement, MapstructTargetReference::new );
161+
return MapstructBaseReference.create( psiElement, MapstructTargetReference::new, true );
162162
}
163163

164164
private static PsiType memberPsiType(PsiElement psiMember) {

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@ public static PsiJavaElementPattern.Capture<PsiElement> mapperConfigElementPatte
6060
return elementPattern( parameterName, MapstructUtil.MAPPER_CONFIG_ANNOTATION_FQN );
6161
}
6262

63+
/**
64+
* @param parameterName the name of the parameter in the {@code @BeanMapping} annotation
65+
*
66+
* @return an element pattern for a parameter in the {@code @BeanMapping} annotation
67+
*/
68+
public static PsiJavaElementPattern.Capture<PsiElement> beanMappingElementPattern(String parameterName) {
69+
return elementPattern( parameterName, MapstructUtil.BEAN_MAPPING_FQN );
70+
}
71+
6372
private static PsiJavaElementPattern.Capture<PsiElement> elementPattern(String parameterName,
6473
String annotationFQN) {
6574
return psiElement()

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ public static KotlinElementPattern.Capture<? extends PsiElement> mappingElementP
5050
);
5151
}
5252

53+
/**
54+
* @param parameterName the name of the parameter in the {@code @BeanMapping} annotation
55+
*
56+
* @return an element pattern for a parameter in the {@code @BeanMapping} annotation
57+
*/
58+
public static KotlinElementPattern.Capture<? extends PsiElement> beanMappingElementPattern(String parameterName) {
59+
return elementPattern(
60+
parameterName,
61+
MapstructUtil.BEAN_MAPPING_FQN
62+
);
63+
}
64+
5365
private static KotlinElementPattern.Capture<? extends PsiElement> elementPattern(String parameterName,
5466
String annotationFQN,
5567
String annotationHolderFQN
@@ -61,4 +73,14 @@ private static KotlinElementPattern.Capture<? extends PsiElement> elementPattern
6173
parameterName
6274
);
6375
}
76+
77+
private static KotlinElementPattern.Capture<? extends PsiElement> elementPattern(String parameterName,
78+
String annotationFQN
79+
) {
80+
return psiElement()
81+
.insideAnnotationParam(
82+
StandardPatterns.string().equalTo( annotationFQN ),
83+
parameterName
84+
);
85+
}
6486
}

src/main/java/org/mapstruct/intellij/util/patterns/KotlinElementPattern.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,20 @@ public Self insideRepeatableAnnotationParam(
4949
);
5050
}
5151

52+
public Self insideAnnotationParam(
53+
ElementPattern<String> annotationQualifiedName,
54+
String parameterName) {
55+
56+
KtValueArgumentPattern ktValueArgumentPattern = ktValueArgument().withName( parameterName );
57+
return withElementType( KtStubElementTypes.STRING_TEMPLATE ).andOr(
58+
withAncestor(
59+
2,
60+
ktValueArgumentPattern
61+
.withSuperParent( 2, ktAnnotation().qName( annotationQualifiedName ) )
62+
)
63+
);
64+
}
65+
5266
public static class Capture<T extends PsiElement> extends KotlinElementPattern<T, KotlinElementPattern.Capture<T>> {
5367
public Capture(Class<T> aClass) {
5468
super( aClass );
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright MapStruct Authors.
3+
*
4+
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
package org.mapstruct.intellij.completion;
7+
8+
import com.intellij.codeInsight.lookup.LookupElement;
9+
import com.intellij.codeInsight.lookup.LookupElementPresentation;
10+
import com.intellij.psi.PsiElement;
11+
import com.intellij.psi.PsiMethod;
12+
import org.mapstruct.intellij.MapstructBaseCompletionTestCase;
13+
14+
import static org.assertj.core.api.Assertions.assertThat;
15+
import static org.mapstruct.intellij.testutil.TestUtils.createVariable;
16+
17+
/**
18+
* @author Filip Hrisafov
19+
*/
20+
public class BeanMappingIgnoreUnmappedSourcePropertiesCompletionTestCase extends MapstructBaseCompletionTestCase {
21+
22+
@Override
23+
protected String getTestDataPath() {
24+
return "testData/completion/beanmapping";
25+
}
26+
27+
@Override
28+
protected void setUp() throws Exception {
29+
super.setUp();
30+
31+
addDirectoryToProject( "../../mapping/dto" );
32+
}
33+
34+
private void assertCarAutoComplete() {
35+
assertThat( myItems )
36+
.extracting( LookupElement::getLookupString )
37+
.containsExactlyInAnyOrder(
38+
"make",
39+
"numberOfSeats",
40+
"manufacturingDate",
41+
"driver",
42+
"passengers",
43+
"price",
44+
"category",
45+
"free"
46+
);
47+
48+
assertThat( myItems )
49+
.extracting( LookupElementPresentation::renderElement )
50+
.usingRecursiveFieldByFieldElementComparator()
51+
.containsExactlyInAnyOrder(
52+
createVariable( "make", "String" ),
53+
createVariable( "numberOfSeats", "int" ),
54+
createVariable( "manufacturingDate", "Date" ),
55+
createVariable( "driver", "Person" ),
56+
createVariable( "passengers", "List<Person>" ),
57+
createVariable( "price", "int" ),
58+
createVariable( "category", "Category" ),
59+
createVariable( "free", "boolean" )
60+
);
61+
}
62+
63+
public void testBeanMappingIgnoreSourcePropertiesSingleCarMapper() {
64+
configureByTestName();
65+
assertCarAutoComplete();
66+
}
67+
68+
public void testCarMapperReferenceSourcePropertyInMulti() {
69+
myFixture.configureByFile( "BeanMappingIgnoreSourcePropertiesSingleReferenceCarMapper.java" );
70+
PsiElement reference = myFixture.getElementAtCaret();
71+
72+
assertThat( reference )
73+
.isInstanceOfSatisfying( PsiMethod.class, method -> {
74+
assertThat( method.getName() ).isEqualTo( "getNumberOfSeats" );
75+
assertThat( method.getPresentation() ).isNotNull();
76+
assertThat( method.getPresentation().getPresentableText() ).isEqualTo( "getNumberOfSeats()" );
77+
assertThat( method.getParameterList().getParametersCount() ).isEqualTo( 0 );
78+
assertThat( method.getReturnType() ).isNotNull();
79+
assertThat( method.getReturnType().getPresentableText() ).isEqualTo( "int" );
80+
} );
81+
}
82+
83+
public void testBeanMappingIgnoreSourcePropertiesMultiCarMapper() {
84+
configureByTestName();
85+
assertCarAutoComplete();
86+
}
87+
88+
public void testCarMapperReferenceSourcePropertyInSingle() {
89+
myFixture.configureByFile( "BeanMappingIgnoreSourcePropertiesMultiReferenceCarMapper.java" );
90+
PsiElement reference = myFixture.getElementAtCaret();
91+
92+
assertThat( reference )
93+
.isInstanceOfSatisfying( PsiMethod.class, method -> {
94+
assertThat( method.getName() ).isEqualTo( "getNumberOfSeats" );
95+
assertThat( method.getPresentation() ).isNotNull();
96+
assertThat( method.getPresentation().getPresentableText() ).isEqualTo( "getNumberOfSeats()" );
97+
assertThat( method.getParameterList().getParametersCount() ).isEqualTo( 0 );
98+
assertThat( method.getReturnType() ).isNotNull();
99+
assertThat( method.getReturnType().getPresentableText() ).isEqualTo( "int" );
100+
} );
101+
}
102+
103+
}

0 commit comments

Comments
 (0)