mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#607 Mapping Iterable<?> object to an object instead of collection
This commit is contained in:
parent
c2e8034030
commit
26f62b7ef0
@ -90,7 +90,7 @@ carDto.getPassengers().addAll( personsToPersonDtos( car.getPassengers() ) );
|
|||||||
|
|
||||||
[WARNING]
|
[WARNING]
|
||||||
====
|
====
|
||||||
It is not allowed to declare mapping methods with an iterable source and a non-iterable target or the other way around. An error will be raised when detecting this situation.
|
It is not allowed to declare mapping methods with an iterable source (from a java package) and a non-iterable target or the other way around. An error will be raised when detecting this situation.
|
||||||
====
|
====
|
||||||
|
|
||||||
[[mapping-maps]]
|
[[mapping-maps]]
|
||||||
@ -224,4 +224,4 @@ When an iterable or map mapping method declares an interface type as return type
|
|||||||
|
|
||||||
|`ConcurrentMap`|`ConcurrentHashMap`
|
|`ConcurrentMap`|`ConcurrentHashMap`
|
||||||
|`ConcurrentNavigableMap`|`ConcurrentSkipListMap`
|
|`ConcurrentNavigableMap`|`ConcurrentSkipListMap`
|
||||||
|===
|
|===
|
||||||
|
@ -483,7 +483,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
|
|
||||||
Type parameterType = sourceParameters.get( 0 ).getType();
|
Type parameterType = sourceParameters.get( 0 ).getType();
|
||||||
|
|
||||||
if ( parameterType.isIterableOrStreamType() && !resultType.isIterableOrStreamType() ) {
|
if ( isStreamTypeOrIterableFromJavaStdLib( parameterType ) && !resultType.isIterableOrStreamType() ) {
|
||||||
messager.printMessage( method, Message.RETRIEVAL_ITERABLE_TO_NON_ITERABLE );
|
messager.printMessage( method, Message.RETRIEVAL_ITERABLE_TO_NON_ITERABLE );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -493,7 +493,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !parameterType.isIterableOrStreamType() && resultType.isIterableOrStreamType() ) {
|
if ( !parameterType.isIterableOrStreamType() && isStreamTypeOrIterableFromJavaStdLib( resultType ) ) {
|
||||||
messager.printMessage( method, Message.RETRIEVAL_NON_ITERABLE_TO_ITERABLE );
|
messager.printMessage( method, Message.RETRIEVAL_NON_ITERABLE_TO_ITERABLE );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -534,6 +534,10 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isStreamTypeOrIterableFromJavaStdLib(Type type) {
|
||||||
|
return type.isStreamType() || ( type.isIterableType() && type.isJavaLangType() );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the mappings configured via {@code @Mapping} from the given
|
* Retrieves the mappings configured via {@code @Mapping} from the given
|
||||||
* method.
|
* method.
|
||||||
|
@ -143,9 +143,9 @@ public enum Message {
|
|||||||
RETRIEVAL_DUPLICATE_MAPPING_TARGETS( "Can't generate mapping method with more than one @MappingTarget parameter." ),
|
RETRIEVAL_DUPLICATE_MAPPING_TARGETS( "Can't generate mapping method with more than one @MappingTarget parameter." ),
|
||||||
RETRIEVAL_VOID_MAPPING_METHOD( "Can't generate mapping method with return type void." ),
|
RETRIEVAL_VOID_MAPPING_METHOD( "Can't generate mapping method with return type void." ),
|
||||||
RETRIEVAL_NON_ASSIGNABLE_RESULTTYPE( "The result type is not assignable to the the return type." ),
|
RETRIEVAL_NON_ASSIGNABLE_RESULTTYPE( "The result type is not assignable to the the return type." ),
|
||||||
RETRIEVAL_ITERABLE_TO_NON_ITERABLE( "Can't generate mapping method from iterable type to non-iterable type." ),
|
RETRIEVAL_ITERABLE_TO_NON_ITERABLE( "Can't generate mapping method from iterable type from java stdlib to non-iterable type." ),
|
||||||
RETRIEVAL_MAPPING_HAS_TARGET_TYPE_PARAMETER( "Can't generate mapping method that has a parameter annotated with @TargetType." ),
|
RETRIEVAL_MAPPING_HAS_TARGET_TYPE_PARAMETER( "Can't generate mapping method that has a parameter annotated with @TargetType." ),
|
||||||
RETRIEVAL_NON_ITERABLE_TO_ITERABLE( "Can't generate mapping method from non-iterable type to iterable type." ),
|
RETRIEVAL_NON_ITERABLE_TO_ITERABLE( "Can't generate mapping method from non-iterable type to iterable type from java stdlib." ),
|
||||||
RETRIEVAL_PRIMITIVE_PARAMETER( "Can't generate mapping method with primitive parameter type." ),
|
RETRIEVAL_PRIMITIVE_PARAMETER( "Can't generate mapping method with primitive parameter type." ),
|
||||||
RETRIEVAL_PRIMITIVE_RETURN( "Can't generate mapping method with primitive return type." ),
|
RETRIEVAL_PRIMITIVE_RETURN( "Can't generate mapping method with primitive return type." ),
|
||||||
RETRIEVAL_TYPE_VAR_SOURCE( "Can't generate mapping method for a generic type variable source." ),
|
RETRIEVAL_TYPE_VAR_SOURCE( "Can't generate mapping method for a generic type variable source." ),
|
||||||
|
@ -28,21 +28,25 @@ public class ErroneousCollectionMappingTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@IssueKey("6")
|
@IssueKey("6")
|
||||||
@WithClasses({ ErroneousCollectionToNonCollectionMapper.class })
|
@WithClasses({ ErroneousCollectionToNonCollectionMapper.class, Source.class })
|
||||||
@ExpectedCompilationOutcome(
|
@ExpectedCompilationOutcome(
|
||||||
value = CompilationResult.FAILED,
|
value = CompilationResult.FAILED,
|
||||||
diagnostics = {
|
diagnostics = {
|
||||||
@Diagnostic(type = ErroneousCollectionToNonCollectionMapper.class,
|
@Diagnostic(type = ErroneousCollectionToNonCollectionMapper.class,
|
||||||
kind = Kind.ERROR,
|
kind = Kind.ERROR,
|
||||||
line = 15,
|
line = 15,
|
||||||
message = "Can't generate mapping method from iterable type to non-iterable type."),
|
message = "Can't generate mapping method from iterable type from java stdlib to non-iterable type."),
|
||||||
@Diagnostic(type = ErroneousCollectionToNonCollectionMapper.class,
|
@Diagnostic(type = ErroneousCollectionToNonCollectionMapper.class,
|
||||||
kind = Kind.ERROR,
|
kind = Kind.ERROR,
|
||||||
line = 17,
|
line = 17,
|
||||||
message = "Can't generate mapping method from non-iterable type to iterable type.")
|
message = "Can't generate mapping method from non-iterable type to iterable type from java stdlib."),
|
||||||
|
@Diagnostic(type = ErroneousCollectionToNonCollectionMapper.class,
|
||||||
|
kind = Kind.ERROR,
|
||||||
|
line = 19,
|
||||||
|
message = "Can't generate mapping method from non-iterable type to iterable type from java stdlib.")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
public void shouldFailToGenerateImplementationBetweenCollectionAndNonCollection() {
|
public void shouldFailToGenerateImplementationBetweenCollectionAndNonCollectionWithResultTypeFromJava() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -15,4 +15,6 @@ public interface ErroneousCollectionToNonCollectionMapper {
|
|||||||
Integer stringSetToInteger(Set<String> strings);
|
Integer stringSetToInteger(Set<String> strings);
|
||||||
|
|
||||||
Set<String> integerToStringSet(Integer integer);
|
Set<String> integerToStringSet(Integer integer);
|
||||||
|
|
||||||
|
Set<String> nonJavaStdlibToCollection(Source stringCollection);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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.collection.iterabletononiterable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Saheb Preet Singh
|
||||||
|
*/
|
||||||
|
public class Fruit {
|
||||||
|
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
public Fruit(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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.collection.iterabletononiterable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Saheb Preet Singh
|
||||||
|
*/
|
||||||
|
public class FruitSalad {
|
||||||
|
|
||||||
|
private List<Fruit> fruits;
|
||||||
|
|
||||||
|
public FruitSalad(List<Fruit> fruits) {
|
||||||
|
this.fruits = fruits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Fruit> getFruits() {
|
||||||
|
return fruits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFruits(List<Fruit> fruits) {
|
||||||
|
this.fruits = fruits;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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.collection.iterabletononiterable;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Saheb Preet Singh
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface FruitsMapper {
|
||||||
|
|
||||||
|
FruitsMapper INSTANCE = Mappers.getMapper(
|
||||||
|
FruitsMapper.class );
|
||||||
|
|
||||||
|
FruitsMenu fruitSaladToMenu(FruitSalad salad);
|
||||||
|
|
||||||
|
FruitSalad fruitsMenuToSalad(FruitsMenu menu);
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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.collection.iterabletononiterable;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Saheb Preet Singh
|
||||||
|
*/
|
||||||
|
public class FruitsMenu implements Iterable<Fruit> {
|
||||||
|
|
||||||
|
private List<Fruit> fruits;
|
||||||
|
|
||||||
|
public FruitsMenu(List<Fruit> fruits) {
|
||||||
|
this.fruits = fruits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Fruit> getFruits() {
|
||||||
|
return fruits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFruits(List<Fruit> fruits) {
|
||||||
|
this.fruits = fruits;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Fruit> iterator() {
|
||||||
|
return this.fruits.iterator();
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ package org.mapstruct.ap.test.collection.iterabletononiterable;
|
|||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@ -15,7 +16,8 @@ import org.mapstruct.ap.testutil.IssueKey;
|
|||||||
import org.mapstruct.ap.testutil.WithClasses;
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
||||||
|
|
||||||
@WithClasses({ Source.class, Target.class, SourceTargetMapper.class, StringListMapper.class })
|
@WithClasses({ Source.class, Target.class, SourceTargetMapper.class, StringListMapper.class, FruitsMenu.class,
|
||||||
|
FruitSalad.class, Fruit.class, FruitsMapper.class })
|
||||||
@RunWith(AnnotationProcessorTestRunner.class)
|
@RunWith(AnnotationProcessorTestRunner.class)
|
||||||
public class IterableToNonIterableMappingTest {
|
public class IterableToNonIterableMappingTest {
|
||||||
|
|
||||||
@ -45,4 +47,26 @@ public class IterableToNonIterableMappingTest {
|
|||||||
assertThat( source.getNames() ).isEqualTo( Arrays.asList( "Alice", "Bob", "Jim" ) );
|
assertThat( source.getNames() ).isEqualTo( Arrays.asList( "Alice", "Bob", "Jim" ) );
|
||||||
assertThat( source.publicNames ).isEqualTo( Arrays.asList( "Alice", "Bob", "Jim" ) );
|
assertThat( source.publicNames ).isEqualTo( Arrays.asList( "Alice", "Bob", "Jim" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("607")
|
||||||
|
public void shouldMapIterableToNonIterable() {
|
||||||
|
List<Fruit> fruits = Arrays.asList( new Fruit( "mango" ), new Fruit( "apple" ),
|
||||||
|
new Fruit( "banana" ) );
|
||||||
|
FruitsMenu menu = new FruitsMenu(fruits);
|
||||||
|
FruitSalad salad = FruitsMapper.INSTANCE.fruitsMenuToSalad( menu );
|
||||||
|
assertThat( salad.getFruits().get( 0 ).getType() ).isEqualTo( "mango" );
|
||||||
|
assertThat( salad.getFruits().get( 1 ).getType() ).isEqualTo( "apple" );
|
||||||
|
assertThat( salad.getFruits().get( 2 ).getType() ).isEqualTo( "banana" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("607")
|
||||||
|
public void shouldMapNonIterableToIterable() {
|
||||||
|
List<Fruit> fruits = Arrays.asList( new Fruit( "mango" ), new Fruit( "apple" ),
|
||||||
|
new Fruit( "banana" ) );
|
||||||
|
FruitSalad salad = new FruitSalad(fruits);
|
||||||
|
FruitsMenu menu = FruitsMapper.INSTANCE.fruitSaladToMenu( salad );
|
||||||
|
assertThat( salad.getFruits() ).extracting( Fruit::getType ).containsExactly( "mango", "apple", "banana" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,11 +42,11 @@ public class ErroneousStreamMappingTest {
|
|||||||
@Diagnostic(type = ErroneousStreamToNonStreamMapper.class,
|
@Diagnostic(type = ErroneousStreamToNonStreamMapper.class,
|
||||||
kind = Kind.ERROR,
|
kind = Kind.ERROR,
|
||||||
line = 15,
|
line = 15,
|
||||||
message = "Can't generate mapping method from iterable type to non-iterable type."),
|
message = "Can't generate mapping method from iterable type from java stdlib to non-iterable type."),
|
||||||
@Diagnostic(type = ErroneousStreamToNonStreamMapper.class,
|
@Diagnostic(type = ErroneousStreamToNonStreamMapper.class,
|
||||||
kind = Kind.ERROR,
|
kind = Kind.ERROR,
|
||||||
line = 17,
|
line = 17,
|
||||||
message = "Can't generate mapping method from non-iterable type to iterable type.")
|
message = "Can't generate mapping method from non-iterable type to iterable type from java stdlib.")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
public void shouldFailToGenerateImplementationBetweenStreamAndNonStreamOrIterable() {
|
public void shouldFailToGenerateImplementationBetweenStreamAndNonStreamOrIterable() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user