mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#3807: Properly recognize the type of public generic fields
Signed-off-by: TangYang <tangyang9464@163.com>
This commit is contained in:
parent
8fc97f5f62
commit
bff88297e3
@ -65,7 +65,7 @@ import org.mapstruct.ap.internal.util.Message;
|
|||||||
import org.mapstruct.ap.internal.util.Strings;
|
import org.mapstruct.ap.internal.util.Strings;
|
||||||
import org.mapstruct.ap.internal.util.accessor.Accessor;
|
import org.mapstruct.ap.internal.util.accessor.Accessor;
|
||||||
import org.mapstruct.ap.internal.util.accessor.AccessorType;
|
import org.mapstruct.ap.internal.util.accessor.AccessorType;
|
||||||
import org.mapstruct.ap.internal.util.accessor.ParameterElementAccessor;
|
import org.mapstruct.ap.internal.util.accessor.ElementAccessor;
|
||||||
import org.mapstruct.ap.internal.util.accessor.PresenceCheckAccessor;
|
import org.mapstruct.ap.internal.util.accessor.PresenceCheckAccessor;
|
||||||
import org.mapstruct.ap.internal.util.accessor.ReadAccessor;
|
import org.mapstruct.ap.internal.util.accessor.ReadAccessor;
|
||||||
|
|
||||||
@ -1067,7 +1067,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
|||||||
existingVariableNames
|
existingVariableNames
|
||||||
);
|
);
|
||||||
existingVariableNames.add( safeParameterName );
|
existingVariableNames.add( safeParameterName );
|
||||||
return new ParameterElementAccessor( element, accessedType, safeParameterName );
|
return new ElementAccessor( element, accessedType, safeParameterName );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasDefaultAnnotationFromAnyPackage(Element element) {
|
private boolean hasDefaultAnnotationFromAnyPackage(Element element) {
|
||||||
|
@ -12,7 +12,7 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.BiFunction;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
@ -23,7 +23,7 @@ import javax.lang.model.type.ExecutableType;
|
|||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
|
||||||
import org.mapstruct.ap.internal.util.accessor.Accessor;
|
import org.mapstruct.ap.internal.util.accessor.Accessor;
|
||||||
import org.mapstruct.ap.internal.util.accessor.ExecutableElementAccessor;
|
import org.mapstruct.ap.internal.util.accessor.ElementAccessor;
|
||||||
import org.mapstruct.ap.internal.util.accessor.ReadAccessor;
|
import org.mapstruct.ap.internal.util.accessor.ReadAccessor;
|
||||||
|
|
||||||
import static org.mapstruct.ap.internal.util.Collections.first;
|
import static org.mapstruct.ap.internal.util.Collections.first;
|
||||||
@ -64,7 +64,7 @@ public class Filters {
|
|||||||
public List<ReadAccessor> getterMethodsIn(List<ExecutableElement> elements) {
|
public List<ReadAccessor> getterMethodsIn(List<ExecutableElement> elements) {
|
||||||
return elements.stream()
|
return elements.stream()
|
||||||
.filter( accessorNaming::isGetterMethod )
|
.filter( accessorNaming::isGetterMethod )
|
||||||
.map( method -> ReadAccessor.fromGetter( method, getReturnType( method ) ) )
|
.map( method -> ReadAccessor.fromGetter( method, getReturnType( method ) ) )
|
||||||
.collect( Collectors.toCollection( LinkedList::new ) );
|
.collect( Collectors.toCollection( LinkedList::new ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +90,10 @@ public class Filters {
|
|||||||
for ( Element recordComponent : recordComponents ) {
|
for ( Element recordComponent : recordComponents ) {
|
||||||
recordAccessors.put(
|
recordAccessors.put(
|
||||||
recordComponent.getSimpleName().toString(),
|
recordComponent.getSimpleName().toString(),
|
||||||
ReadAccessor.fromRecordComponent( recordComponent )
|
ReadAccessor.fromRecordComponent(
|
||||||
|
recordComponent,
|
||||||
|
typeUtils.asMemberOf( (DeclaredType) typeMirror, recordComponent )
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,10 +104,10 @@ public class Filters {
|
|||||||
return getWithinContext( executableElement ).getReturnType();
|
return getWithinContext( executableElement ).getReturnType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> List<T> fieldsIn(List<VariableElement> accessors, Function<VariableElement, T> creator) {
|
public <T> List<T> fieldsIn(List<VariableElement> accessors, BiFunction<VariableElement, TypeMirror, T> creator) {
|
||||||
return accessors.stream()
|
return accessors.stream()
|
||||||
.filter( Fields::isFieldAccessor )
|
.filter( Fields::isFieldAccessor )
|
||||||
.map( creator )
|
.map( variableElement -> creator.apply( variableElement, getWithinContext( variableElement ) ) )
|
||||||
.collect( Collectors.toCollection( LinkedList::new ) );
|
.collect( Collectors.toCollection( LinkedList::new ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +120,7 @@ public class Filters {
|
|||||||
public List<Accessor> setterMethodsIn(List<ExecutableElement> elements) {
|
public List<Accessor> setterMethodsIn(List<ExecutableElement> elements) {
|
||||||
return elements.stream()
|
return elements.stream()
|
||||||
.filter( accessorNaming::isSetterMethod )
|
.filter( accessorNaming::isSetterMethod )
|
||||||
.map( method -> new ExecutableElementAccessor( method, getFirstParameter( method ), SETTER ) )
|
.map( method -> new ElementAccessor( method, getFirstParameter( method ), SETTER ) )
|
||||||
.collect( Collectors.toCollection( LinkedList::new ) );
|
.collect( Collectors.toCollection( LinkedList::new ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,10 +132,14 @@ public class Filters {
|
|||||||
return (ExecutableType) typeUtils.asMemberOf( (DeclaredType) typeMirror, executableElement );
|
return (ExecutableType) typeUtils.asMemberOf( (DeclaredType) typeMirror, executableElement );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TypeMirror getWithinContext( VariableElement variableElement ) {
|
||||||
|
return typeUtils.asMemberOf( (DeclaredType) typeMirror, variableElement );
|
||||||
|
}
|
||||||
|
|
||||||
public List<Accessor> adderMethodsIn(List<ExecutableElement> elements) {
|
public List<Accessor> adderMethodsIn(List<ExecutableElement> elements) {
|
||||||
return elements.stream()
|
return elements.stream()
|
||||||
.filter( accessorNaming::isAdderMethod )
|
.filter( accessorNaming::isAdderMethod )
|
||||||
.map( method -> new ExecutableElementAccessor( method, getFirstParameter( method ), ADDER ) )
|
.map( method -> new ElementAccessor( method, getFirstParameter( method ), ADDER ) )
|
||||||
.collect( Collectors.toCollection( LinkedList::new ) );
|
.collect( Collectors.toCollection( LinkedList::new ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.internal.util.accessor;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.lang.model.element.Element;
|
|
||||||
import javax.lang.model.element.Modifier;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an abstract implementation of an {@link Accessor} that provides the common implementation.
|
|
||||||
*
|
|
||||||
* @author Filip Hrisafov
|
|
||||||
*/
|
|
||||||
abstract class AbstractAccessor<T extends Element> implements Accessor {
|
|
||||||
|
|
||||||
protected final T element;
|
|
||||||
|
|
||||||
AbstractAccessor(T element) {
|
|
||||||
this.element = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSimpleName() {
|
|
||||||
return element.getSimpleName().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<Modifier> getModifiers() {
|
|
||||||
return element.getModifiers();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T getElement() {
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -5,31 +5,61 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.util.accessor;
|
package org.mapstruct.ap.internal.util.accessor;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.Modifier;
|
||||||
import javax.lang.model.element.VariableElement;
|
import javax.lang.model.element.VariableElement;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link Accessor} that wraps a {@link VariableElement}.
|
* An {@link Accessor} that wraps a {@link Element}.
|
||||||
*
|
* Used for getter, setter, filed, constructor, record-class, etc.
|
||||||
* @author Filip Hrisafov
|
* @author Filip Hrisafov
|
||||||
|
* @author Tang Yang
|
||||||
*/
|
*/
|
||||||
public class ElementAccessor extends AbstractAccessor<Element> {
|
public class ElementAccessor implements Accessor {
|
||||||
|
|
||||||
|
private final Element element;
|
||||||
|
private final String name;
|
||||||
private final AccessorType accessorType;
|
private final AccessorType accessorType;
|
||||||
|
private final TypeMirror accessedType;
|
||||||
|
|
||||||
public ElementAccessor(VariableElement variableElement) {
|
public ElementAccessor(VariableElement variableElement, TypeMirror accessedType) {
|
||||||
this( variableElement, AccessorType.FIELD );
|
this( variableElement, accessedType, AccessorType.FIELD );
|
||||||
}
|
}
|
||||||
|
|
||||||
public ElementAccessor(Element element, AccessorType accessorType) {
|
public ElementAccessor(Element element, TypeMirror accessedType, String name) {
|
||||||
super( element );
|
this.element = element;
|
||||||
|
this.name = name;
|
||||||
|
this.accessedType = accessedType;
|
||||||
|
this.accessorType = AccessorType.PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ElementAccessor(Element element, TypeMirror accessedType, AccessorType accessorType) {
|
||||||
|
this.element = element;
|
||||||
|
this.accessedType = accessedType;
|
||||||
this.accessorType = accessorType;
|
this.accessorType = accessorType;
|
||||||
|
this.name = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypeMirror getAccessedType() {
|
public TypeMirror getAccessedType() {
|
||||||
return element.asType();
|
return accessedType != null ? accessedType : element.asType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSimpleName() {
|
||||||
|
return name != null ? name : element.getSimpleName().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Modifier> getModifiers() {
|
||||||
|
return element.getModifiers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Element getElement() {
|
||||||
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.internal.util.accessor;
|
|
||||||
|
|
||||||
import javax.lang.model.element.ExecutableElement;
|
|
||||||
import javax.lang.model.type.TypeMirror;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An {@link Accessor} that wraps an {@link ExecutableElement}.
|
|
||||||
*
|
|
||||||
* @author Filip Hrisafov
|
|
||||||
*/
|
|
||||||
public class ExecutableElementAccessor extends AbstractAccessor<ExecutableElement> {
|
|
||||||
|
|
||||||
private final TypeMirror accessedType;
|
|
||||||
private final AccessorType accessorType;
|
|
||||||
|
|
||||||
public ExecutableElementAccessor(ExecutableElement element, TypeMirror accessedType, AccessorType accessorType) {
|
|
||||||
super( element );
|
|
||||||
this.accessedType = accessedType;
|
|
||||||
this.accessorType = accessorType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeMirror getAccessedType() {
|
|
||||||
return accessedType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return element.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessorType getAccessorType() {
|
|
||||||
return accessorType;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.internal.util.accessor;
|
|
||||||
|
|
||||||
import javax.lang.model.element.Element;
|
|
||||||
import javax.lang.model.element.VariableElement;
|
|
||||||
import javax.lang.model.type.TypeMirror;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An {@link Accessor} that wraps a {@link VariableElement}.
|
|
||||||
*
|
|
||||||
* @author Filip Hrisafov
|
|
||||||
*/
|
|
||||||
public class ParameterElementAccessor extends AbstractAccessor<Element> {
|
|
||||||
|
|
||||||
protected final String name;
|
|
||||||
protected final TypeMirror accessedType;
|
|
||||||
|
|
||||||
public ParameterElementAccessor(Element element, TypeMirror accessedType, String name) {
|
|
||||||
super( element );
|
|
||||||
this.name = name;
|
|
||||||
this.accessedType = accessedType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSimpleName() {
|
|
||||||
return name != null ? name : super.getSimpleName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeMirror getAccessedType() {
|
|
||||||
return accessedType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return element.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessorType getAccessorType() {
|
|
||||||
return AccessorType.PARAMETER;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -17,8 +17,8 @@ public interface ReadAccessor extends Accessor {
|
|||||||
|
|
||||||
String getReadValueSource();
|
String getReadValueSource();
|
||||||
|
|
||||||
static ReadAccessor fromField(VariableElement variableElement) {
|
static ReadAccessor fromField(VariableElement variableElement, TypeMirror accessedType) {
|
||||||
return new ReadDelegateAccessor( new ElementAccessor( variableElement ) ) {
|
return new ReadDelegateAccessor( new ElementAccessor( variableElement, accessedType ) ) {
|
||||||
@Override
|
@Override
|
||||||
public String getReadValueSource() {
|
public String getReadValueSource() {
|
||||||
return getSimpleName();
|
return getSimpleName();
|
||||||
@ -26,8 +26,8 @@ public interface ReadAccessor extends Accessor {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static ReadAccessor fromRecordComponent(Element element) {
|
static ReadAccessor fromRecordComponent(Element element, TypeMirror accessedType) {
|
||||||
return new ReadDelegateAccessor( new ElementAccessor( element, AccessorType.GETTER ) ) {
|
return new ReadDelegateAccessor( new ElementAccessor( element, accessedType, AccessorType.GETTER ) ) {
|
||||||
@Override
|
@Override
|
||||||
public String getReadValueSource() {
|
public String getReadValueSource() {
|
||||||
return getSimpleName() + "()";
|
return getSimpleName() + "()";
|
||||||
@ -36,7 +36,7 @@ public interface ReadAccessor extends Accessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ReadAccessor fromGetter(ExecutableElement element, TypeMirror accessedType) {
|
static ReadAccessor fromGetter(ExecutableElement element, TypeMirror accessedType) {
|
||||||
return new ReadDelegateAccessor( new ExecutableElementAccessor( element, accessedType, AccessorType.GETTER ) ) {
|
return new ReadDelegateAccessor( new ElementAccessor( element, accessedType, AccessorType.GETTER ) ) {
|
||||||
@Override
|
@Override
|
||||||
public String getReadValueSource() {
|
public String getReadValueSource() {
|
||||||
return getSimpleName() + "()";
|
return getSimpleName() + "()";
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.internal.util.accessor;
|
|
||||||
|
|
||||||
import javax.lang.model.element.Element;
|
|
||||||
import javax.lang.model.element.VariableElement;
|
|
||||||
import javax.lang.model.type.TypeMirror;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An {@link Accessor} that wraps a {@link VariableElement}.
|
|
||||||
*
|
|
||||||
* @author Filip Hrisafov
|
|
||||||
*/
|
|
||||||
public class RecordElementAccessor extends AbstractAccessor<Element> {
|
|
||||||
|
|
||||||
public RecordElementAccessor(Element element) {
|
|
||||||
super( element );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeMirror getAccessedType() {
|
|
||||||
return element.asType();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return element.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessorType getAccessorType() {
|
|
||||||
return AccessorType.GETTER;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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._3807;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface Issue3807Mapper {
|
||||||
|
Issue3807Mapper INSTANCE = Mappers.getMapper( Issue3807Mapper.class );
|
||||||
|
|
||||||
|
TargetWithoutSetter<String> mapNoSetter(Source target);
|
||||||
|
|
||||||
|
NormalTarget<String> mapNormalSource(Source target);
|
||||||
|
|
||||||
|
class Source {
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
public Source(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//CHECKSTYLE:OFF
|
||||||
|
class TargetWithoutSetter<T> {
|
||||||
|
public T value;
|
||||||
|
}
|
||||||
|
//CHECKSTYLE:ON
|
||||||
|
|
||||||
|
class NormalTarget<T> {
|
||||||
|
private T value;
|
||||||
|
|
||||||
|
public T getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(T value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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._3807;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
|
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||||
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@WithClasses(Issue3807Mapper.class)
|
||||||
|
@IssueKey("3087")
|
||||||
|
class Issue3807Test {
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
void fieldAndSetterShouldWorkWithGeneric() {
|
||||||
|
Issue3807Mapper.Source source = new Issue3807Mapper.Source( "value" );
|
||||||
|
Issue3807Mapper.TargetWithoutSetter<String> targetWithoutSetter =
|
||||||
|
Issue3807Mapper.INSTANCE.mapNoSetter( source );
|
||||||
|
|
||||||
|
assertThat( targetWithoutSetter ).isNotNull();
|
||||||
|
assertThat( targetWithoutSetter.value ).isEqualTo( "value" );
|
||||||
|
|
||||||
|
Issue3807Mapper.NormalTarget<String> normalTarget = Issue3807Mapper.INSTANCE.mapNormalSource( source );
|
||||||
|
|
||||||
|
assertThat( normalTarget ).isNotNull();
|
||||||
|
assertThat( normalTarget.getValue() ).isEqualTo( "value" );
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user