#3376 support mapping from iterables to collection

This commit is contained in:
Xiu Hong Kooi 2023-11-01 06:55:11 +08:00 committed by GitHub
parent c59eca2a77
commit 5d39314bd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 330 additions and 2 deletions

View File

@ -278,4 +278,5 @@ public final class ConversionUtils {
public static String url(ConversionContext conversionContext) { public static String url(ConversionContext conversionContext) {
return typeReferenceName( conversionContext, URL.class ); return typeReferenceName( conversionContext, URL.class );
} }
} }

View File

@ -301,7 +301,8 @@ public class PropertyMapping extends ModelElement {
private Assignment forge( ) { private Assignment forge( ) {
Assignment assignment; Assignment assignment;
Type sourceType = rightHandSide.getSourceType(); Type sourceType = rightHandSide.getSourceType();
if ( (sourceType.isCollectionType() || sourceType.isArrayType()) && targetType.isIterableType() ) { if ( ( sourceType.isCollectionType() || sourceType.isArrayType()) && targetType.isIterableType()
|| ( sourceType.isIterableType() && targetType.isCollectionType() ) ) {
assignment = forgeIterableMapping( sourceType, targetType, rightHandSide ); assignment = forgeIterableMapping( sourceType, targetType, rightHandSide );
} }
else if ( sourceType.isMapType() && targetType.isMapType() ) { else if ( sourceType.isMapType() && targetType.isMapType() ) {

View File

@ -434,7 +434,6 @@ public class MappingResolverImpl implements MappingResolver {
private ConversionAssignment resolveViaConversion(Type sourceType, Type targetType) { private ConversionAssignment resolveViaConversion(Type sourceType, Type targetType) {
ConversionProvider conversionProvider = conversions.getConversion( sourceType, targetType ); ConversionProvider conversionProvider = conversions.getConversion( sourceType, targetType );
if ( conversionProvider == null ) { if ( conversionProvider == null ) {
return null; return null;
} }

View File

@ -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.iterabletolist;
/**
*
* @author Xiu-Hong Kooi
*/
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;
}
}

View File

@ -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.iterabletolist;
import java.util.List;
/**
*
* @author Xiu-Hong Kooi
*/
public class FruitSalad {
private Iterable<Fruit> fruits;
public FruitSalad(List<Fruit> fruits) {
this.fruits = fruits;
}
public Iterable<Fruit> getFruits() {
return fruits;
}
public void setFruits(List<Fruit> fruits) {
this.fruits = fruits;
}
}

View File

@ -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.iterabletolist;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
*
* @author Xiu-Hong Kooi
*/
@Mapper
public interface FruitsMapper {
FruitsMapper INSTANCE = Mappers.getMapper(
FruitsMapper.class );
FruitsMenu fruitSaladToMenu(FruitSalad salad);
FruitSalad fruitsMenuToSalad(FruitsMenu menu);
}

View File

@ -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.iterabletolist;
import java.util.Iterator;
import java.util.List;
/**
*
* @author Xiu-Hong Kooi
*/
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();
}
}

View File

@ -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.collection.iterabletolist;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.ProcessorTest;
import org.mapstruct.ap.testutil.WithClasses;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
/**
*
* @author Xiu-Hong Kooi
*/
@WithClasses({ FruitsMenu.class, FruitSalad.class, Fruit.class, FruitsMapper.class })
public class IterableToListMappingTest {
@ProcessorTest
@IssueKey("3376")
public void shouldMapIterableToList() {
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 );
Iterator<Fruit> itr = salad.getFruits().iterator();
assertThat( itr.next().getType() ).isEqualTo( "mango" );
assertThat( itr.next().getType() ).isEqualTo( "apple" );
assertThat( itr.next().getType() ).isEqualTo( "banana" );
}
@ProcessorTest
@IssueKey("3376")
public void shouldMapListToIterable() {
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( menu.getFruits() ).extracting( Fruit::getType ).containsExactly( "mango", "apple", "banana" );
}
}

View File

@ -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.iterabletoset;
/**
*
* @author Xiu-Hong Kooi
*/
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;
}
}

View File

@ -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.iterabletoset;
import java.util.List;
/**
*
* @author Xiu-Hong Kooi
*/
public class FruitSalad {
private Iterable<Fruit> fruits;
public FruitSalad(Iterable<Fruit> fruits) {
this.fruits = fruits;
}
public Iterable<Fruit> getFruits() {
return fruits;
}
public void setFruits(List<Fruit> fruits) {
this.fruits = fruits;
}
}

View File

@ -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.iterabletoset;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
*
* @author Xiu-Hong Kooi
*/
@Mapper
public interface FruitsMapper {
FruitsMapper INSTANCE = Mappers.getMapper(
FruitsMapper.class );
FruitsMenu fruitSaladToMenu(FruitSalad salad);
FruitSalad fruitsMenuToSalad(FruitsMenu menu);
}

View File

@ -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.iterabletoset;
import java.util.Iterator;
import java.util.Set;
/**
*
* @author Xiu-Hong Kooi
*/
public class FruitsMenu implements Iterable<Fruit> {
private Set<Fruit> fruits;
public FruitsMenu(Set<Fruit> fruits) {
this.fruits = fruits;
}
public Set<Fruit> getFruits() {
return fruits;
}
public void setFruits(Set<Fruit> fruits) {
this.fruits = fruits;
}
@Override
public Iterator<Fruit> iterator() {
return this.fruits.iterator();
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.iterabletoset;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.ProcessorTest;
import org.mapstruct.ap.testutil.WithClasses;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
/**
*
* @author Xiu-Hong Kooi
*/
@WithClasses({ FruitsMenu.class, FruitSalad.class, Fruit.class, FruitsMapper.class })
public class IterableToSetMappingTest {
@ProcessorTest
@IssueKey("3376")
public void shouldMapIterableToSet() {
Set<Fruit> fruits = new HashSet<>( Arrays.asList( new Fruit( "mango" ), new Fruit( "apple" ),
new Fruit( "banana" ) ) );
FruitsMenu menu = new FruitsMenu(fruits);
FruitSalad salad = FruitsMapper.INSTANCE.fruitsMenuToSalad( menu );
Iterator<Fruit> itr = salad.getFruits().iterator();
Set<String> fruitTypes = fruits.stream().map( Fruit::getType ).collect( Collectors.toSet() );
assertThat( fruitTypes.contains( itr.next().getType() ) );
assertThat( fruitTypes.contains( itr.next().getType() ) );
assertThat( fruitTypes.contains( itr.next().getType() ) );
}
@ProcessorTest
@IssueKey("3376")
public void shouldMapSetToIterable() {
Set<Fruit> fruits = new HashSet<>( Arrays.asList( new Fruit( "mango" ), new Fruit( "apple" ),
new Fruit( "banana" ) ) );
FruitSalad salad = new FruitSalad(fruits);
FruitsMenu menu = FruitsMapper.INSTANCE.fruitSaladToMenu( salad );
assertThat( menu.getFruits() ).extracting( Fruit::getType ).contains( "mango", "apple", "banana" );
}
}