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.accessor.Accessor;
|
||||
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.ReadAccessor;
|
||||
|
||||
@ -1067,7 +1067,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
existingVariableNames
|
||||
);
|
||||
existingVariableNames.add( safeParameterName );
|
||||
return new ParameterElementAccessor( element, accessedType, safeParameterName );
|
||||
return new ElementAccessor( element, accessedType, safeParameterName );
|
||||
}
|
||||
|
||||
private boolean hasDefaultAnnotationFromAnyPackage(Element element) {
|
||||
|
@ -12,7 +12,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
@ -23,7 +23,7 @@ import javax.lang.model.type.ExecutableType;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
|
||||
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 static org.mapstruct.ap.internal.util.Collections.first;
|
||||
@ -64,7 +64,7 @@ public class Filters {
|
||||
public List<ReadAccessor> getterMethodsIn(List<ExecutableElement> elements) {
|
||||
return elements.stream()
|
||||
.filter( accessorNaming::isGetterMethod )
|
||||
.map( method -> ReadAccessor.fromGetter( method, getReturnType( method ) ) )
|
||||
.map( method -> ReadAccessor.fromGetter( method, getReturnType( method ) ) )
|
||||
.collect( Collectors.toCollection( LinkedList::new ) );
|
||||
}
|
||||
|
||||
@ -90,7 +90,10 @@ public class Filters {
|
||||
for ( Element recordComponent : recordComponents ) {
|
||||
recordAccessors.put(
|
||||
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();
|
||||
}
|
||||
|
||||
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()
|
||||
.filter( Fields::isFieldAccessor )
|
||||
.map( creator )
|
||||
.map( variableElement -> creator.apply( variableElement, getWithinContext( variableElement ) ) )
|
||||
.collect( Collectors.toCollection( LinkedList::new ) );
|
||||
}
|
||||
|
||||
@ -117,7 +120,7 @@ public class Filters {
|
||||
public List<Accessor> setterMethodsIn(List<ExecutableElement> elements) {
|
||||
return elements.stream()
|
||||
.filter( accessorNaming::isSetterMethod )
|
||||
.map( method -> new ExecutableElementAccessor( method, getFirstParameter( method ), SETTER ) )
|
||||
.map( method -> new ElementAccessor( method, getFirstParameter( method ), SETTER ) )
|
||||
.collect( Collectors.toCollection( LinkedList::new ) );
|
||||
}
|
||||
|
||||
@ -129,10 +132,14 @@ public class Filters {
|
||||
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) {
|
||||
return elements.stream()
|
||||
.filter( accessorNaming::isAdderMethod )
|
||||
.map( method -> new ExecutableElementAccessor( method, getFirstParameter( method ), ADDER ) )
|
||||
.map( method -> new ElementAccessor( method, getFirstParameter( method ), ADDER ) )
|
||||
.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;
|
||||
|
||||
import java.util.Set;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
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 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 TypeMirror accessedType;
|
||||
|
||||
public ElementAccessor(VariableElement variableElement) {
|
||||
this( variableElement, AccessorType.FIELD );
|
||||
public ElementAccessor(VariableElement variableElement, TypeMirror accessedType) {
|
||||
this( variableElement, accessedType, AccessorType.FIELD );
|
||||
}
|
||||
|
||||
public ElementAccessor(Element element, AccessorType accessorType) {
|
||||
super( element );
|
||||
public ElementAccessor(Element element, TypeMirror accessedType, String name) {
|
||||
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.name = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
|
@ -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();
|
||||
|
||||
static ReadAccessor fromField(VariableElement variableElement) {
|
||||
return new ReadDelegateAccessor( new ElementAccessor( variableElement ) ) {
|
||||
static ReadAccessor fromField(VariableElement variableElement, TypeMirror accessedType) {
|
||||
return new ReadDelegateAccessor( new ElementAccessor( variableElement, accessedType ) ) {
|
||||
@Override
|
||||
public String getReadValueSource() {
|
||||
return getSimpleName();
|
||||
@ -26,8 +26,8 @@ public interface ReadAccessor extends Accessor {
|
||||
};
|
||||
}
|
||||
|
||||
static ReadAccessor fromRecordComponent(Element element) {
|
||||
return new ReadDelegateAccessor( new ElementAccessor( element, AccessorType.GETTER ) ) {
|
||||
static ReadAccessor fromRecordComponent(Element element, TypeMirror accessedType) {
|
||||
return new ReadDelegateAccessor( new ElementAccessor( element, accessedType, AccessorType.GETTER ) ) {
|
||||
@Override
|
||||
public String getReadValueSource() {
|
||||
return getSimpleName() + "()";
|
||||
@ -36,7 +36,7 @@ public interface ReadAccessor extends Accessor {
|
||||
}
|
||||
|
||||
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
|
||||
public String getReadValueSource() {
|
||||
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