mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#838 check for suitable constructors when reversing
This commit is contained in:
parent
70ba92b229
commit
3d43d022f4
@ -39,6 +39,7 @@ import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.type.WildcardType;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
|
||||
@ -95,6 +96,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
|
||||
private Type boundingBase = null;
|
||||
|
||||
private Boolean hasEmptyAccessibleContructor;
|
||||
|
||||
//CHECKSTYLE:OFF
|
||||
public Type(Types typeUtils, Elements elementUtils, TypeFactory typeFactory,
|
||||
@ -770,4 +772,22 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
|
||||
return boundingBase;
|
||||
}
|
||||
|
||||
|
||||
public boolean hasEmptyAccessibleContructor() {
|
||||
|
||||
if ( this.hasEmptyAccessibleContructor == null ) {
|
||||
hasEmptyAccessibleContructor = false;
|
||||
List<ExecutableElement> constructors = ElementFilter.constructorsIn( typeElement.getEnclosedElements() );
|
||||
for ( ExecutableElement constructor : constructors ) {
|
||||
if ( (constructor.getModifiers().contains( Modifier.PUBLIC )
|
||||
|| constructor.getModifiers().contains( Modifier.PROTECTED ) )
|
||||
&& constructor.getParameters().isEmpty() ) {
|
||||
hasEmptyAccessibleContructor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasEmptyAccessibleContructor;
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,12 @@ public class SourceMethod implements Method {
|
||||
|
||||
private List<SourceMethod> applicablePrototypeMethods;
|
||||
|
||||
private Boolean isBeanMapping;
|
||||
private Boolean isEnumMapping;
|
||||
private Boolean isValueMapping;
|
||||
private Boolean isIterableMapping;
|
||||
private Boolean isMapMapping;
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private Type declaringMapper = null;
|
||||
@ -367,18 +373,40 @@ public class SourceMethod implements Method {
|
||||
}
|
||||
|
||||
public boolean isIterableMapping() {
|
||||
return getSourceParameters().size() == 1 && first( getSourceParameters() ).getType().isIterableType()
|
||||
&& getResultType().isIterableType();
|
||||
if ( isIterableMapping == null ) {
|
||||
isIterableMapping = getSourceParameters().size() == 1
|
||||
&& first( getSourceParameters() ).getType().isIterableType()
|
||||
&& getResultType().isIterableType();
|
||||
}
|
||||
return isIterableMapping;
|
||||
}
|
||||
|
||||
public boolean isMapMapping() {
|
||||
return getSourceParameters().size() == 1 && first( getSourceParameters() ).getType().isMapType()
|
||||
&& getResultType().isMapType();
|
||||
if ( isMapMapping == null ) {
|
||||
isMapMapping = getSourceParameters().size() == 1
|
||||
&& first( getSourceParameters() ).getType().isMapType()
|
||||
&& getResultType().isMapType();
|
||||
}
|
||||
return isMapMapping;
|
||||
}
|
||||
|
||||
public boolean isEnumMapping() {
|
||||
return getSourceParameters().size() == 1 && first( getSourceParameters() ).getType().isEnumType()
|
||||
&& getResultType().isEnumType();
|
||||
if ( isEnumMapping == null ) {
|
||||
isEnumMapping = getSourceParameters().size() == 1
|
||||
&& first( getSourceParameters() ).getType().isEnumType()
|
||||
&& getResultType().isEnumType();
|
||||
}
|
||||
return isEnumMapping;
|
||||
}
|
||||
|
||||
public boolean isBeanMapping() {
|
||||
if ( isBeanMapping == null ) {
|
||||
isBeanMapping = !isIterableMapping()
|
||||
&& !isMapMapping()
|
||||
&& !isEnumMapping()
|
||||
&& !isValueMapping();
|
||||
}
|
||||
return isBeanMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -388,7 +416,11 @@ public class SourceMethod implements Method {
|
||||
* @return whether (true) or not (false) to execute value mappings
|
||||
*/
|
||||
public boolean isValueMapping() {
|
||||
return isEnumMapping() && mappingOptions.getMappings().isEmpty();
|
||||
|
||||
if ( isValueMapping == null ) {
|
||||
isValueMapping = isEnumMapping() && mappingOptions.getMappings().isEmpty();
|
||||
}
|
||||
return isValueMapping;
|
||||
}
|
||||
|
||||
private boolean equals(Object o1, Object o2) {
|
||||
|
@ -458,6 +458,14 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
|
||||
if ( reversePrism != null ) {
|
||||
|
||||
// is there a suitable constructor
|
||||
if ( method.isBeanMapping()
|
||||
&& !method.getResultType().isCollectionOrMapType()
|
||||
&& !method.getResultType().hasEmptyAccessibleContructor() ) {
|
||||
reportErrorWhenNoSuitableConstrutor( method, reversePrism );
|
||||
return null;
|
||||
}
|
||||
|
||||
// method is configured as being reverse method, collect candidates
|
||||
List<SourceMethod> candidates = new ArrayList<SourceMethod>();
|
||||
for ( SourceMethod oneMethod : rawMethods ) {
|
||||
@ -621,6 +629,17 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
}
|
||||
}
|
||||
|
||||
private void reportErrorWhenNoSuitableConstrutor( SourceMethod method,
|
||||
InheritInverseConfigurationPrism reversePrism) {
|
||||
|
||||
messager.printMessage( method.getExecutable(),
|
||||
reversePrism.mirror,
|
||||
Message.INHERITINVERSECONFIGURATION_NO_SUITABLE_CONSTRUCTOR,
|
||||
reversePrism.name()
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
private void reportErrorWhenSeveralNamesMatch(List<SourceMethod> candidates, SourceMethod method,
|
||||
InheritInverseConfigurationPrism reversePrism) {
|
||||
|
||||
|
@ -48,7 +48,7 @@ public enum Message {
|
||||
PROPERTYMAPPING_EXPRESSION_AND_DEFAULT_VALUE_BOTH_DEFINED( "Expression and default value are both defined in @Mapping, either define a defaultValue or an expression." ),
|
||||
PROPERTYMAPPING_CONSTANT_AND_DEFAULT_VALUE_BOTH_DEFINED( "Constant and default value are both defined in @Mapping, either define a defaultValue or a constant." ),
|
||||
PROPERTYMAPPING_INVALID_EXPRESSION( "Value must be given in the form \"java(<EXPRESSION>)\"." ),
|
||||
PROPERTYMAPPING_REVERSAL_PROBLEM( "Parameter %s cannot be reversed." ),
|
||||
PROPERTYMAPPING_REVERSAL_PROBLEM( "Parameter %s cannot be reversed.", Diagnostic.Kind.NOTE ),
|
||||
PROPERTYMAPPING_INVALID_PARAMETER_NAME( "Method has no parameter named \"%s\"." ),
|
||||
PROPERTYMAPPING_NO_PROPERTY_IN_PARAMETER( "The type of parameter \"%s\" has no property named \"%s\"." ),
|
||||
PROPERTYMAPPING_INVALID_PROPERTY_NAME( "No property named \"%s\" exists in source parameter(s)." ),
|
||||
@ -102,6 +102,7 @@ public enum Message {
|
||||
INHERITINVERSECONFIGURATION_DUPLICATES( "Several matching inverse methods exist: %s(). Specify a name explicitly." ),
|
||||
INHERITINVERSECONFIGURATION_INVALID_NAME( "None of the candidates %s() matches given name: \"%s\"." ),
|
||||
INHERITINVERSECONFIGURATION_DUPLICATE_MATCHES( "Given name \"%s\" matches several candidate methods: %s." ),
|
||||
INHERITINVERSECONFIGURATION_NO_SUITABLE_CONSTRUCTOR( "There is no suitable result type constructor for reversing this method." ),
|
||||
INHERITINVERSECONFIGURATION_NO_NAME_MATCH( "Given name \"%s\" does not match the only candidate. Did you mean: \"%s\"." ),
|
||||
INHERITCONFIGURATION_DUPLICATES( "Several matching methods exist: %s(). Specify a name explicitly." ),
|
||||
INHERITCONFIGURATION_INVALIDNAME( "None of the candidates %s() matches given name: \"%s\"." ),
|
||||
|
@ -171,17 +171,17 @@ public class NestedSourcePropertiesTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IssueKey( "337" )
|
||||
@IssueKey( "838" )
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic( type = ArtistToChartEntryErroneous.class,
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
line = 47,
|
||||
messageRegExp = "Parameter java.lang.Integer position cannot be reversed" )
|
||||
line = 46,
|
||||
messageRegExp = "There is no suitable result type constructor for reversing this method\\." )
|
||||
}
|
||||
)
|
||||
@WithClasses({ ArtistToChartEntryErroneous.class })
|
||||
public void reverseShouldIgnoreParameter() {
|
||||
public void reverseShouldRaiseErrorForEmptyContructor() {
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user