squash issue 81 after rebase to issue 112

This commit is contained in:
sjaakd 2014-01-20 23:28:34 +01:00
parent de7aab04b0
commit c3df6d8572
16 changed files with 563 additions and 5 deletions

View File

@ -38,10 +38,14 @@ import org.mapstruct.ap.model.source.Method;
public class BeanMappingMethod extends MappingMethod {
private final List<PropertyMapping> propertyMappings;
private final FactoryMethod factoryMethod;
private final boolean hasFactoryMethod;
public BeanMappingMethod(Method method, List<PropertyMapping> propertyMappings) {
public BeanMappingMethod(Method method, List<PropertyMapping> propertyMappings, FactoryMethod factoryMethod) {
super( method );
this.propertyMappings = propertyMappings;
this.factoryMethod = factoryMethod;
this.hasFactoryMethod = factoryMethod != null;
}
public List<PropertyMapping> getPropertyMappings() {
@ -74,4 +78,12 @@ public class BeanMappingMethod extends MappingMethod {
return types;
}
public boolean isHasFactoryMethod() {
return this.hasFactoryMethod;
}
public FactoryMethod getFactoryMethod() {
return this.factoryMethod;
}
}

View File

@ -0,0 +1,83 @@
/**
* 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.model;
import java.beans.Introspector;
import java.util.HashSet;
import java.util.Set;
import org.mapstruct.ap.model.source.Method;
import org.mapstruct.ap.util.Strings;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.common.ModelElement;
/**
* A factory method
*
* @author Sjaak Derksen
*/
public class FactoryMethod extends ModelElement {
private final String name;
private final boolean hasDeclaringMapper;
private final Type declaringMapper;
private final Type returnType;
public FactoryMethod(Method method) {
this.name = method.getName();
this.hasDeclaringMapper = method.getDeclaringMapper() != null;
this.declaringMapper = method.getDeclaringMapper();
this.returnType = method.getReturnType();
}
public String getName() {
return name;
}
public Type getDeclaringMapper() {
return declaringMapper;
}
public String getMapperVariableName() {
return Strings.getSaveVariableName( Introspector.decapitalize( declaringMapper.getName() ) );
}
@Override
public Set<Type> getImportTypes() {
Set<Type> types = new HashSet<Type>();
types.add( returnType );
types.addAll( returnType.getImportTypes() );
return types;
}
/**
* There is no declaring mapper when the factory method is on an abstract
* mapper class. If the declaring mapper is a referenced mapper, then this will
* result into true.
*
* @return true when declaring mapper is a referenced mapper (or factory)
*/
public boolean isHasDeclaringMapper() {
return hasDeclaringMapper;
}
public Object getReturnType() {
return returnType;
}
}

View File

@ -75,6 +75,22 @@ public class Method {
);
}
public static Method forFactoryMethod(Type declaringMapper, ExecutableElement executable,
Type returnType ) {
return new Method(
declaringMapper,
executable,
Collections.<Parameter>emptyList(),
returnType,
Collections.<String, List<Mapping>>emptyMap(),
null,
null
);
}
private Method(Type declaringMapper, ExecutableElement executable, List<Parameter> parameters, Type returnType,
Map<String, List<Mapping>> mappings, IterableMapping iterableMapping, MapMapping mapMapping) {
this.declaringMapper = declaringMapper;

View File

@ -45,6 +45,7 @@ import org.mapstruct.ap.conversion.Conversions;
import org.mapstruct.ap.conversion.DefaultConversionContext;
import org.mapstruct.ap.model.BeanMappingMethod;
import org.mapstruct.ap.model.DefaultMapperReference;
import org.mapstruct.ap.model.FactoryMethod;
import org.mapstruct.ap.model.IterableMappingMethod;
import org.mapstruct.ap.model.MapMappingMethod;
import org.mapstruct.ap.model.Mapper;
@ -208,6 +209,32 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
return mappingMethods;
}
private FactoryMethod getFactoryMethod(List<Method> methods, Type returnType) {
FactoryMethod result = null;
for ( Method method : methods ) {
if ( !method.requiresImplementation() && !method.isIterableMapping() && !method.isMapMapping()
&& method.getMappings().isEmpty() && method.getParameters().isEmpty() ) {
if ( method.getReturnType().equals( returnType ) ) {
if ( result == null ) {
result = new FactoryMethod(method);
}
else {
messager.printMessage(
Kind.ERROR,
String.format(
"Ambigious factory method: \"%s\" conflicts with \"%s\".",
result.getName(),
method.getName()
),
method.getExecutable()
);
}
}
}
}
return result;
}
private void reportErrorIfNoImplementationTypeIsRegisteredForInterfaceReturnType(Method method) {
if ( method.getReturnType().getTypeMirror().getKind() != TypeKind.VOID &&
method.getReturnType().isInterface() &&
@ -352,7 +379,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
mappedTargetProperties
);
return new BeanMappingMethod( method, propertyMappings );
FactoryMethod factoryMethod = getFactoryMethod( methods, method.getReturnType() );
return new BeanMappingMethod( method, propertyMappings, factoryMethod );
}
private void reportErrorForUnmappedTargetPropertiesIfRequired(Method method,

View File

@ -156,6 +156,15 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
returnType
);
}
//create factory method
else if ( parameters.isEmpty() ) {
return
Method.forFactoryMethod(
mapperRequiresImplementation ? null : typeFactory.getType( element ),
method,
returnType
);
}
else {
return null;
}

View File

@ -25,8 +25,7 @@ public <@includeModel object=returnType/> ${name}(<#list parameters as param><@i
}
<#if !existingInstanceMapping>
<@includeModel object=resultType/> ${resultName} = new <@includeModel object=resultType/>();
${resultType.name} ${resultName} = <#if hasFactoryMethod><#if factoryMethod.hasDeclaringMapper>${factoryMethod.mapperVariableName}.</#if>${factoryMethod.name}()<#else>new ${resultType.name}()</#if>;
</#if>
<#if (sourceParameters?size > 1)>
<#list sourceParameters as sourceParam>

View File

@ -0,0 +1,21 @@
<#--
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.
-->
<#if declaringMapper??>${mapperVariableName}.</#if>${name}( ${ext.input} )

View File

@ -0,0 +1,45 @@
/**
* 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;
/**
* @author Sjaak Derksen
*
*/
public class Bar1 {
private String prop;
private final String someTypeProp;
public Bar1( String someTypeProp ) {
this.someTypeProp = someTypeProp;
}
public String getProp() {
return prop;
}
public void setProp(String prop) {
this.prop = prop;
}
public String getSomeTypeProp() {
return someTypeProp;
}
}

View File

@ -0,0 +1,31 @@
/**
* 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;
/**
*
* @author Sjaak Derksen
*/
public class Bar1Factory {
public Bar1 createBar1() {
return new Bar1("BAR1");
}
}

View File

@ -0,0 +1,45 @@
/**
* 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;
/**
* @author Sjaak Derksen
*
*/
public class Bar2 {
private String prop;
private final String someTypeProp;
public Bar2( String someTypeProp ) {
this.someTypeProp = someTypeProp;
}
public String getProp() {
return prop;
}
public void setProp(String prop) {
this.prop = prop;
}
public String getSomeTypeProp() {
return someTypeProp;
}
}

View File

@ -0,0 +1,62 @@
/**
* 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 static org.fest.assertions.Assertions.assertThat;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.MapperTestBase;
import org.mapstruct.ap.testutil.WithClasses;
import org.testng.annotations.Test;
/**
* @author Sjaak Derksen
*
*/
@IssueKey( "81" )
@WithClasses( { Bar1.class, Foo1.class, Bar2.class, Foo2.class, Bar1Factory.class, Source.class,
SourceTargetMapperAndBar2Factory.class, Target.class } )
public class FactoryTest extends MapperTestBase {
@Test
public void shouldUseTwoFactoryMethods() {
Target target = SourceTargetMapperAndBar2Factory.INSTANCE.sourceToTarget( createSource() );
assertThat( target ).isNotNull();
assertThat( target.getProp1() ).isNotNull();
assertThat( target.getProp1().getProp() ).isEqualTo( "foo1" );
assertThat( target.getProp1().getSomeTypeProp()).isEqualTo( "BAR1" );
assertThat( target.getProp2() ).isNotNull();
assertThat( target.getProp2().getProp() ).isEqualTo( "foo2" );
assertThat( target.getProp2().getSomeTypeProp()).isEqualTo( "BAR2" );
}
private Source createSource() {
Source source = new Source();
Foo1 foo1 = new Foo1();
foo1.setProp( "foo1" );
source.setProp1( foo1 );
Foo2 foo2 = new Foo2();
foo2.setProp( "foo2" );
source.setProp2( foo2 );
return source;
}
}

View File

@ -0,0 +1,35 @@
/**
* 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;
/**
* @author Sjaak Derksen
*
*/
public class Foo1 {
private String prop;
public String getProp() {
return prop;
}
public void setProp(String prop) {
this.prop = prop;
}
}

View File

@ -0,0 +1,35 @@
/**
* 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;
/**
* @author Sjaak Derksen
*
*/
public class Foo2 {
private String prop;
public String getProp() {
return prop;
}
public void setProp(String prop) {
this.prop = prop;
}
}

View File

@ -0,0 +1,46 @@
/**
* 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;
/**
* @author Sjaak Derksen
*
*/
public class Source {
private Foo1 prop1;
private Foo2 prop2;
public Foo1 getProp1() {
return prop1;
}
public void setProp1( Foo1 prop1 ) {
this.prop1 = prop1;
}
public Foo2 getProp2() {
return prop2;
}
public void setProp2( Foo2 prop2 ) {
this.prop2 = prop2;
}
}

View File

@ -0,0 +1,42 @@
/**
* 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 org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* @author Sjaak Derksen
*
*/
@Mapper( uses = { Bar1Factory.class } )
public abstract class SourceTargetMapperAndBar2Factory {
public static final SourceTargetMapperAndBar2Factory INSTANCE =
Mappers.getMapper( SourceTargetMapperAndBar2Factory.class );
public abstract Target sourceToTarget(Source source);
public abstract Bar1 foo1ToBar1(Foo1 foo1);
public abstract Bar2 foo1ToBar1(Foo2 foo2);
public Bar2 createBar2() {
return new Bar2("BAR2");
}
}

View File

@ -0,0 +1,49 @@
/**
* 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;
/**
* @author Sjaak Derksen
*
*/
public class Target {
private Bar1 prop1;
private Bar2 prop2;
public Bar1 getProp1() {
return prop1;
}
public void setProp1(Bar1 prop1) {
this.prop1 = prop1;
}
public Bar2 getProp2() {
return prop2;
}
public void setProp2( Bar2 prop2 ) {
this.prop2 = prop2;
}
}