mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#3591 Fix duplicate method generation with recursive auto mapping
This commit is contained in:
parent
df49ce5ff9
commit
3047760fd0
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.model;
|
package org.mapstruct.ap.internal.model;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
import javax.lang.model.element.AnnotationMirror;
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
|
|
||||||
import org.mapstruct.ap.internal.model.common.Assignment;
|
import org.mapstruct.ap.internal.model.common.Assignment;
|
||||||
@ -74,16 +75,9 @@ class AbstractBaseBuilder<B extends AbstractBaseBuilder<B>> {
|
|||||||
*/
|
*/
|
||||||
Assignment createForgedAssignment(SourceRHS sourceRHS, BuilderType builderType, ForgedMethod forgedMethod) {
|
Assignment createForgedAssignment(SourceRHS sourceRHS, BuilderType builderType, ForgedMethod forgedMethod) {
|
||||||
|
|
||||||
if ( ctx.getForgedMethodsUnderCreation().containsKey( forgedMethod ) ) {
|
Supplier<MappingMethod> forgedMappingMethodCreator;
|
||||||
return createAssignment( sourceRHS, ctx.getForgedMethodsUnderCreation().get( forgedMethod ) );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ctx.getForgedMethodsUnderCreation().put( forgedMethod, forgedMethod );
|
|
||||||
}
|
|
||||||
|
|
||||||
MappingMethod forgedMappingMethod;
|
|
||||||
if ( MappingMethodUtils.isEnumMapping( forgedMethod ) ) {
|
if ( MappingMethodUtils.isEnumMapping( forgedMethod ) ) {
|
||||||
forgedMappingMethod = new ValueMappingMethod.Builder()
|
forgedMappingMethodCreator = () -> new ValueMappingMethod.Builder()
|
||||||
.method( forgedMethod )
|
.method( forgedMethod )
|
||||||
.valueMappings( forgedMethod.getOptions().getValueMappings() )
|
.valueMappings( forgedMethod.getOptions().getValueMappings() )
|
||||||
.enumMapping( forgedMethod.getOptions().getEnumMappingOptions() )
|
.enumMapping( forgedMethod.getOptions().getEnumMappingOptions() )
|
||||||
@ -91,15 +85,31 @@ class AbstractBaseBuilder<B extends AbstractBaseBuilder<B>> {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
forgedMappingMethod = new BeanMappingMethod.Builder()
|
forgedMappingMethodCreator = () -> new BeanMappingMethod.Builder()
|
||||||
.forgedMethod( forgedMethod )
|
.forgedMethod( forgedMethod )
|
||||||
.returnTypeBuilder( builderType )
|
.returnTypeBuilder( builderType )
|
||||||
.mappingContext( ctx )
|
.mappingContext( ctx )
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return getOrCreateForgedAssignment( sourceRHS, forgedMethod, forgedMappingMethodCreator );
|
||||||
|
}
|
||||||
|
|
||||||
|
Assignment getOrCreateForgedAssignment(SourceRHS sourceRHS, ForgedMethod forgedMethod,
|
||||||
|
Supplier<MappingMethod> mappingMethodCreator) {
|
||||||
|
|
||||||
|
if ( ctx.getForgedMethodsUnderCreation().containsKey( forgedMethod ) ) {
|
||||||
|
return createAssignment( sourceRHS, ctx.getForgedMethodsUnderCreation().get( forgedMethod ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ctx.getForgedMethodsUnderCreation().put( forgedMethod, forgedMethod );
|
||||||
|
}
|
||||||
|
|
||||||
|
MappingMethod forgedMappingMethod = mappingMethodCreator.get();
|
||||||
|
|
||||||
Assignment forgedAssignment = createForgedAssignment( sourceRHS, forgedMethod, forgedMappingMethod );
|
Assignment forgedAssignment = createForgedAssignment( sourceRHS, forgedMethod, forgedMappingMethod );
|
||||||
ctx.getForgedMethodsUnderCreation().remove( forgedMethod );
|
ctx.getForgedMethodsUnderCreation().remove( forgedMethod );
|
||||||
|
|
||||||
return forgedAssignment;
|
return forgedAssignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,8 @@ public abstract class ContainerMappingMethod extends NormalTypeMappingMethod {
|
|||||||
afterMappingReferences );
|
afterMappingReferences );
|
||||||
this.elementAssignment = parameterAssignment;
|
this.elementAssignment = parameterAssignment;
|
||||||
this.loopVariableName = loopVariableName;
|
this.loopVariableName = loopVariableName;
|
||||||
this.selectionParameters = selectionParameters;
|
this.selectionParameters = selectionParameters != null ? selectionParameters : SelectionParameters.empty();
|
||||||
|
|
||||||
this.index1Name = Strings.getSafeVariableName( "i", existingVariables );
|
this.index1Name = Strings.getSafeVariableName( "i", existingVariables );
|
||||||
this.index2Name = Strings.getSafeVariableName( "j", existingVariables );
|
this.index2Name = Strings.getSafeVariableName( "j", existingVariables );
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import javax.lang.model.element.AnnotationMirror;
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
|
|
||||||
import org.mapstruct.ap.internal.gem.BuilderGem;
|
import org.mapstruct.ap.internal.gem.BuilderGem;
|
||||||
@ -746,7 +747,7 @@ public class PropertyMapping extends ModelElement {
|
|||||||
targetType = targetType.withoutBounds();
|
targetType = targetType.withoutBounds();
|
||||||
ForgedMethod methodRef = prepareForgedMethod( sourceType, targetType, source, "[]" );
|
ForgedMethod methodRef = prepareForgedMethod( sourceType, targetType, source, "[]" );
|
||||||
|
|
||||||
ContainerMappingMethod iterableMappingMethod = builder
|
Supplier<MappingMethod> mappingMethodCreator = () -> builder
|
||||||
.mappingContext( ctx )
|
.mappingContext( ctx )
|
||||||
.method( methodRef )
|
.method( methodRef )
|
||||||
.selectionParameters( selectionParameters )
|
.selectionParameters( selectionParameters )
|
||||||
@ -754,7 +755,7 @@ public class PropertyMapping extends ModelElement {
|
|||||||
.positionHint( positionHint )
|
.positionHint( positionHint )
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
return createForgedAssignment( source, methodRef, iterableMappingMethod );
|
return getOrCreateForgedAssignment( source, methodRef, mappingMethodCreator );
|
||||||
}
|
}
|
||||||
|
|
||||||
private ForgedMethod prepareForgedMethod(Type sourceType, Type targetType, SourceRHS source, String suffix) {
|
private ForgedMethod prepareForgedMethod(Type sourceType, Type targetType, SourceRHS source, String suffix) {
|
||||||
@ -772,12 +773,12 @@ public class PropertyMapping extends ModelElement {
|
|||||||
ForgedMethod methodRef = prepareForgedMethod( sourceType, targetType, source, "{}" );
|
ForgedMethod methodRef = prepareForgedMethod( sourceType, targetType, source, "{}" );
|
||||||
|
|
||||||
MapMappingMethod.Builder builder = new MapMappingMethod.Builder();
|
MapMappingMethod.Builder builder = new MapMappingMethod.Builder();
|
||||||
MapMappingMethod mapMappingMethod = builder
|
Supplier<MappingMethod> mapMappingMethodCreator = () -> builder
|
||||||
.mappingContext( ctx )
|
.mappingContext( ctx )
|
||||||
.method( methodRef )
|
.method( methodRef )
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
return createForgedAssignment( source, methodRef, mapMappingMethod );
|
return getOrCreateForgedAssignment( source, methodRef, mapMappingMethodCreator );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Assignment forgeMapping(SourceRHS sourceRHS) {
|
private Assignment forgeMapping(SourceRHS sourceRHS) {
|
||||||
|
@ -58,7 +58,7 @@ public class BeanMappingOptions extends DelegatingOptions {
|
|||||||
public static BeanMappingOptions forForgedMethods(BeanMappingOptions beanMapping) {
|
public static BeanMappingOptions forForgedMethods(BeanMappingOptions beanMapping) {
|
||||||
BeanMappingOptions options = new BeanMappingOptions(
|
BeanMappingOptions options = new BeanMappingOptions(
|
||||||
beanMapping.selectionParameters != null ?
|
beanMapping.selectionParameters != null ?
|
||||||
SelectionParameters.withoutResultType( beanMapping.selectionParameters ) : null,
|
SelectionParameters.withoutResultType( beanMapping.selectionParameters ) : SelectionParameters.empty(),
|
||||||
Collections.emptyList(),
|
Collections.emptyList(),
|
||||||
beanMapping.beanMapping,
|
beanMapping.beanMapping,
|
||||||
beanMapping
|
beanMapping
|
||||||
@ -78,7 +78,7 @@ public class BeanMappingOptions extends DelegatingOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static BeanMappingOptions empty(DelegatingOptions delegatingOptions) {
|
public static BeanMappingOptions empty(DelegatingOptions delegatingOptions) {
|
||||||
return new BeanMappingOptions( null, Collections.emptyList(), null, delegatingOptions );
|
return new BeanMappingOptions( SelectionParameters.empty(), Collections.emptyList(), null, delegatingOptions );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BeanMappingOptions getInstanceOn(BeanMappingGem beanMapping, MapperOptions mapperOptions,
|
public static BeanMappingOptions getInstanceOn(BeanMappingGem beanMapping, MapperOptions mapperOptions,
|
||||||
|
@ -8,14 +8,14 @@ package org.mapstruct.ap.internal.model.source;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.lang.model.element.AnnotationMirror;
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import org.mapstruct.ap.internal.util.ElementUtils;
|
|
||||||
import org.mapstruct.ap.internal.util.TypeUtils;
|
|
||||||
|
|
||||||
import org.mapstruct.ap.internal.model.common.FormattingParameters;
|
|
||||||
import org.mapstruct.ap.internal.gem.IterableMappingGem;
|
import org.mapstruct.ap.internal.gem.IterableMappingGem;
|
||||||
import org.mapstruct.ap.internal.gem.NullValueMappingStrategyGem;
|
import org.mapstruct.ap.internal.gem.NullValueMappingStrategyGem;
|
||||||
|
import org.mapstruct.ap.internal.model.common.FormattingParameters;
|
||||||
|
import org.mapstruct.ap.internal.util.ElementUtils;
|
||||||
import org.mapstruct.ap.internal.util.FormattingMessager;
|
import org.mapstruct.ap.internal.util.FormattingMessager;
|
||||||
import org.mapstruct.ap.internal.util.Message;
|
import org.mapstruct.ap.internal.util.Message;
|
||||||
|
import org.mapstruct.ap.internal.util.TypeUtils;
|
||||||
import org.mapstruct.tools.gem.GemValue;
|
import org.mapstruct.tools.gem.GemValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,7 +34,12 @@ public class IterableMappingOptions extends DelegatingOptions {
|
|||||||
FormattingMessager messager, TypeUtils typeUtils) {
|
FormattingMessager messager, TypeUtils typeUtils) {
|
||||||
|
|
||||||
if ( iterableMapping == null || !isConsistent( iterableMapping, method, messager ) ) {
|
if ( iterableMapping == null || !isConsistent( iterableMapping, method, messager ) ) {
|
||||||
IterableMappingOptions options = new IterableMappingOptions( null, null, null, mapperOptions );
|
IterableMappingOptions options = new IterableMappingOptions(
|
||||||
|
null,
|
||||||
|
SelectionParameters.empty(),
|
||||||
|
null,
|
||||||
|
mapperOptions
|
||||||
|
);
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,9 +38,9 @@ public class MapMappingOptions extends DelegatingOptions {
|
|||||||
if ( mapMapping == null || !isConsistent( mapMapping, method, messager ) ) {
|
if ( mapMapping == null || !isConsistent( mapMapping, method, messager ) ) {
|
||||||
MapMappingOptions options = new MapMappingOptions(
|
MapMappingOptions options = new MapMappingOptions(
|
||||||
null,
|
null,
|
||||||
|
SelectionParameters.empty(),
|
||||||
null,
|
null,
|
||||||
null,
|
SelectionParameters.empty(),
|
||||||
null,
|
|
||||||
null,
|
null,
|
||||||
mapperOptions
|
mapperOptions
|
||||||
);
|
);
|
||||||
|
@ -182,7 +182,7 @@ public class MappingOptions extends DelegatingOptions {
|
|||||||
null,
|
null,
|
||||||
true,
|
true,
|
||||||
null,
|
null,
|
||||||
null,
|
SelectionParameters.empty(),
|
||||||
Collections.emptySet(),
|
Collections.emptySet(),
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
@ -21,6 +21,16 @@ import org.mapstruct.ap.internal.model.common.SourceRHS;
|
|||||||
*/
|
*/
|
||||||
public class SelectionParameters {
|
public class SelectionParameters {
|
||||||
|
|
||||||
|
private static final SelectionParameters EMPTY = new SelectionParameters(
|
||||||
|
Collections.emptyList(),
|
||||||
|
Collections.emptyList(),
|
||||||
|
Collections.emptyList(),
|
||||||
|
Collections.emptyList(),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
private final List<TypeMirror> qualifiers;
|
private final List<TypeMirror> qualifiers;
|
||||||
private final List<String> qualifyingNames;
|
private final List<String> qualifyingNames;
|
||||||
private final List<TypeMirror> conditionQualifiers;
|
private final List<TypeMirror> conditionQualifiers;
|
||||||
@ -225,4 +235,9 @@ public class SelectionParameters {
|
|||||||
sourceRHS
|
sourceRHS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SelectionParameters empty() {
|
||||||
|
return EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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._3591;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Bean {
|
||||||
|
private List<Bean> beans;
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
public Bean() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bean(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Bean> getBeans() {
|
||||||
|
return beans;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBeans(List<Bean> beans) {
|
||||||
|
this.beans = beans;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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._3591;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class BeanDto {
|
||||||
|
|
||||||
|
private List<BeanDto> beans;
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BeanDto> getBeans() {
|
||||||
|
return beans;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBeans(List<BeanDto> beans) {
|
||||||
|
this.beans = beans;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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._3591;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.MappingTarget;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface BeanMapper {
|
||||||
|
|
||||||
|
BeanMapper INSTANCE = Mappers.getMapper( BeanMapper.class );
|
||||||
|
|
||||||
|
@Mapping(source = "beans", target = "beans")
|
||||||
|
BeanDto map(Bean bean, @MappingTarget BeanDto beanDto);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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._3591;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class ContainerBean {
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
private Map<String, ContainerBean> beanMap;
|
||||||
|
private Stream<ContainerBean> beanStream;
|
||||||
|
|
||||||
|
public ContainerBean() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContainerBean(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, ContainerBean> getBeanMap() {
|
||||||
|
return beanMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBeanMap(Map<String, ContainerBean> beanMap) {
|
||||||
|
this.beanMap = beanMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream<ContainerBean> getBeanStream() {
|
||||||
|
return beanStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBeanStream(Stream<ContainerBean> beanStream) {
|
||||||
|
this.beanStream = beanStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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._3591;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class ContainerBeanDto {
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
private Map<String, ContainerBeanDto> beanMap;
|
||||||
|
private Stream<ContainerBeanDto> beanStream;
|
||||||
|
|
||||||
|
public Map<String, ContainerBeanDto> getBeanMap() {
|
||||||
|
return beanMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBeanMap(Map<String, ContainerBeanDto> beanMap) {
|
||||||
|
this.beanMap = beanMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream<ContainerBeanDto> getBeanStream() {
|
||||||
|
return beanStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBeanStream(Stream<ContainerBeanDto> beanStream) {
|
||||||
|
this.beanStream = beanStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* 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._3591;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.MappingTarget;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ContainerBeanMapper {
|
||||||
|
|
||||||
|
ContainerBeanMapper INSTANCE = Mappers.getMapper( ContainerBeanMapper.class );
|
||||||
|
|
||||||
|
@Mapping(source = "beanMap", target = "beanMap")
|
||||||
|
@Mapping(source = "beanStream", target = "beanStream")
|
||||||
|
ContainerBeanDto mapWithMapMapping(ContainerBean containerBean, @MappingTarget ContainerBeanDto containerBeanDto);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* 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._3591;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
|
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||||
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
import org.mapstruct.ap.testutil.runner.GeneratedSource;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@IssueKey("3591")
|
||||||
|
class Issue3591Test {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
GeneratedSource generatedSource = new GeneratedSource();
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
@WithClasses({
|
||||||
|
BeanDto.class,
|
||||||
|
Bean.class,
|
||||||
|
BeanMapper.class
|
||||||
|
})
|
||||||
|
void mapNestedBeansWithMappingAnnotation() {
|
||||||
|
Bean bean = new Bean( "parent" );
|
||||||
|
Bean child = new Bean( "child" );
|
||||||
|
bean.setBeans( Collections.singletonList( child ) );
|
||||||
|
|
||||||
|
BeanDto beanDto = BeanMapper.INSTANCE.map( bean, new BeanDto() );
|
||||||
|
|
||||||
|
assertThat( beanDto ).isNotNull();
|
||||||
|
assertThat( beanDto.getValue() ).isEqualTo( "parent" );
|
||||||
|
assertThat( beanDto.getBeans() )
|
||||||
|
.extracting( BeanDto::getValue )
|
||||||
|
.containsExactly( "child" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
@WithClasses({
|
||||||
|
ContainerBean.class,
|
||||||
|
ContainerBeanDto.class,
|
||||||
|
ContainerBeanMapper.class,
|
||||||
|
})
|
||||||
|
void shouldMapNestedMapAndStream() {
|
||||||
|
generatedSource.addComparisonToFixtureFor( ContainerBeanMapper.class );
|
||||||
|
|
||||||
|
ContainerBean containerBean = new ContainerBean( "parent" );
|
||||||
|
Map<String, ContainerBean> beanMap = new HashMap<>();
|
||||||
|
beanMap.put( "child", new ContainerBean( "mapChild" ) );
|
||||||
|
containerBean.setBeanMap( beanMap );
|
||||||
|
|
||||||
|
Stream<ContainerBean> streamChild = Stream.of( new ContainerBean( "streamChild" ) );
|
||||||
|
containerBean.setBeanStream( streamChild );
|
||||||
|
|
||||||
|
ContainerBeanDto dto = ContainerBeanMapper.INSTANCE.mapWithMapMapping( containerBean, new ContainerBeanDto() );
|
||||||
|
|
||||||
|
assertThat( dto ).isNotNull();
|
||||||
|
|
||||||
|
assertThat( dto.getBeanMap() )
|
||||||
|
.extractingByKey( "child" )
|
||||||
|
.extracting( ContainerBeanDto::getValue )
|
||||||
|
.isEqualTo( "mapChild" );
|
||||||
|
|
||||||
|
assertThat( dto.getBeanStream() )
|
||||||
|
.singleElement()
|
||||||
|
.extracting( ContainerBeanDto::getValue )
|
||||||
|
.isEqualTo( "streamChild" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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._3591;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import javax.annotation.processing.Generated;
|
||||||
|
|
||||||
|
@Generated(
|
||||||
|
value = "org.mapstruct.ap.MappingProcessor",
|
||||||
|
date = "2024-05-25T14:23:23+0200",
|
||||||
|
comments = "version: , compiler: javac, environment: Java 17.0.11 (N/A)"
|
||||||
|
)
|
||||||
|
public class ContainerBeanMapperImpl implements ContainerBeanMapper {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ContainerBeanDto mapWithMapMapping(ContainerBean containerBean, ContainerBeanDto containerBeanDto) {
|
||||||
|
if ( containerBean == null ) {
|
||||||
|
return containerBeanDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( containerBeanDto.getBeanMap() != null ) {
|
||||||
|
Map<String, ContainerBeanDto> map = stringContainerBeanMapToStringContainerBeanDtoMap( containerBean.getBeanMap() );
|
||||||
|
if ( map != null ) {
|
||||||
|
containerBeanDto.getBeanMap().clear();
|
||||||
|
containerBeanDto.getBeanMap().putAll( map );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
containerBeanDto.setBeanMap( null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Map<String, ContainerBeanDto> map = stringContainerBeanMapToStringContainerBeanDtoMap( containerBean.getBeanMap() );
|
||||||
|
if ( map != null ) {
|
||||||
|
containerBeanDto.setBeanMap( map );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
containerBeanDto.setBeanStream( containerBeanStreamToContainerBeanDtoStream( containerBean.getBeanStream() ) );
|
||||||
|
containerBeanDto.setValue( containerBean.getValue() );
|
||||||
|
|
||||||
|
return containerBeanDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Stream<ContainerBeanDto> containerBeanStreamToContainerBeanDtoStream(Stream<ContainerBean> stream) {
|
||||||
|
if ( stream == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream.map( containerBean -> containerBeanToContainerBeanDto( containerBean ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ContainerBeanDto containerBeanToContainerBeanDto(ContainerBean containerBean) {
|
||||||
|
if ( containerBean == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContainerBeanDto containerBeanDto = new ContainerBeanDto();
|
||||||
|
|
||||||
|
containerBeanDto.setBeanMap( stringContainerBeanMapToStringContainerBeanDtoMap( containerBean.getBeanMap() ) );
|
||||||
|
containerBeanDto.setBeanStream( containerBeanStreamToContainerBeanDtoStream( containerBean.getBeanStream() ) );
|
||||||
|
containerBeanDto.setValue( containerBean.getValue() );
|
||||||
|
|
||||||
|
return containerBeanDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, ContainerBeanDto> stringContainerBeanMapToStringContainerBeanDtoMap(Map<String, ContainerBean> map) {
|
||||||
|
if ( map == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, ContainerBeanDto> map1 = new LinkedHashMap<String, ContainerBeanDto>( Math.max( (int) ( map.size() / .75f ) + 1, 16 ) );
|
||||||
|
|
||||||
|
for ( java.util.Map.Entry<String, ContainerBean> entry : map.entrySet() ) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
ContainerBeanDto value = containerBeanToContainerBeanDto( entry.getValue() );
|
||||||
|
map1.put( key, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
return map1;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user