From b11fa302004e8ba09131dafa4461686a4fd914db Mon Sep 17 00:00:00 2001 From: Gunnar Morling Date: Tue, 30 Apr 2013 23:57:18 +0200 Subject: [PATCH] #6 Using default implementations for mapping collection types --- .../java/org/mapstruct/ap/model/Type.java | 23 +++++- .../main/resources/mapper-implementation.ftl | 7 +- .../DefaultCollectionImplementationTest.java | 73 +++++++++++++++++++ .../defaultimplementation/Source.java | 53 ++++++++++++++ .../defaultimplementation/SourceFoo.java | 36 +++++++++ .../SourceTargetMapper.java | 40 ++++++++++ .../defaultimplementation/Target.java | 53 ++++++++++++++ .../defaultimplementation/TargetFoo.java | 67 +++++++++++++++++ .../java/org/mapstruct/ap/test/model/Car.java | 10 +-- .../org/mapstruct/ap/test/model/CarDto.java | 10 +-- .../mapstruct/ap/test/model/CarMapper.java | 10 +-- 11 files changed, 361 insertions(+), 21 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/DefaultCollectionImplementationTest.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/Source.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/SourceFoo.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/SourceTargetMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/Target.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/TargetFoo.java diff --git a/processor/src/main/java/org/mapstruct/ap/model/Type.java b/processor/src/main/java/org/mapstruct/ap/model/Type.java index bee3b3ca3..a4551c3a8 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/model/Type.java @@ -15,9 +15,14 @@ */ package org.mapstruct.ap.model; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; /** * Represents the type of a bean property, parameter etc. @@ -30,10 +35,19 @@ public class Type { Arrays.asList( "boolean", "char", "byte", "short", "int", "long", "float", "double" ) ); + private final static ConcurrentMap defaultCollectionImplementationTypes = new ConcurrentHashMap(); + + static { + defaultCollectionImplementationTypes.put( List.class.getName(), forClass( ArrayList.class ) ); + defaultCollectionImplementationTypes.put( Set.class.getName(), forClass( HashSet.class ) ); + defaultCollectionImplementationTypes.put( Collection.class.getName(), forClass( ArrayList.class ) ); + } + private final String packageName; private final String name; private final Type elementType; private final boolean isEnumType; + private final Type implementingType; public static Type forClass(Class clazz) { Package pakkage = clazz.getPackage(); @@ -50,15 +64,12 @@ public class Type { this( null, name, null, false ); } - public Type(String packageName, String name) { - this( packageName, name, null, false ); - } - public Type(String packageName, String name, Type elementType, boolean isEnumType) { this.packageName = packageName; this.name = name; this.elementType = elementType; this.isEnumType = isEnumType; + implementingType = defaultCollectionImplementationTypes.get( packageName + "." + name ); } public String getPackageName() { @@ -81,6 +92,10 @@ public class Type { return isEnumType; } + public Type getImplementingType() { + return implementingType; + } + @Override public String toString() { if ( packageName == null ) { diff --git a/processor/src/main/resources/mapper-implementation.ftl b/processor/src/main/resources/mapper-implementation.ftl index 567375ee2..be1d95a23 100644 --- a/processor/src/main/resources/mapper-implementation.ftl +++ b/processor/src/main/resources/mapper-implementation.ftl @@ -18,7 +18,10 @@ package ${packageName}; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import javax.annotation.Generated; import java.util.Date; @@ -41,7 +44,7 @@ public class ${implementationName} implements ${interfaceName} { return null; } - ${beanMapping.targetType.name}<${beanMapping.targetType.elementType.name}> ${beanMapping.targetType.name?uncap_first} = new ${beanMapping.targetType.name}<${beanMapping.targetType.elementType.name}>(); + ${beanMapping.targetType.name}<${beanMapping.targetType.elementType.name}> ${beanMapping.targetType.name?uncap_first} = new <#if beanMapping.targetType.implementingType??>${beanMapping.targetType.implementingType.name}<#else>${beanMapping.targetType.name}<${beanMapping.targetType.elementType.name}>(); for ( ${beanMapping.sourceType.elementType.name} ${beanMapping.sourceType.elementType.name?uncap_first} : ${beanMapping.mappingMethod.parameterName} ) { ${beanMapping.targetType.name?uncap_first}.add( ${beanMapping.mappingMethod.elementMappingMethod.name}( ${beanMapping.sourceType.elementType.name?uncap_first} ) ); @@ -90,7 +93,7 @@ public class ${implementationName} implements ${interfaceName} { return null; } - ${beanMapping.sourceType.name}<${beanMapping.sourceType.elementType.name}> ${beanMapping.sourceType.name?uncap_first} = new ${beanMapping.sourceType.name}<${beanMapping.sourceType.elementType.name}>(); + ${beanMapping.sourceType.name}<${beanMapping.sourceType.elementType.name}> ${beanMapping.sourceType.name?uncap_first} = new <#if beanMapping.sourceType.implementingType??>${beanMapping.sourceType.implementingType.name}<#else>${beanMapping.sourceType.name}<${beanMapping.sourceType.elementType.name}>(); for ( ${beanMapping.targetType.elementType.name} ${beanMapping.targetType.elementType.name?uncap_first} : ${beanMapping.reverseMappingMethod.parameterName} ) { ${beanMapping.sourceType.name?uncap_first}.add( ${beanMapping.reverseMappingMethod.elementMappingMethod.name}( ${beanMapping.targetType.elementType.name?uncap_first} ) ); diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/DefaultCollectionImplementationTest.java b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/DefaultCollectionImplementationTest.java new file mode 100644 index 000000000..209356a25 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/DefaultCollectionImplementationTest.java @@ -0,0 +1,73 @@ +/** + * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.collection.defaultimplementation; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +import org.mapstruct.ap.testutil.IssueKey; +import org.mapstruct.ap.testutil.MapperTestBase; +import org.testng.annotations.Test; + +import static org.fest.assertions.Assertions.assertThat; + +public class DefaultCollectionImplementationTest extends MapperTestBase { + + @Override + protected List> getTestClasses() { + return Arrays.>asList( + Source.class, + SourceFoo.class, + Target.class, + TargetFoo.class, + SourceTargetMapper.class + ); + } + + @Test + @IssueKey("6") + public void shouldUseDefaultImplementationForList() { + Source source = new Source(); + source.setFooList( Arrays.asList( new SourceFoo( "Bob" ), new SourceFoo( "Alice" ) ) ); + Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getFooList() ).containsExactly( new TargetFoo( "Bob" ), new TargetFoo( "Alice" ) ); + } + + @Test + @IssueKey("6") + public void shouldUseDefaultImplementationForSet() { + Source source = new Source(); + source.setFooSet( new HashSet( Arrays.asList( new SourceFoo( "Bob" ), new SourceFoo( "Alice" ) ) ) ); + Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getFooSet() ).containsOnly( new TargetFoo( "Bob" ), new TargetFoo( "Alice" ) ); + } + + @Test + @IssueKey("6") + public void shouldUseDefaultImplementationForCollection() { + Source source = new Source(); + source.setFooCollection( Arrays.asList( new SourceFoo( "Bob" ), new SourceFoo( "Alice" ) ) ); + Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getFooCollection() ).containsOnly( new TargetFoo( "Bob" ), new TargetFoo( "Alice" ) ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/Source.java b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/Source.java new file mode 100644 index 000000000..50c00e1a8 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/Source.java @@ -0,0 +1,53 @@ +/** + * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.collection.defaultimplementation; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +public class Source { + + private List fooList; + + private Set fooSet; + + private Collection fooCollection; + + public List getFooList() { + return fooList; + } + + public void setFooList(List fooList) { + this.fooList = fooList; + } + + public Set getFooSet() { + return fooSet; + } + + public void setFooSet(Set fooSet) { + this.fooSet = fooSet; + } + + public Collection getFooCollection() { + return fooCollection; + } + + public void setFooCollection(Collection fooCollection) { + this.fooCollection = fooCollection; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/SourceFoo.java b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/SourceFoo.java new file mode 100644 index 000000000..31c372218 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/SourceFoo.java @@ -0,0 +1,36 @@ +/** + * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.collection.defaultimplementation; + +public class SourceFoo { + + private String name; + + public SourceFoo() { + } + + public SourceFoo(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/SourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/SourceTargetMapper.java new file mode 100644 index 000000000..01b581d50 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/SourceTargetMapper.java @@ -0,0 +1,40 @@ +/** + * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.collection.defaultimplementation; + + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import org.mapstruct.Mapper; +import org.mapstruct.Mappers; + +@Mapper +public interface SourceTargetMapper { + + public static SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class ); + + Target sourceToTarget(Source source); + + TargetFoo sourceFooToTargetFoo(SourceFoo sourceFoo); + + List sourceFoosToTargetFoos(List foos); + + Set sourceFoosToTargetFoos(Set foos); + + Collection sourceFoosToTargetFoos(Collection foos); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/Target.java b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/Target.java new file mode 100644 index 000000000..f10797491 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/Target.java @@ -0,0 +1,53 @@ +/** + * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.collection.defaultimplementation; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +public class Target { + + private List fooList; + + private Set fooSet; + + private Collection fooCollection; + + public List getFooList() { + return fooList; + } + + public void setFooList(List fooList) { + this.fooList = fooList; + } + + public Set getFooSet() { + return fooSet; + } + + public void setFooSet(Set fooSet) { + this.fooSet = fooSet; + } + + public Collection getFooCollection() { + return fooCollection; + } + + public void setFooCollection(Collection fooCollection) { + this.fooCollection = fooCollection; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/TargetFoo.java b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/TargetFoo.java new file mode 100644 index 000000000..af6bce8a1 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/TargetFoo.java @@ -0,0 +1,67 @@ +/** + * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.collection.defaultimplementation; + +public class TargetFoo { + + private String name; + + public TargetFoo() { + } + + public TargetFoo(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ( ( name == null ) ? 0 : name.hashCode() ); + return result; + } + + @Override + public boolean equals(Object obj) { + if ( this == obj ) { + return true; + } + if ( obj == null ) { + return false; + } + if ( getClass() != obj.getClass() ) { + return false; + } + TargetFoo other = (TargetFoo) obj; + if ( name == null ) { + if ( other.name != null ) { + return false; + } + } + else if ( !name.equals( other.name ) ) { + return false; + } + return true; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/model/Car.java b/processor/src/test/java/org/mapstruct/ap/test/model/Car.java index a1116cdec..0b0c7f236 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/model/Car.java +++ b/processor/src/test/java/org/mapstruct/ap/test/model/Car.java @@ -15,8 +15,8 @@ */ package org.mapstruct.ap.test.model; -import java.util.ArrayList; import java.util.Date; +import java.util.List; public class Car { @@ -24,14 +24,14 @@ public class Car { private int numberOfSeats; private Date manufacturingDate; private Person driver; - private ArrayList passengers; + private List passengers; private int price; private Category category; public Car() { } - public Car(String make, int numberOfSeats, Date manufacturingDate, Person driver, ArrayList passengers) { + public Car(String make, int numberOfSeats, Date manufacturingDate, Person driver, List passengers) { this.make = make; this.numberOfSeats = numberOfSeats; this.manufacturingDate = manufacturingDate; @@ -71,11 +71,11 @@ public class Car { this.driver = driver; } - public ArrayList getPassengers() { + public List getPassengers() { return passengers; } - public void setPassengers(ArrayList passengers) { + public void setPassengers(List passengers) { this.passengers = passengers; } diff --git a/processor/src/test/java/org/mapstruct/ap/test/model/CarDto.java b/processor/src/test/java/org/mapstruct/ap/test/model/CarDto.java index 41de78d52..6565f33be 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/model/CarDto.java +++ b/processor/src/test/java/org/mapstruct/ap/test/model/CarDto.java @@ -15,7 +15,7 @@ */ package org.mapstruct.ap.test.model; -import java.util.ArrayList; +import java.util.List; public class CarDto { @@ -23,14 +23,14 @@ public class CarDto { private int seatCount; private String manufacturingYear; private PersonDto driver; - private ArrayList passengers; + private List passengers; private Long price; private String category; public CarDto() { } - public CarDto(String make, int seatCount, String manufacturingYear, PersonDto driver, ArrayList passengers) { + public CarDto(String make, int seatCount, String manufacturingYear, PersonDto driver, List passengers) { this.make = make; this.seatCount = seatCount; this.manufacturingYear = manufacturingYear; @@ -70,11 +70,11 @@ public class CarDto { this.driver = driver; } - public ArrayList getPassengers() { + public List getPassengers() { return passengers; } - public void setPassengers(ArrayList passengers) { + public void setPassengers(List passengers) { this.passengers = passengers; } diff --git a/processor/src/test/java/org/mapstruct/ap/test/model/CarMapper.java b/processor/src/test/java/org/mapstruct/ap/test/model/CarMapper.java index 593f3acff..a7ab15c3e 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/model/CarMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/model/CarMapper.java @@ -15,7 +15,7 @@ */ package org.mapstruct.ap.test.model; -import java.util.ArrayList; +import java.util.List; import org.mapstruct.Mapper; import org.mapstruct.Mappers; @@ -35,15 +35,15 @@ public interface CarMapper { Car carDtoToCar(CarDto carDto); - ArrayList carsToCarDtos(ArrayList cars); + List carsToCarDtos(List cars); - ArrayList carDtosToCars(ArrayList carDtos); + List carDtosToCars(List carDtos); PersonDto personToPersonDto(Person person); Person personDtoToPerson(PersonDto personDto); - ArrayList personsToPersonDtos(ArrayList persons); + List personsToPersonDtos(List persons); - ArrayList personDtosToPersons(ArrayList personDtos); + List personDtosToPersons(List personDtos); }