#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 MethodReference elementMappingMethod;
private final TypeConversion conversion; private final TypeConversion conversion;
private final MethodReference factoryMethod;
public IterableMappingMethod(Method method, MethodReference elementMappingMethod, public IterableMappingMethod(Method method, MethodReference elementMappingMethod,
TypeConversion conversion) { TypeConversion conversion, MethodReference factoryMethod) {
super( method ); super( method );
this.elementMappingMethod = elementMappingMethod; this.elementMappingMethod = elementMappingMethod;
this.conversion = conversion; this.conversion = conversion;
this.factoryMethod = factoryMethod;
} }
public Parameter getSourceParameter() { public Parameter getSourceParameter() {
@ -83,4 +85,8 @@ public class IterableMappingMethod extends MappingMethod {
), getParameterNames() ), getParameterNames()
); );
} }
public MethodReference getFactoryMethod() {
return this.factoryMethod;
}
} }

View File

@ -37,15 +37,18 @@ public class MapMappingMethod extends MappingMethod {
private final MethodReference valueMappingMethod; private final MethodReference valueMappingMethod;
private final TypeConversion keyConversion; private final TypeConversion keyConversion;
private final TypeConversion valueConversion; private final TypeConversion valueConversion;
private final MethodReference factoryMethod;
public MapMappingMethod(Method method, MethodReference keyMappingMethod, TypeConversion keyConversion, public MapMappingMethod(Method method, MethodReference keyMappingMethod, TypeConversion keyConversion,
MethodReference valueMappingMethod, TypeConversion valueConversion) { MethodReference valueMappingMethod, TypeConversion valueConversion,
MethodReference factoryMethod) {
super( method ); super( method );
this.keyMappingMethod = keyMappingMethod; this.keyMappingMethod = keyMappingMethod;
this.keyConversion = keyConversion; this.keyConversion = keyConversion;
this.valueMappingMethod = valueMappingMethod; this.valueMappingMethod = valueMappingMethod;
this.valueConversion = valueConversion; this.valueConversion = valueConversion;
this.factoryMethod = factoryMethod;
} }
public Parameter getSourceParameter() { public Parameter getSourceParameter() {
@ -108,4 +111,8 @@ public class MapMappingMethod extends MappingMethod {
getParameterNames() 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.element.TypeElement;
import javax.lang.model.type.DeclaredType; import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType; import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter; import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements; import javax.lang.model.util.Elements;
@ -170,7 +169,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
continue; continue;
} }
reportErrorIfNoImplementationTypeIsRegisteredForInterfaceReturnType( method ); // TODO: Either find a good check for this or remove?
// reportErrorIfNoImplementationTypeIsRegisteredForInterfaceReturnType( method );
Method reverseMappingMethod = getReverseMappingMethod( methods, method ); Method reverseMappingMethod = getReverseMappingMethod( methods, method );
@ -243,20 +243,21 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
return result; return result;
} }
private void reportErrorIfNoImplementationTypeIsRegisteredForInterfaceReturnType(Method method) { // TODO: Either find a good check for this or remove?
if ( method.getReturnType().getTypeMirror().getKind() != TypeKind.VOID && // private void reportErrorIfNoImplementationTypeIsRegisteredForInterfaceReturnType(Method method) {
method.getReturnType().isInterface() && // if ( method.getReturnType().getTypeMirror().getKind() != TypeKind.VOID &&
method.getReturnType().getImplementationType() == null ) { // method.getReturnType().isInterface() &&
messager.printMessage( // method.getReturnType().getImplementationType() == null ) {
Kind.ERROR, // messager.printMessage(
String.format( // Kind.ERROR,
"No implementation type is registered for return type %s.", // String.format(
method.getReturnType() // "No implementation type is registered for return type %s.",
), // method.getReturnType()
method.getExecutable() // ),
); // method.getExecutable()
} // );
} // }
// }
private Map<String, List<Mapping>> reverse(Map<String, List<Mapping>> mappings) { private Map<String, List<Mapping>> reverse(Map<String, List<Mapping>> mappings) {
Map<String, List<Mapping>> reversed = new HashMap<String, List<Mapping>>(); 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( return new IterableMappingMethod(
method, method,
elementMappingMethod, 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) { 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(); ${resultName}.clear();
<#else> <#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 --> <#-- 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> </#if>
for ( <@includeModel object=sourceParameter.type.typeParameters[0]/> ${loopVariableName} : ${sourceParameter.name} ) { 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> <#if existingInstanceMapping>
${resultName}.clear(); ${resultName}.clear();
<#else> <#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> </#if>
for ( Map.Entry<<#list sourceParameter.type.typeParameters as typeParameter><@includeModel object=typeParameter /><#if typeParameter_has_next>, </#if></#list>> ${entryVariableName} : ${sourceParameter.name}.entrySet() ) { 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; 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 org.mapstruct.ap.test.factories.a.BarFactory;
import static org.fest.assertions.Assertions.assertThat; import static org.fest.assertions.Assertions.assertThat;
@ -33,7 +37,7 @@ import org.testng.annotations.Test;
@IssueKey( "81" ) @IssueKey( "81" )
@WithClasses( { Bar1.class, Foo1.class, Bar2.class, Foo2.class, Bar3.class, Foo3.class, BarFactory.class, @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, 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 { public class FactoryTest extends MapperTestBase {
@Test @Test
public void shouldUseTwoFactoryMethods() { public void shouldUseTwoFactoryMethods() {
@ -49,6 +53,12 @@ public class FactoryTest extends MapperTestBase {
assertThat( target.getProp3() ).isNotNull(); assertThat( target.getProp3() ).isNotNull();
assertThat( target.getProp3().getProp() ).isEqualTo( "foo3" ); assertThat( target.getProp3().getProp() ).isEqualTo( "foo3" );
assertThat( target.getProp3().getSomeTypeProp()).isEqualTo( "BAR3" ); 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() { private Source createSource() {
@ -66,6 +76,13 @@ public class FactoryTest extends MapperTestBase {
foo3.setProp( "foo3" ); foo3.setProp( "foo3" );
source.setProp3( 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; return source;
} }
} }

View File

@ -18,6 +18,9 @@
*/ */
package org.mapstruct.ap.test.factories; package org.mapstruct.ap.test.factories;
import java.util.List;
import java.util.Map;
/** /**
* @author Sjaak Derksen * @author Sjaak Derksen
* *
@ -27,6 +30,8 @@ public class Source {
private Foo1 prop1; private Foo1 prop1;
private Foo2 prop2; private Foo2 prop2;
private Foo3 prop3; private Foo3 prop3;
private List<String> propList;
private Map<String, String> propMap;
public Foo1 getProp1() { public Foo1 getProp1() {
return prop1; return prop1;
@ -51,4 +56,21 @@ public class Source {
public void setProp3( Foo3 prop3 ) { public void setProp3( Foo3 prop3 ) {
this.prop3 = 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; 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.ap.test.factories.a.BarFactory;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
@ -39,7 +41,19 @@ public abstract class SourceTargetMapperAndBar2Factory {
public abstract Bar3 foo3ToBar3(Foo3 foo3); 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() { public Bar2 createBar2() {
return new Bar2("BAR2"); 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; package org.mapstruct.ap.test.factories;
/** /**
* @author Sjaak Derksen * @author Sjaak Derksen
* *
@ -28,7 +27,8 @@ public class Target {
private Bar1 prop1; private Bar1 prop1;
private Bar2 prop2; private Bar2 prop2;
private Bar3 prop3; private Bar3 prop3;
private CustomList<String> propList;
private CustomMap<String, String> propMap;
public Bar1 getProp1() { public Bar1 getProp1() {
return prop1; return prop1;
@ -53,4 +53,21 @@ public class Target {
public void setProp3( Bar3 prop3 ) { public void setProp3( Bar3 prop3 ) {
this.prop3 = 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;
}
} }