Skip to content

Commit 7fe1c86

Browse files
thunderhookfiliphr
authored andcommitted
Find disabled builder in @MapperConfig
closes #97
1 parent 44f5d97 commit 7fe1c86

9 files changed

+205
-2
lines changed

change-notes.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ <h2>1.4.0</h2>
33
<ul>
44
<li>Suppress redundant default parameter value assignment warning for <code>Mapping#constant</code> and <code>Mapping#defaultValue</code></li>
55
<li>Support for Java records</li>
6+
<li>Support MapStruct explicit <code>Builder#disableBuilder</code> through <code>@MapperConfig</code></li>
67
<li>Bug fix: language injections inside expressions when target is field</li>
78
</ul>
89
<h2>1.3.1</h2>

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@
2424
import com.intellij.psi.PsiAnnotation;
2525
import com.intellij.psi.PsiAnnotationMemberValue;
2626
import com.intellij.psi.PsiArrayInitializerMemberValue;
27+
import com.intellij.psi.PsiClassObjectAccessExpression;
2728
import com.intellij.psi.PsiElement;
2829
import com.intellij.psi.PsiFile;
30+
import com.intellij.psi.PsiJavaCodeReferenceElement;
2931
import com.intellij.psi.PsiMethod;
32+
import com.intellij.psi.PsiModifierListOwner;
3033
import com.intellij.psi.PsiNameValuePair;
3134
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
3235
import com.intellij.util.IncorrectOperationException;
@@ -286,4 +289,37 @@ private static boolean isMappingPsiAnnotation(PsiAnnotationMemberValue memberVal
286289
private static boolean isMappingAnnotation(PsiAnnotation psiAnnotation) {
287290
return Objects.equals( psiAnnotation.getQualifiedName(), MAPPING_ANNOTATION_FQN );
288291
}
292+
293+
/**
294+
* Find the mapper config reference class or interface defined in the {@code mapperAnnotation}
295+
*
296+
* @param mapperAnnotation the mapper annotation in which the mapper config is defined
297+
*
298+
* @return the class / interface that is defined in the mapper config,
299+
* or {@code null} if there isn't anything defined
300+
*/
301+
public static PsiModifierListOwner findMapperConfigReference(PsiAnnotation mapperAnnotation) {
302+
PsiNameValuePair configAttribute = findDeclaredAttribute( mapperAnnotation, "config" );
303+
if ( configAttribute == null ) {
304+
return null;
305+
}
306+
307+
PsiAnnotationMemberValue configValue = configAttribute.getValue();
308+
if ( !( configValue instanceof PsiClassObjectAccessExpression ) ) {
309+
return null;
310+
}
311+
312+
PsiJavaCodeReferenceElement referenceElement = ( (PsiClassObjectAccessExpression) configValue ).getOperand()
313+
.getInnermostComponentReferenceElement();
314+
if ( referenceElement == null ) {
315+
return null;
316+
}
317+
318+
PsiElement resolvedElement = referenceElement.resolve();
319+
if ( !( resolvedElement instanceof PsiModifierListOwner ) ) {
320+
return null;
321+
}
322+
323+
return (PsiModifierListOwner) resolvedElement;
324+
}
289325
}

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import static com.intellij.codeInsight.AnnotationUtil.findAnnotation;
4343
import static com.intellij.codeInsight.AnnotationUtil.getBooleanAttributeValue;
4444
import static org.mapstruct.intellij.util.MapstructAnnotationUtils.findAllDefinedMappingAnnotations;
45+
import static org.mapstruct.intellij.util.MapstructAnnotationUtils.findMapperConfigReference;
4546
import static org.mapstruct.intellij.util.MapstructUtil.canDescendIntoType;
4647
import static org.mapstruct.intellij.util.MapstructUtil.isFluentSetter;
4748
import static org.mapstruct.intellij.util.MapstructUtil.publicFields;
@@ -148,10 +149,18 @@ public static boolean isBuilderEnabled(@Nullable PsiMethod mappingMethod) {
148149
Optional<Boolean> disableBuilder = findDisableBuilder( mappingMethod, MapstructUtil.BEAN_MAPPING_FQN );
149150

150151
if ( !disableBuilder.isPresent() && mappingMethod != null ) {
151-
disableBuilder = findDisableBuilder(
152+
PsiAnnotation mapperAnnotation = findAnnotation(
152153
mappingMethod.getContainingClass(),
153154
MapstructUtil.MAPPER_ANNOTATION_FQN
154155
);
156+
disableBuilder = findDisabledBuilder( mapperAnnotation );
157+
158+
if ( disableBuilder.isEmpty() && mapperAnnotation != null ) {
159+
disableBuilder = findDisableBuilder(
160+
findMapperConfigReference( mapperAnnotation ),
161+
MapstructUtil.MAPPER_CONFIG_ANNOTATION_FQN
162+
);
163+
}
155164
}
156165

157166
return !disableBuilder.orElse( false );
@@ -160,6 +169,10 @@ public static boolean isBuilderEnabled(@Nullable PsiMethod mappingMethod) {
160169
private static Optional<Boolean> findDisableBuilder(@Nullable PsiModifierListOwner listOwner,
161170
String annotationName) {
162171
PsiAnnotation requestedAnnotation = findAnnotation( listOwner, true, annotationName );
172+
return findDisabledBuilder( requestedAnnotation );
173+
}
174+
175+
private static Optional<Boolean> findDisabledBuilder(@Nullable PsiAnnotation requestedAnnotation) {
163176
if ( requestedAnnotation != null ) {
164177
PsiNameValuePair builderAttribute = AnnotationUtil.findDeclaredAttribute( requestedAnnotation, "builder" );
165178
if ( builderAttribute != null ) {

src/test/java/org/mapstruct/intellij/MapstructCompletionTestCase.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,4 +992,24 @@ public void testMapperWithBuilderAndMapperDisabledBuilderAndBeanMappingOther() {
992992
);
993993
}
994994

995+
public void testMapperWithBuilderAndMapperConfigDisabledBuilder() {
996+
configureByTestName();
997+
998+
assertThat( myItems )
999+
.extracting( LookupElement::getLookupString )
1000+
.containsExactlyInAnyOrder(
1001+
"targetValue"
1002+
);
1003+
}
1004+
1005+
public void testMapperWithBuilderAndMapperConfigDisabledBuilderAndMapperEnable() {
1006+
configureByTestName();
1007+
1008+
assertThat( myItems )
1009+
.extracting( LookupElement::getLookupString )
1010+
.containsExactlyInAnyOrder(
1011+
"builderValue"
1012+
);
1013+
}
1014+
9951015
}

src/test/java/org/mapstruct/intellij/inspection/UnmappedTargetPropertiesWithBuilderInspectionTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ public void testUnmappedTargetPropertiesWithBuilder() {
5151
"Add unmapped target property: 'targetTestName'",
5252

5353
"Ignore unmapped target property: 'builderTestName'",
54-
"Add unmapped target property: 'builderTestName'"
54+
"Add unmapped target property: 'builderTestName'",
55+
56+
"Ignore unmapped target property: 'targetTestName'",
57+
"Add unmapped target property: 'targetTestName'"
5558
);
5659

5760
allQuickFixes.forEach( myFixture::launchAction );

testData/inspection/UnmappedTargetPropertiesWithBuilder.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.mapstruct.BeanMapping;
88
import org.mapstruct.Builder;
99
import org.mapstruct.Mapper;
10+
import org.mapstruct.MapperConfig;
1011
import org.mapstruct.Mapping;
1112
import org.example.data.UnmappedTargetPropertiesData.Target;
1213

@@ -35,3 +36,14 @@ interface MapperDisabledBuilderBeanMappingEnabledBuilder {
3536
@BeanMapping(builder = @Builder(disableBuilder = false))
3637
Target <warning descr="Unmapped target property: builderTestName">map</warning>(String source);
3738
}
39+
40+
@MapperConfig(builder = @Builder(disableBuilder = true))
41+
class DoNotUseBuilderMapperConfig {
42+
43+
}
44+
45+
@Mapper(config = DoNotUseBuilderMapperConfig.class)
46+
interface MapperConfigDisabledBuilder {
47+
48+
Target <warning descr="Unmapped target property: targetTestName">map</warning>(String source);
49+
}

testData/inspection/UnmappedTargetPropertiesWithBuilder_after.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.mapstruct.BeanMapping;
88
import org.mapstruct.Builder;
99
import org.mapstruct.Mapper;
10+
import org.mapstruct.MapperConfig;
1011
import org.mapstruct.Mapping;
1112
import org.example.data.UnmappedTargetPropertiesData.Target;
1213

@@ -43,3 +44,16 @@ interface MapperDisabledBuilderBeanMappingEnabledBuilder {
4344
@BeanMapping(builder = @Builder(disableBuilder = false))
4445
Target map(String source);
4546
}
47+
48+
@MapperConfig(builder = @Builder(disableBuilder = true))
49+
class DoNotUseBuilderMapperConfig {
50+
51+
}
52+
53+
@Mapper(config = DoNotUseBuilderMapperConfig.class)
54+
interface MapperConfigDisabledBuilder {
55+
56+
@Mapping(target = "targetTestName", source = "")
57+
@Mapping(target = "targetTestName", ignore = true)
58+
Target map(String source);
59+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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.ap.test.complex;
7+
8+
import java.util.List;
9+
10+
import org.mapstruct.Builder;
11+
import org.mapstruct.Mapper;
12+
import org.mapstruct.MapperConfig;
13+
import org.mapstruct.Mapping;
14+
15+
@Mapper(config = CarMapper.MapperConfigDisabledBuilder.class)
16+
public interface CarMapper {
17+
18+
@Mapping(target = "<caret>")
19+
Target map(String source);
20+
21+
class Target {
22+
23+
private String targetValue;
24+
25+
public String getTargetValue() {
26+
return targetValue;
27+
}
28+
29+
public void setTargetValue(String targetValue) {
30+
this.targetValue = targetValue;
31+
}
32+
33+
public static Builder builder() {
34+
return null;
35+
}
36+
37+
public static class Builder {
38+
39+
public Builder builderValue(String address) {
40+
41+
}
42+
43+
public Target build() {
44+
return null;
45+
}
46+
}
47+
}
48+
49+
@MapperConfig(builder = @Builder(disableBuilder = true))
50+
interface MapperConfigDisabledBuilder {}
51+
52+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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.ap.test.complex;
7+
8+
import java.util.List;
9+
10+
import org.mapstruct.Builder;
11+
import org.mapstruct.Mapper;
12+
import org.mapstruct.MapperConfig;
13+
import org.mapstruct.Mapping;
14+
15+
@Mapper(config = CarMapper.MapperConfigDisabledBuilder.class, builder = @Builder(disableBuilder = false))
16+
public interface CarMapper {
17+
18+
@Mapping(target = "<caret>")
19+
Target map(String source);
20+
21+
class Target {
22+
23+
private String targetValue;
24+
25+
public String getTargetValue() {
26+
return targetValue;
27+
}
28+
29+
public void setTargetValue(String targetValue) {
30+
this.targetValue = targetValue;
31+
}
32+
33+
public static Builder builder() {
34+
return null;
35+
}
36+
37+
public static class Builder {
38+
39+
public Builder builderValue(String address) {
40+
41+
}
42+
43+
public Target build() {
44+
return null;
45+
}
46+
}
47+
}
48+
49+
@MapperConfig(builder = @Builder(disableBuilder = true))
50+
interface MapperConfigDisabledBuilder {}
51+
52+
}

0 commit comments

Comments
 (0)