Skip to content

Commit 60794df

Browse files
authored
#180 WrongUsageOfMappersFactory componentModel from config (#186)
1 parent 1100022 commit 60794df

File tree

5 files changed

+312
-16
lines changed

5 files changed

+312
-16
lines changed

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

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.jetbrains.annotations.Nls;
3030
import org.jetbrains.annotations.NotNull;
3131
import org.mapstruct.intellij.MapStructBundle;
32+
import org.mapstruct.intellij.util.MapstructAnnotationUtils;
3233
import org.mapstruct.intellij.util.MapstructUtil;
3334

3435
import java.util.ArrayList;
@@ -45,6 +46,7 @@ public class WrongUsageOfMappersFactoryInspection extends InspectionBase {
4546
MapstructUtil.MAPPERS_FQN,
4647
"getMapper"
4748
).parameterTypes( CommonClassNames.JAVA_LANG_CLASS );
49+
private static final String COMPONENT_MODEL = "componentModel";
4850

4951
@NotNull
5052
@Override
@@ -103,17 +105,24 @@ public void visitMethodCallExpression(PsiMethodCallExpression expression) {
103105
else {
104106
PsiNameValuePair componentModelAttribute = AnnotationUtil.findDeclaredAttribute(
105107
mapperAnnotation,
106-
"componentModel"
108+
COMPONENT_MODEL
107109
);
108-
PsiAnnotationMemberValue memberValue = componentModelAttribute == null ?
109-
null :
110-
componentModelAttribute.getDetachedValue();
111-
String componentModel = memberValue == null ?
112-
null :
113-
AnnotationUtil.getStringAttributeValue( memberValue );
110+
PsiAnnotationMemberValue memberValue;
111+
112+
if (componentModelAttribute != null) {
113+
memberValue = componentModelAttribute.getDetachedValue();
114+
}
115+
else {
116+
memberValue = MapstructAnnotationUtils.findConfigValueFromMapperConfig( mapperAnnotation,
117+
COMPONENT_MODEL );
118+
}
119+
String componentModel = memberValue == null ? null :
120+
AnnotationUtil.getStringAttributeValue( memberValue );
114121
if ( componentModel != null && !componentModel.equals( "default" ) ) {
115122
List<LocalQuickFix> fixes = new ArrayList<>(2);
116-
fixes.add( createRemoveComponentModelFix( componentModelAttribute, mapperClass ) );
123+
if (componentModelAttribute != null) {
124+
fixes.add( createRemoveComponentModelFix( componentModelAttribute, mapperClass ) );
125+
}
117126
LocalQuickFix removeMappersFix = createRemoveMappersFix( expression );
118127
if ( removeMappersFix != null ) {
119128
fixes.add( removeMappersFix );

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

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -567,22 +567,34 @@ private static ReportingPolicy getUnmappedTargetPolicyFromClass(@NotNull PsiClas
567567

568568
@NotNull
569569
private static ReportingPolicy getUnmappedTargetPolicyFromMapperConfig(@NotNull PsiAnnotation mapperAnnotation) {
570+
PsiAnnotationMemberValue configValue = findConfigValueFromMapperConfig( mapperAnnotation,
571+
UNMAPPED_TARGET_POLICY );
572+
if (configValue == null) {
573+
return ReportingPolicy.WARN;
574+
}
575+
return getUnmappedTargetPolicyPolicyFromAnnotation( configValue );
576+
}
577+
578+
/**
579+
* finds a property from a referenced mapper config class
580+
* @param mapperAnnotation the @Mapper annotation from the current class
581+
* @param name the name of the property tp find
582+
* @return null if no mapper config class is used or no property with name is found.
583+
*/
584+
@Nullable
585+
public static PsiAnnotationMemberValue findConfigValueFromMapperConfig(@NotNull PsiAnnotation mapperAnnotation,
586+
@NotNull String name) {
570587
PsiModifierListOwner mapperConfigReference = findMapperConfigReference( mapperAnnotation );
571588
if ( mapperConfigReference == null ) {
572-
return ReportingPolicy.WARN;
589+
return null;
573590
}
574591
PsiAnnotation mapperConfigAnnotation = mapperConfigReference.getAnnotation(
575592
MapstructUtil.MAPPER_CONFIG_ANNOTATION_FQN );
576593

577594
if ( mapperConfigAnnotation == null ) {
578-
return ReportingPolicy.WARN;
579-
}
580-
PsiAnnotationMemberValue configValue =
581-
mapperConfigAnnotation.findDeclaredAttributeValue( UNMAPPED_TARGET_POLICY );
582-
if ( configValue == null ) {
583-
return ReportingPolicy.WARN;
595+
return null;
584596
}
585-
return getUnmappedTargetPolicyPolicyFromAnnotation( configValue );
597+
return mapperConfigAnnotation.findDeclaredAttributeValue( name );
586598
}
587599

588600

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright MapStruct Authors.
3+
*
4+
* Licensed under the Apache License version 2.0, available at https://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
package org.mapstruct.intellij.bugs._180;
7+
8+
import com.intellij.codeInsight.intention.IntentionAction;
9+
import org.jetbrains.annotations.NotNull;
10+
import org.mapstruct.intellij.inspection.BaseInspectionTest;
11+
import org.mapstruct.intellij.inspection.WrongUsageOfMappersFactoryInspection;
12+
13+
import java.util.List;
14+
15+
import static org.assertj.core.api.Assertions.assertThat;
16+
17+
/**
18+
* @author hduelme
19+
*/
20+
public class WrongUsageOfMappersFactoryFromConfigInspectionTest extends BaseInspectionTest {
21+
22+
@Override
23+
protected String getTestDataPath() {
24+
return "testData/bugs/_180";
25+
}
26+
27+
@NotNull
28+
@Override
29+
protected Class<WrongUsageOfMappersFactoryInspection> getInspection() {
30+
return WrongUsageOfMappersFactoryInspection.class;
31+
}
32+
33+
public void testWrongUsageOfMappersFactoryFromConfig() {
34+
doTest();
35+
String testName = getTestName( false );
36+
List<IntentionAction> allQuickFixes = myFixture.getAllQuickFixes();
37+
38+
assertThat( allQuickFixes )
39+
.extracting( IntentionAction::getText )
40+
.as( "Intent Text" )
41+
.containsExactly(
42+
"Remove 'spring' componentModel from 'SpringConfigComponentModelOverrideMapper' @Mapper",
43+
"Remove usage of Mappers factory",
44+
"Remove usage of Mappers factory",
45+
"Remove usage of Mappers factory",
46+
"Remove usage of Mappers factory"
47+
);
48+
// Remove usage fix
49+
myFixture.launchAction( allQuickFixes.get( 1 ) );
50+
myFixture.launchAction( allQuickFixes.get( 2 ) );
51+
myFixture.launchAction( allQuickFixes.get( 3 ) );
52+
myFixture.launchAction( allQuickFixes.get( 4 ) );
53+
myFixture.checkResultByFile( testName + "_after.java" );
54+
}
55+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright MapStruct Authors.
3+
*
4+
* Licensed under the Apache License version 2.0, available at https://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
7+
import org.mapstruct.Mapper;
8+
import org.mapstruct.MapperConfig;
9+
import org.mapstruct.ReportingPolicy;
10+
import org.mapstruct.factory.Mappers;
11+
12+
@Mapper(config = DefaultConfigComponentModelMapper.DefaultConfig.class)
13+
interface DefaultConfigComponentModelMapper {
14+
15+
@MapperConfig(componentModel = "default")
16+
interface DefaultConfig {
17+
18+
}
19+
20+
DefaultConfigComponentModelMapper INSTANCE = Mappers.getMapper( DefaultConfigComponentModelMapper.class );
21+
22+
Target map(Source source);
23+
}
24+
25+
@Mapper(config = SpringConfigComponentModelOverrideMapper.DefaultConfig.class, componentModel = "spring")
26+
interface SpringConfigComponentModelOverrideMapper {
27+
28+
@MapperConfig(componentModel = "default")
29+
interface DefaultConfig {
30+
31+
}
32+
33+
SpringConfigComponentModelOverrideMapper INSTANCE = <warning descr="Using Mappers factory with non default component model">Mappers.getMapper( SpringConfigComponentModelOverrideMapper.class )</warning>;
34+
35+
Target map(Source source);
36+
}
37+
38+
@Mapper(config = SpringConfigComponentModelMapper.SpringConfig.class)
39+
interface SpringConfigComponentModelMapper {
40+
41+
@MapperConfig(componentModel = "spring")
42+
interface SpringConfig {
43+
44+
}
45+
46+
SpringConfigComponentModelMapper INSTANCE = <warning descr="Using Mappers factory with non default component model">Mappers.getMapper( SpringConfigComponentModelMapper.class )</warning>;
47+
48+
Target map(Source source);
49+
}
50+
51+
@Mapper(config = Jsr330ConfigComponentModelMapper.Jsr33Config.class, unmappedTargetPolicy = ReportingPolicy.ERROR)
52+
interface Jsr330ConfigComponentModelMapper {
53+
54+
@MapperConfig(componentModel = "jsr330")
55+
interface Jsr33Config {
56+
57+
}
58+
59+
Jsr330ConfigComponentModelMapper INSTANCE = <warning descr="Using Mappers factory with non default component model">Mappers.getMapper( Jsr330ConfigComponentModelMapper.class )</warning>;
60+
61+
Target map(Source source);
62+
}
63+
64+
@Mapper(config = CustomConfigComponentModelMapper.CustomConfig.class)
65+
interface CustomConfigComponentModelMapper {
66+
67+
@MapperConfig(componentModel = "custom")
68+
interface CustomConfig {
69+
70+
}
71+
72+
CustomConfigComponentModelMapper INSTANCE = <warning descr="Using Mappers factory with non default component model">Mappers.getMapper( CustomConfigComponentModelMapper.class )</warning>;
73+
74+
Target map(Source source);
75+
}
76+
77+
@Mapper(config = DefaultConfigComponentModelOverrideMapper.SpringConfig.class, componentModel = "default")
78+
interface DefaultConfigComponentModelOverrideMapper {
79+
80+
@MapperConfig(componentModel = "spring")
81+
interface SpringConfig {
82+
83+
}
84+
85+
DefaultConfigComponentModelOverrideMapper INSTANCE = Mappers.getMapper( DefaultConfigComponentModelOverrideMapper.class );
86+
87+
Target map(Source source);
88+
}
89+
90+
class Source {
91+
92+
private String value;
93+
94+
public String getValue() {
95+
return value;
96+
}
97+
98+
public void setValue(String value) {
99+
this.value = value;
100+
}
101+
}
102+
103+
class Target {
104+
105+
private String value;
106+
107+
public String getValue() {
108+
return value;
109+
}
110+
111+
public void setValue(String value) {
112+
this.value = value;
113+
}
114+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright MapStruct Authors.
3+
*
4+
* Licensed under the Apache License version 2.0, available at https://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
7+
import org.mapstruct.Mapper;
8+
import org.mapstruct.MapperConfig;
9+
import org.mapstruct.ReportingPolicy;
10+
import org.mapstruct.factory.Mappers;
11+
12+
@Mapper(config = DefaultConfigComponentModelMapper.DefaultConfig.class)
13+
interface DefaultConfigComponentModelMapper {
14+
15+
@MapperConfig(componentModel = "default")
16+
interface DefaultConfig {
17+
18+
}
19+
20+
DefaultConfigComponentModelMapper INSTANCE = Mappers.getMapper( DefaultConfigComponentModelMapper.class );
21+
22+
Target map(Source source);
23+
}
24+
25+
@Mapper(config = SpringConfigComponentModelOverrideMapper.DefaultConfig.class, componentModel = "spring")
26+
interface SpringConfigComponentModelOverrideMapper {
27+
28+
@MapperConfig(componentModel = "default")
29+
interface DefaultConfig {
30+
31+
}
32+
33+
Target map(Source source);
34+
}
35+
36+
@Mapper(config = SpringConfigComponentModelMapper.SpringConfig.class)
37+
interface SpringConfigComponentModelMapper {
38+
39+
@MapperConfig(componentModel = "spring")
40+
interface SpringConfig {
41+
42+
}
43+
44+
Target map(Source source);
45+
}
46+
47+
@Mapper(config = Jsr330ConfigComponentModelMapper.Jsr33Config.class, unmappedTargetPolicy = ReportingPolicy.ERROR)
48+
interface Jsr330ConfigComponentModelMapper {
49+
50+
@MapperConfig(componentModel = "jsr330")
51+
interface Jsr33Config {
52+
53+
}
54+
55+
Target map(Source source);
56+
}
57+
58+
@Mapper(config = CustomConfigComponentModelMapper.CustomConfig.class)
59+
interface CustomConfigComponentModelMapper {
60+
61+
@MapperConfig(componentModel = "custom")
62+
interface CustomConfig {
63+
64+
}
65+
66+
Target map(Source source);
67+
}
68+
69+
@Mapper(config = DefaultConfigComponentModelOverrideMapper.SpringConfig.class, componentModel = "default")
70+
interface DefaultConfigComponentModelOverrideMapper {
71+
72+
@MapperConfig(componentModel = "spring")
73+
interface SpringConfig {
74+
75+
}
76+
77+
DefaultConfigComponentModelOverrideMapper INSTANCE = Mappers.getMapper( DefaultConfigComponentModelOverrideMapper.class );
78+
79+
Target map(Source source);
80+
}
81+
82+
class Source {
83+
84+
private String value;
85+
86+
public String getValue() {
87+
return value;
88+
}
89+
90+
public void setValue(String value) {
91+
this.value = value;
92+
}
93+
}
94+
95+
class Target {
96+
97+
private String value;
98+
99+
public String getValue() {
100+
return value;
101+
}
102+
103+
public void setValue(String value) {
104+
this.value = value;
105+
}
106+
}

0 commit comments

Comments
 (0)