mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#2668: Added support for collections and maps with a no-args constructor. Added a compiler error in case of a collection or map without either a no-arg constructor or a copy constructor.
This commit is contained in:
parent
b22efd9ad7
commit
9105041522
@ -5,19 +5,27 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.model;
|
package org.mapstruct.ap.internal.model;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.ElementKind;
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
import javax.lang.model.element.Modifier;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.internal.gem.CollectionMappingStrategyGem;
|
||||||
|
import org.mapstruct.ap.internal.gem.NullValueCheckStrategyGem;
|
||||||
|
import org.mapstruct.ap.internal.gem.NullValuePropertyMappingStrategyGem;
|
||||||
import org.mapstruct.ap.internal.model.assignment.ExistingInstanceSetterWrapperForCollectionsAndMaps;
|
import org.mapstruct.ap.internal.model.assignment.ExistingInstanceSetterWrapperForCollectionsAndMaps;
|
||||||
import org.mapstruct.ap.internal.model.assignment.GetterWrapperForCollectionsAndMaps;
|
import org.mapstruct.ap.internal.model.assignment.GetterWrapperForCollectionsAndMaps;
|
||||||
|
import org.mapstruct.ap.internal.model.assignment.NewInstanceSetterWrapperForCollectionsAndMaps;
|
||||||
import org.mapstruct.ap.internal.model.assignment.SetterWrapperForCollectionsAndMaps;
|
import org.mapstruct.ap.internal.model.assignment.SetterWrapperForCollectionsAndMaps;
|
||||||
import org.mapstruct.ap.internal.model.assignment.SetterWrapperForCollectionsAndMapsWithNullCheck;
|
import org.mapstruct.ap.internal.model.assignment.SetterWrapperForCollectionsAndMapsWithNullCheck;
|
||||||
import org.mapstruct.ap.internal.model.assignment.UpdateWrapper;
|
import org.mapstruct.ap.internal.model.assignment.UpdateWrapper;
|
||||||
import org.mapstruct.ap.internal.model.common.Assignment;
|
import org.mapstruct.ap.internal.model.common.Assignment;
|
||||||
|
import org.mapstruct.ap.internal.model.common.Assignment.AssignmentType;
|
||||||
import org.mapstruct.ap.internal.model.common.SourceRHS;
|
import org.mapstruct.ap.internal.model.common.SourceRHS;
|
||||||
import org.mapstruct.ap.internal.model.common.Type;
|
import org.mapstruct.ap.internal.model.common.Type;
|
||||||
import org.mapstruct.ap.internal.model.source.Method;
|
import org.mapstruct.ap.internal.model.source.Method;
|
||||||
import org.mapstruct.ap.internal.model.source.SelectionParameters;
|
import org.mapstruct.ap.internal.model.source.SelectionParameters;
|
||||||
import org.mapstruct.ap.internal.gem.CollectionMappingStrategyGem;
|
|
||||||
import org.mapstruct.ap.internal.gem.NullValueCheckStrategyGem;
|
|
||||||
import org.mapstruct.ap.internal.gem.NullValuePropertyMappingStrategyGem;
|
|
||||||
import org.mapstruct.ap.internal.util.Message;
|
import org.mapstruct.ap.internal.util.Message;
|
||||||
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;
|
||||||
@ -169,7 +177,8 @@ public class CollectionAssignmentBuilder {
|
|||||||
targetAccessorType.isFieldAssignment()
|
targetAccessorType.isFieldAssignment()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if ( setterWrapperNeedsSourceNullCheck( result ) ) {
|
else if ( setterWrapperNeedsSourceNullCheck( result )
|
||||||
|
&& canBeMappedOrDirectlyAssigned( result ) ) {
|
||||||
|
|
||||||
result = new SetterWrapperForCollectionsAndMapsWithNullCheck(
|
result = new SetterWrapperForCollectionsAndMapsWithNullCheck(
|
||||||
result,
|
result,
|
||||||
@ -179,7 +188,7 @@ public class CollectionAssignmentBuilder {
|
|||||||
targetAccessorType.isFieldAssignment()
|
targetAccessorType.isFieldAssignment()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else if ( canBeMappedOrDirectlyAssigned( result ) ) {
|
||||||
//TODO init default value
|
//TODO init default value
|
||||||
|
|
||||||
// target accessor is setter, so wrap the setter in setter map/ collection handling
|
// target accessor is setter, so wrap the setter in setter map/ collection handling
|
||||||
@ -190,6 +199,21 @@ public class CollectionAssignmentBuilder {
|
|||||||
targetAccessorType.isFieldAssignment()
|
targetAccessorType.isFieldAssignment()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
else if ( hasNoArgsConstructor() ) {
|
||||||
|
result = new NewInstanceSetterWrapperForCollectionsAndMaps(
|
||||||
|
result,
|
||||||
|
method.getThrownTypes(),
|
||||||
|
targetType,
|
||||||
|
ctx.getTypeFactory(),
|
||||||
|
targetAccessorType.isFieldAssignment() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
method.getExecutable(),
|
||||||
|
Message.PROPERTYMAPPING_NO_SUITABLE_COLLECTION_OR_MAP_CONSTRUCTOR,
|
||||||
|
targetType
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( targetImmutable ) {
|
if ( targetImmutable ) {
|
||||||
@ -212,6 +236,12 @@ public class CollectionAssignmentBuilder {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean canBeMappedOrDirectlyAssigned(Assignment result) {
|
||||||
|
return result.getType() != AssignmentType.DIRECT
|
||||||
|
|| hasCopyConstructor()
|
||||||
|
|| targetType.isEnumSet();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the setter wrapper should include a null / presence check or not
|
* Checks whether the setter wrapper should include a null / presence check or not
|
||||||
*
|
*
|
||||||
@ -236,4 +266,48 @@ public class CollectionAssignmentBuilder {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasCopyConstructor() {
|
||||||
|
return checkConstructorForPredicate( this::hasCopyConstructor );
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasNoArgsConstructor() {
|
||||||
|
return checkConstructorForPredicate( this::hasNoArgsConstructor );
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkConstructorForPredicate(Predicate<Element> predicate) {
|
||||||
|
if ( targetType.isCollectionOrMapType() ) {
|
||||||
|
if ( "java.util".equals( targetType.getPackageName() ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Element sourceElement = targetType.getImplementationType() != null
|
||||||
|
? targetType.getImplementationType().getTypeElement()
|
||||||
|
: targetType.getTypeElement();
|
||||||
|
if ( sourceElement != null ) {
|
||||||
|
for ( Element element : sourceElement.getEnclosedElements() ) {
|
||||||
|
if ( element.getKind() == ElementKind.CONSTRUCTOR
|
||||||
|
&& element.getModifiers().contains( Modifier.PUBLIC ) ) {
|
||||||
|
if ( predicate.test( element ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasNoArgsConstructor(Element element) {
|
||||||
|
return ( (ExecutableElement) element ).getParameters().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasCopyConstructor(Element element) {
|
||||||
|
if ( element instanceof ExecutableElement ) {
|
||||||
|
ExecutableElement ee = (ExecutableElement) element;
|
||||||
|
return ee.getParameters().size() == 1
|
||||||
|
&& ctx.getTypeUtils().isAssignable( targetType.getTypeMirror(), ee.getParameters().get( 0 ).asType() );
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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.model.assignment;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.internal.model.common.Assignment;
|
||||||
|
import org.mapstruct.ap.internal.model.common.Type;
|
||||||
|
import org.mapstruct.ap.internal.model.common.TypeFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This wrapper handles the situation where an assignment is done via the setter, while creating the collection or map
|
||||||
|
* using a no-args constructor.
|
||||||
|
*
|
||||||
|
* @author Ben Zegveld
|
||||||
|
*/
|
||||||
|
public class NewInstanceSetterWrapperForCollectionsAndMaps extends SetterWrapperForCollectionsAndMapsWithNullCheck {
|
||||||
|
|
||||||
|
private String instanceVar;
|
||||||
|
|
||||||
|
public NewInstanceSetterWrapperForCollectionsAndMaps(Assignment decoratedAssignment,
|
||||||
|
List<Type> thrownTypesToExclude,
|
||||||
|
Type targetType,
|
||||||
|
TypeFactory typeFactory,
|
||||||
|
boolean fieldAssignment) {
|
||||||
|
|
||||||
|
super(
|
||||||
|
decoratedAssignment,
|
||||||
|
thrownTypesToExclude,
|
||||||
|
targetType,
|
||||||
|
typeFactory,
|
||||||
|
fieldAssignment
|
||||||
|
);
|
||||||
|
this.instanceVar = decoratedAssignment.createUniqueVarName( targetType.getName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInstanceVar() {
|
||||||
|
return instanceVar;
|
||||||
|
}
|
||||||
|
}
|
@ -68,7 +68,7 @@ public class SetterWrapperForCollectionsAndMapsWithNullCheck extends WrapperForC
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnumSet() {
|
public boolean isEnumSet() {
|
||||||
return "java.util.EnumSet".equals( targetType.getFullyQualifiedName() );
|
return targetType.isEnumSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ import java.util.Set;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.ElementKind;
|
import javax.lang.model.element.ElementKind;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
@ -113,7 +112,6 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
private List<Accessor> setters = null;
|
private List<Accessor> setters = null;
|
||||||
private List<Accessor> adders = null;
|
private List<Accessor> adders = null;
|
||||||
private List<Accessor> alternativeTargetAccessors = null;
|
private List<Accessor> alternativeTargetAccessors = null;
|
||||||
private Map<String, Accessor> constructorAccessors = null;
|
|
||||||
|
|
||||||
private Type boundingBase = null;
|
private Type boundingBase = null;
|
||||||
|
|
||||||
@ -1603,4 +1601,8 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
return parent == null ? null : typeFactory.getType( parent.asType() );
|
return parent == null ? null : typeFactory.getType( parent.asType() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEnumSet() {
|
||||||
|
return "java.util.EnumSet".equals( getFullyQualifiedName() );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,7 @@ public enum Message {
|
|||||||
PROPERTYMAPPING_WHITESPACE_TRIMMED( "The property named \"%s\" has whitespaces, using trimmed property \"%s\" instead.", Diagnostic.Kind.WARNING ),
|
PROPERTYMAPPING_WHITESPACE_TRIMMED( "The property named \"%s\" has whitespaces, using trimmed property \"%s\" instead.", Diagnostic.Kind.WARNING ),
|
||||||
PROPERTYMAPPING_CANNOT_DETERMINE_SOURCE_PROPERTY_FROM_TARGET("The type of parameter \"%s\" has no property named \"%s\". Please define the source property explicitly."),
|
PROPERTYMAPPING_CANNOT_DETERMINE_SOURCE_PROPERTY_FROM_TARGET("The type of parameter \"%s\" has no property named \"%s\". Please define the source property explicitly."),
|
||||||
PROPERTYMAPPING_CANNOT_DETERMINE_SOURCE_PARAMETER_FROM_TARGET("No property named \"%s\" exists in source parameter(s). Please define the source explicitly."),
|
PROPERTYMAPPING_CANNOT_DETERMINE_SOURCE_PARAMETER_FROM_TARGET("No property named \"%s\" exists in source parameter(s). Please define the source explicitly."),
|
||||||
|
PROPERTYMAPPING_NO_SUITABLE_COLLECTION_OR_MAP_CONSTRUCTOR( "%s does not have an accessible copy or no-args constructor." ),
|
||||||
|
|
||||||
CONVERSION_LOSSY_WARNING( "%s has a possibly lossy conversion from %s to %s.", Diagnostic.Kind.WARNING ),
|
CONVERSION_LOSSY_WARNING( "%s has a possibly lossy conversion from %s to %s.", Diagnostic.Kind.WARNING ),
|
||||||
CONVERSION_LOSSY_ERROR( "Can't map %s. It has a possibly lossy conversion from %s to %s." ),
|
CONVERSION_LOSSY_ERROR( "Can't map %s. It has a possibly lossy conversion from %s to %s." ),
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
<#--
|
||||||
|
|
||||||
|
Copyright MapStruct Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
-->
|
||||||
|
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.assignment.SetterWrapperForCollectionsAndMapsWithNullCheck" -->
|
||||||
|
<#import "../macro/CommonMacros.ftl" as lib>
|
||||||
|
<@lib.sourceLocalVarAssignment/>
|
||||||
|
<@lib.handleExceptions>
|
||||||
|
<@callTargetWriteAccessor/>
|
||||||
|
</@lib.handleExceptions>
|
||||||
|
<#--
|
||||||
|
assigns the target via the regular target write accessor (usually the setter)
|
||||||
|
-->
|
||||||
|
<#macro callTargetWriteAccessor>
|
||||||
|
<@lib.handleLocalVarNullCheck needs_explicit_local_var=directAssignment>
|
||||||
|
<#if ext.targetType.implementationType??><@includeModel object=ext.targetType.implementationType/><#else><@includeModel object=ext.targetType/></#if> ${instanceVar} = new <#if ext.targetType.implementationType??><@includeModel object=ext.targetType.implementationType/><#else><@includeModel object=ext.targetType/></#if>();
|
||||||
|
${instanceVar}.<#if ext.targetType.collectionType>addAll<#else>putAll</#if>( ${nullCheckLocalVarName} );
|
||||||
|
<#if ext.targetBeanName?has_content>${ext.targetBeanName}.</#if>${ext.targetWriteAccessorName}<@lib.handleWrite>${instanceVar}</@lib.handleWrite>;
|
||||||
|
</@lib.handleLocalVarNullCheck>
|
||||||
|
</#macro>
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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._2668;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ben Zegveld
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface Erroneous2668ListMapper {
|
||||||
|
|
||||||
|
Erroneous2668ListMapper INSTANCE = Mappers.getMapper( Erroneous2668ListMapper.class );
|
||||||
|
|
||||||
|
CollectionTarget map(CollectionSource source);
|
||||||
|
|
||||||
|
class CollectionTarget {
|
||||||
|
MyArrayList list;
|
||||||
|
|
||||||
|
public MyArrayList getList() {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setList(MyArrayList list) {
|
||||||
|
this.list = list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollectionSource {
|
||||||
|
MyArrayList list;
|
||||||
|
|
||||||
|
public MyArrayList getList() {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setList(MyArrayList list) {
|
||||||
|
this.list = list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyArrayList extends ArrayList<String> {
|
||||||
|
private String unusable;
|
||||||
|
|
||||||
|
public MyArrayList(String unusable) {
|
||||||
|
this.unusable = unusable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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._2668;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ben Zegveld
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface Erroneous2668MapMapper {
|
||||||
|
|
||||||
|
Erroneous2668MapMapper INSTANCE = Mappers.getMapper( Erroneous2668MapMapper.class );
|
||||||
|
|
||||||
|
CollectionTarget map(CollectionSource source);
|
||||||
|
|
||||||
|
class CollectionTarget {
|
||||||
|
MyHashMap map;
|
||||||
|
|
||||||
|
public MyHashMap getMap() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMap(MyHashMap map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollectionSource {
|
||||||
|
MyHashMap map;
|
||||||
|
|
||||||
|
public MyHashMap getMap() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMap(MyHashMap map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyHashMap extends HashMap<String, String> {
|
||||||
|
private String unusable;
|
||||||
|
|
||||||
|
public MyHashMap(String unusable) {
|
||||||
|
this.unusable = unusable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* 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._2668;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ben Zegveld
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface Issue2668Mapper {
|
||||||
|
|
||||||
|
Issue2668Mapper INSTANCE = Mappers.getMapper( Issue2668Mapper.class );
|
||||||
|
|
||||||
|
CollectionTarget map(CollectionSource source);
|
||||||
|
|
||||||
|
class CollectionTarget {
|
||||||
|
MyArrayList list;
|
||||||
|
MyHashMap map;
|
||||||
|
MyCopyArrayList copyList;
|
||||||
|
MyCopyHashMap copyMap;
|
||||||
|
|
||||||
|
public MyArrayList getList() {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyHashMap getMap() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setList(MyArrayList list) {
|
||||||
|
this.list = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMap(MyHashMap map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyCopyArrayList getCopyList() {
|
||||||
|
return copyList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyCopyHashMap getCopyMap() {
|
||||||
|
return copyMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCopyList(MyCopyArrayList copyList) {
|
||||||
|
this.copyList = copyList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCopyMap(MyCopyHashMap copyMap) {
|
||||||
|
this.copyMap = copyMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollectionSource {
|
||||||
|
MyArrayList list;
|
||||||
|
MyHashMap map;
|
||||||
|
MyCopyArrayList copyList;
|
||||||
|
MyCopyHashMap copyMap;
|
||||||
|
|
||||||
|
public MyArrayList getList() {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyHashMap getMap() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setList(MyArrayList list) {
|
||||||
|
this.list = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMap(MyHashMap map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyCopyArrayList getCopyList() {
|
||||||
|
return copyList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyCopyHashMap getCopyMap() {
|
||||||
|
return copyMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCopyList(MyCopyArrayList copyList) {
|
||||||
|
this.copyList = copyList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCopyMap(MyCopyHashMap copyMap) {
|
||||||
|
this.copyMap = copyMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyArrayList extends ArrayList<String> {
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyHashMap extends HashMap<String, String> {
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyCopyArrayList extends ArrayList<String> {
|
||||||
|
public MyCopyArrayList(Collection<String> copy) {
|
||||||
|
super( copy );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyCopyHashMap extends HashMap<String, String> {
|
||||||
|
public MyCopyHashMap(HashMap<String, String> copy) {
|
||||||
|
super( copy );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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._2668;
|
||||||
|
|
||||||
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
|
||||||
|
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 Ben Zegveld
|
||||||
|
*/
|
||||||
|
@IssueKey( "2668" )
|
||||||
|
class Issue2668Test {
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
@WithClasses( Issue2668Mapper.class )
|
||||||
|
void shouldCompileCorrectlyWithAvailableConstructors() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
@WithClasses( Erroneous2668ListMapper.class )
|
||||||
|
@ExpectedCompilationOutcome(
|
||||||
|
value = CompilationResult.FAILED,
|
||||||
|
diagnostics = {
|
||||||
|
@Diagnostic(
|
||||||
|
kind = Kind.ERROR,
|
||||||
|
line = 21,
|
||||||
|
message = "org.mapstruct.ap.test.bugs._2668.Erroneous2668ListMapper.MyArrayList"
|
||||||
|
+ " does not have an accessible copy or no-args constructor."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
void errorExpectedBecauseCollectionIsNotUsable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
@WithClasses( Erroneous2668MapMapper.class )
|
||||||
|
@ExpectedCompilationOutcome(
|
||||||
|
value = CompilationResult.FAILED,
|
||||||
|
diagnostics = {
|
||||||
|
@Diagnostic(
|
||||||
|
kind = Kind.ERROR,
|
||||||
|
line = 21,
|
||||||
|
message = "org.mapstruct.ap.test.bugs._2668.Erroneous2668MapMapper.MyHashMap"
|
||||||
|
+ " does not have an accessible copy or no-args constructor."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
void errorExpectedBecauseMapIsNotUsable() {
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user