#81 adding implementation for Map and Iterable types, and adding unit test. NOTE a TODO is still in MapperCreationProcessor

This commit is contained in:
sjaakd 2014-02-02 20:36:49 +01:00
parent 3f94c51884
commit aa06a767ac
13 changed files with 251 additions and 25 deletions

View File

@ -36,12 +36,14 @@ public class IterableMappingMethod extends MappingMethod {
private final MethodReference elementMappingMethod;
private final TypeConversion conversion;
private final MethodReference factoryMethod;
public IterableMappingMethod(Method method, MethodReference elementMappingMethod,
TypeConversion conversion) {
TypeConversion conversion, MethodReference factoryMethod) {
super( method );
this.elementMappingMethod = elementMappingMethod;
this.conversion = conversion;
this.factoryMethod = factoryMethod;
}
public Parameter getSourceParameter() {
@ -83,4 +85,8 @@ public class IterableMappingMethod extends MappingMethod {
), getParameterNames()
);
}
public MethodReference getFactoryMethod() {
return this.factoryMethod;
}
}

View File

@ -37,15 +37,18 @@ public class MapMappingMethod extends MappingMethod {
private final MethodReference valueMappingMethod;
private final TypeConversion keyConversion;
private final TypeConversion valueConversion;
private final MethodReference factoryMethod;
public MapMappingMethod(Method method, MethodReference keyMappingMethod, TypeConversion keyConversion,
MethodReference valueMappingMethod, TypeConversion valueConversion) {
MethodReference valueMappingMethod, TypeConversion valueConversion,
MethodReference factoryMethod) {
super( method );
this.keyMappingMethod = keyMappingMethod;
this.keyConversion = keyConversion;
this.valueMappingMethod = valueMappingMethod;
this.valueConversion = valueConversion;
this.factoryMethod = factoryMethod;
}
public Parameter getSourceParameter() {
@ -108,4 +111,8 @@ public class MapMappingMethod extends MappingMethod {
getParameterNames()
);
}
public MethodReference getFactoryMethod() {
return this.factoryMethod;
}
}

View File

@ -33,7 +33,6 @@ import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
@ -170,7 +169,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
continue;
}
reportErrorIfNoImplementationTypeIsRegisteredForInterfaceReturnType( method );
// TODO: Either find a good check for this or remove?
// reportErrorIfNoImplementationTypeIsRegisteredForInterfaceReturnType( method );
Method reverseMappingMethod = getReverseMappingMethod( methods, method );
@ -243,20 +243,21 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
return result;
}
private void reportErrorIfNoImplementationTypeIsRegisteredForInterfaceReturnType(Method method) {
if ( method.getReturnType().getTypeMirror().getKind() != TypeKind.VOID &&
method.getReturnType().isInterface() &&
method.getReturnType().getImplementationType() == null ) {
messager.printMessage(
Kind.ERROR,
String.format(
"No implementation type is registered for return type %s.",
method.getReturnType()
),
method.getExecutable()
);
}
}
// TODO: Either find a good check for this or remove?
// private void reportErrorIfNoImplementationTypeIsRegisteredForInterfaceReturnType(Method method) {
// if ( method.getReturnType().getTypeMirror().getKind() != TypeKind.VOID &&
// method.getReturnType().isInterface() &&
// method.getReturnType().getImplementationType() == null ) {
// messager.printMessage(
// Kind.ERROR,
// String.format(
// "No implementation type is registered for return type %s.",
// method.getReturnType()
// ),
// method.getExecutable()
// );
// }
// }
private Map<String, List<Mapping>> reverse(Map<String, List<Mapping>> mappings) {
Map<String, List<Mapping>> reversed = new HashMap<String, List<Mapping>>();
@ -608,10 +609,12 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
);
}
MethodReference factoryMethod = getFactoryMethod( mapperReferences, methods, method.getReturnType() );
return new IterableMappingMethod(
method,
elementMappingMethod,
conversion
conversion,
factoryMethod
);
}
@ -674,7 +677,9 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
);
}
return new MapMappingMethod( method, keyMappingMethod, keyConversion, valueMappingMethod, valueConversion );
MethodReference factoryMethod = getFactoryMethod( mapperReferences, methods, method.getReturnType() );
return new MapMappingMethod( method, keyMappingMethod, keyConversion, valueMappingMethod, valueConversion,
factoryMethod );
}
private TypeConversion getConversion(Type sourceType, Type targetType, String dateFormat, String sourceReference) {

View File

@ -28,7 +28,7 @@ public <@includeModel object=returnType/> ${name}(<#list parameters as param><@i
${resultName}.clear();
<#else>
<#-- Use the interface type on the left side, except it is java.lang.Iterable; use the implementation type - if present - on the right side -->
<#if resultType.fullyQualifiedName == "java.lang.Iterable"><@includeModel object=resultType.implementationType/><#else><@includeModel object=resultType/></#if> ${resultName} = new <#if resultType.implementationType??><@includeModel object=resultType.implementationType/><#else><@includeModel object=resultType/></#if>();
<#if resultType.fullyQualifiedName == "java.lang.Iterable"><@includeModel object=resultType.implementationType/><#else><@includeModel object=resultType/></#if> ${resultName} = <#if factoryMethod??><@includeModel object=factoryMethod/><#else>new <#if resultType.implementationType??><@includeModel object=resultType.implementationType/><#else><@includeModel object=resultType/></#if>()</#if>;
</#if>
for ( <@includeModel object=sourceParameter.type.typeParameters[0]/> ${loopVariableName} : ${sourceParameter.name} ) {

View File

@ -27,7 +27,7 @@ public <@includeModel object=returnType /> ${name}(<#list parameters as param><@
<#if existingInstanceMapping>
${resultName}.clear();
<#else>
<@includeModel object=resultType /> ${resultName} = new <#if resultType.implementationType??><@includeModel object=resultType.implementationType /><#else><@includeModel object=resultType /></#if>();
<@includeModel object=resultType /> ${resultName} = <#if factoryMethod??><@includeModel object=factoryMethod/><#else>new <#if resultType.implementationType??><@includeModel object=resultType.implementationType /><#else><@includeModel object=resultType /></#if>()</#if>;
</#if>
for ( Map.Entry<<#list sourceParameter.type.typeParameters as typeParameter><@includeModel object=typeParameter /><#if typeParameter_has_next>, </#if></#list>> ${entryVariableName} : ${sourceParameter.name}.entrySet() ) {

View File

@ -0,0 +1,30 @@
/**
* Copyright 2012-2014 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* 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.factories;
import java.util.List;
/**
*
* @author Sjaak Derksen
*/
public interface CustomList<T> extends List<T> {
String getTypeProp();
}

View File

@ -0,0 +1,39 @@
/**
* Copyright 2012-2014 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* 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.factories;
import java.util.LinkedList;
/**
*
* @author Sjaak Derksen
*/
public class CustomListImpl<T> extends LinkedList<T> implements CustomList<T> {
private final String typeProp;
public CustomListImpl( String typeProp ) {
this.typeProp = typeProp;
}
@Override
public String getTypeProp() {
return typeProp;
}
}

View File

@ -0,0 +1,30 @@
/**
* Copyright 2012-2014 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* 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.factories;
import java.util.Map;
/**
*
* @author Sjaak Derksen
*/
public interface CustomMap<K, V> extends Map<K, V> {
String getTypeProp();
}

View File

@ -0,0 +1,39 @@
/**
* Copyright 2012-2014 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* 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.factories;
import java.util.HashMap;
/**
*
* @author Sjaak Derksen
*/
public class CustomMapImpl<K, V> extends HashMap<K, V> implements CustomMap<K, V> {
private final String typeProp;
public CustomMapImpl( String typeProp ) {
this.typeProp = typeProp;
}
@Override
public String getTypeProp() {
return typeProp;
}
}

View File

@ -18,6 +18,10 @@
*/
package org.mapstruct.ap.test.factories;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.mapstruct.ap.test.factories.a.BarFactory;
import static org.fest.assertions.Assertions.assertThat;
@ -33,7 +37,7 @@ import org.testng.annotations.Test;
@IssueKey( "81" )
@WithClasses( { Bar1.class, Foo1.class, Bar2.class, Foo2.class, Bar3.class, Foo3.class, BarFactory.class,
org.mapstruct.ap.test.factories.b.BarFactory.class, Source.class, SourceTargetMapperAndBar2Factory.class,
Target.class } )
Target.class, CustomList.class, CustomListImpl.class, CustomMap.class, CustomMapImpl.class } )
public class FactoryTest extends MapperTestBase {
@Test
public void shouldUseTwoFactoryMethods() {
@ -49,6 +53,12 @@ public class FactoryTest extends MapperTestBase {
assertThat( target.getProp3() ).isNotNull();
assertThat( target.getProp3().getProp() ).isEqualTo( "foo3" );
assertThat( target.getProp3().getSomeTypeProp()).isEqualTo( "BAR3" );
assertThat( target.getPropList() ).isNotNull();
assertThat( target.getPropList().get( 0 ) ).isEqualTo( "fooListEntry" );
assertThat( target.getPropList().getTypeProp()).isEqualTo( "CUSTOMLIST" );
assertThat( target.getPropMap() ).isNotNull();
assertThat( target.getPropMap().get( "key" ) ).isEqualTo( "fooValue" );
assertThat( target.getPropMap().getTypeProp()).isEqualTo( "CUSTOMMAP" );
}
private Source createSource() {
@ -66,6 +76,13 @@ public class FactoryTest extends MapperTestBase {
foo3.setProp( "foo3" );
source.setProp3( foo3 );
List<String> fooList = new ArrayList<String>();
fooList.add( "fooListEntry" );
source.setPropList( fooList );
Map<String, String> fooMap = new HashMap<String, String>();
fooMap.put( "key", "fooValue");
source.setPropMap( fooMap );
return source;
}
}

View File

@ -18,6 +18,9 @@
*/
package org.mapstruct.ap.test.factories;
import java.util.List;
import java.util.Map;
/**
* @author Sjaak Derksen
*
@ -27,6 +30,8 @@ public class Source {
private Foo1 prop1;
private Foo2 prop2;
private Foo3 prop3;
private List<String> propList;
private Map<String, String> propMap;
public Foo1 getProp1() {
return prop1;
@ -51,4 +56,21 @@ public class Source {
public void setProp3( Foo3 prop3 ) {
this.prop3 = prop3;
}
public List<String> getPropList() {
return propList;
}
public void setPropList( List<String> propList ) {
this.propList = propList;
}
public Map<String, String> getPropMap() {
return propMap;
}
public void setPropMap( Map<String, String> propMap ) {
this.propMap = propMap;
}
}

View File

@ -18,6 +18,8 @@
*/
package org.mapstruct.ap.test.factories;
import java.util.List;
import java.util.Map;
import org.mapstruct.ap.test.factories.a.BarFactory;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@ -39,7 +41,19 @@ public abstract class SourceTargetMapperAndBar2Factory {
public abstract Bar3 foo3ToBar3(Foo3 foo3);
public abstract CustomList<String> customListToList(List<String> list);
public abstract CustomMap<String, String> customMapToMap(Map<String, String> list);
public Bar2 createBar2() {
return new Bar2("BAR2");
}
public CustomList<String> createCustomList() {
return new CustomListImpl<String>("CUSTOMLIST");
}
public CustomMap<String, String> createCustomMap() {
return new CustomMapImpl<String, String>("CUSTOMMAP");
}
}

View File

@ -18,7 +18,6 @@
*/
package org.mapstruct.ap.test.factories;
/**
* @author Sjaak Derksen
*
@ -28,7 +27,8 @@ public class Target {
private Bar1 prop1;
private Bar2 prop2;
private Bar3 prop3;
private CustomList<String> propList;
private CustomMap<String, String> propMap;
public Bar1 getProp1() {
return prop1;
@ -53,4 +53,21 @@ public class Target {
public void setProp3( Bar3 prop3 ) {
this.prop3 = prop3;
}
public CustomList<String> getPropList() {
return propList;
}
public void setPropList( CustomList<String> propList ) {
this.propList = propList;
}
public CustomMap<String, String> getPropMap() {
return propMap;
}
public void setPropMap( CustomMap<String, String> propMap ) {
this.propMap = propMap;
}
}