mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#2439 Do not throw NPE getting accessors for null typeElement
Provide better error message if the source type has no read properties
This commit is contained in:
parent
934a47323a
commit
845d83e9d5
@ -10,6 +10,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.AnnotationValue;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
@ -277,10 +278,15 @@ public class SourceReference extends AbstractReference {
|
||||
notFoundPropertyIndex = entries.size();
|
||||
sourceType = last( entries ).getType();
|
||||
}
|
||||
|
||||
Set<String> readProperties = sourceType.getPropertyReadAccessors().keySet();
|
||||
|
||||
if ( !readProperties.isEmpty() ) {
|
||||
String mostSimilarWord = Strings.getMostSimilarWord(
|
||||
propertyNames[notFoundPropertyIndex],
|
||||
sourceType.getPropertyReadAccessors().keySet()
|
||||
readProperties
|
||||
);
|
||||
|
||||
List<String> elements = new ArrayList<>(
|
||||
Arrays.asList( propertyNames ).subList( 0, notFoundPropertyIndex )
|
||||
);
|
||||
@ -289,6 +295,14 @@ public class SourceReference extends AbstractReference {
|
||||
Message.PROPERTYMAPPING_INVALID_PROPERTY_NAME, sourceName, Strings.join( elements, "." )
|
||||
);
|
||||
}
|
||||
else {
|
||||
reportMappingError(
|
||||
Message.PROPERTYMAPPING_INVALID_PROPERTY_NAME_SOURCE_HAS_NO_PROPERTIES,
|
||||
sourceName,
|
||||
sourceType.describe()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<PropertyEntry> matchWithSourceAccessorTypes(Type type, String[] entryNames) {
|
||||
|
@ -14,6 +14,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -693,7 +694,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
|
||||
public List<Element> getRecordComponents() {
|
||||
if ( recordComponents == null ) {
|
||||
recordComponents = filters.recordComponentsIn( typeElement );
|
||||
recordComponents = nullSafeTypeElementListConversion( filters::recordComponentsIn );
|
||||
}
|
||||
|
||||
return recordComponents;
|
||||
@ -720,7 +721,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
|
||||
private List<ExecutableElement> getAllMethods() {
|
||||
if ( allMethods == null ) {
|
||||
allMethods = elementUtils.getAllEnclosedExecutableElements( typeElement );
|
||||
allMethods = nullSafeTypeElementListConversion( elementUtils::getAllEnclosedExecutableElements );
|
||||
}
|
||||
|
||||
return allMethods;
|
||||
@ -728,12 +729,20 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
|
||||
private List<VariableElement> getAllFields() {
|
||||
if ( allFields == null ) {
|
||||
allFields = elementUtils.getAllEnclosedFields( typeElement );
|
||||
allFields = nullSafeTypeElementListConversion( elementUtils::getAllEnclosedFields );
|
||||
}
|
||||
|
||||
return allFields;
|
||||
}
|
||||
|
||||
private <T> List<T> nullSafeTypeElementListConversion(Function<TypeElement, List<T>> conversionFunction) {
|
||||
if ( typeElement != null ) {
|
||||
return conversionFunction.apply( typeElement );
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private String getPropertyName(Accessor accessor ) {
|
||||
Element accessorElement = accessor.getElement();
|
||||
if ( accessorElement instanceof ExecutableElement ) {
|
||||
|
@ -70,6 +70,7 @@ public enum Message {
|
||||
PROPERTYMAPPING_INVALID_PARAMETER_NAME( "Method has no source parameter named \"%s\". Method source parameters are: \"%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). Did you mean \"%s\"?" ),
|
||||
PROPERTYMAPPING_INVALID_PROPERTY_NAME_SOURCE_HAS_NO_PROPERTIES( "No property named \"%s\" exists in source parameter(s). Type \"%s\" has no properties." ),
|
||||
PROPERTYMAPPING_NO_PRESENCE_CHECKER_FOR_SOURCE_TYPE( "Using custom source value presence checking strategy, but no presence checker found for %s in source type." ),
|
||||
PROPERTYMAPPING_NO_READ_ACCESSOR_FOR_TARGET_TYPE( "No read accessor found for property \"%s\" in target type." ),
|
||||
PROPERTYMAPPING_NO_WRITE_ACCESSOR_FOR_TARGET_TYPE( "No write accessor found for property \"%s\" in target type." ),
|
||||
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2439;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper
|
||||
public interface ErroneousIssue2439Mapper {
|
||||
|
||||
@Mapping(target = "modeName", source = "mode.desc")
|
||||
LiveDto map(LiveEntity entity);
|
||||
|
||||
class LiveEntity {
|
||||
private final LiveMode[] mode;
|
||||
|
||||
public LiveEntity(LiveMode... mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public LiveMode[] getMode() {
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
|
||||
class LiveDto {
|
||||
private String modeName;
|
||||
|
||||
public String getModeName() {
|
||||
return modeName;
|
||||
}
|
||||
|
||||
public void setModeName(String modeName) {
|
||||
this.modeName = modeName;
|
||||
}
|
||||
}
|
||||
|
||||
enum LiveMode {
|
||||
TEST,
|
||||
PROD,
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2439;
|
||||
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@IssueKey("2439")
|
||||
@WithClasses({
|
||||
ErroneousIssue2439Mapper.class
|
||||
})
|
||||
class Issuer2439Test {
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(type = ErroneousIssue2439Mapper.class,
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
line = 17,
|
||||
message = "No property named \"mode.desc\" exists in source parameter(s)." +
|
||||
" Type \"ErroneousIssue2439Mapper.LiveMode[]\" has no properties.")
|
||||
}
|
||||
)
|
||||
void shouldProvideGoodErrorMessage() {
|
||||
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user