From 502780c44110ec05930328cbf92a03c2a281b32e Mon Sep 17 00:00:00 2001 From: Gunnar Morling Date: Sat, 29 Jun 2013 13:39:21 +0200 Subject: [PATCH] #32 Support for CDI-based mapper implementations --- core/src/main/java/org/mapstruct/Mapper.java | 15 +++++ integrationtest/pom.xml | 21 +++++++ .../java/org/mapstruct/itest/cdi/Source.java | 37 +++++++++++ .../itest/cdi/SourceTargetMapper.java | 28 +++++++++ .../java/org/mapstruct/itest/cdi/Target.java | 42 +++++++++++++ .../mapstruct/itest/cdi/other/DateMapper.java | 41 +++++++++++++ .../itest/cdi/CdiBasedMapperTest.java | 61 +++++++++++++++++++ parent/pom.xml | 38 ++++++++++++ .../org/mapstruct/ap/MappingProcessor.java | 2 + .../ap/model/AbstractModelElement.java | 2 +- .../org/mapstruct/ap/model/Annotation.java | 41 +++++++++++++ .../mapstruct/ap/model/BeanMappingMethod.java | 7 +-- .../ap/model/CdiMapperReference.java | 49 +++++++++++++++ .../ap/model/DefaultMapperReference.java | 49 +++++++++++++++ .../java/org/mapstruct/ap/model/Mapper.java | 49 +++++++++------ .../mapstruct/ap/model/MapperReference.java | 30 +++++++++ .../org/mapstruct/ap/model/MappingMethod.java | 3 +- .../org/mapstruct/ap/model/ModelElement.java | 10 +++ .../mapstruct/ap/model/PropertyMapping.java | 9 +++ .../ap/processor/CdiComponentProcessor.java | 59 ++++++++++++++++++ .../ap/processor/MapperCreationProcessor.java | 22 ++++--- .../org/mapstruct/ap/util/Collections.java | 43 +++++++++++++ .../org.mapstruct.ap.model.Annotation.ftl | 21 +++++++ ....mapstruct.ap.model.CdiMapperReference.ftl | 22 +++++++ ...struct.ap.model.DefaultMapperReference.ftl | 21 +++++++ .../org.mapstruct.ap.model.Mapper.ftl | 9 ++- .../mapstruct/ap/test/complex/CarMapper.java | 1 + .../ap/test/complex/CarMapperTest.java | 1 + .../test/complex/{ => other}/DateMapper.java | 2 +- 29 files changed, 699 insertions(+), 36 deletions(-) create mode 100644 integrationtest/src/main/java/org/mapstruct/itest/cdi/Source.java create mode 100644 integrationtest/src/main/java/org/mapstruct/itest/cdi/SourceTargetMapper.java create mode 100644 integrationtest/src/main/java/org/mapstruct/itest/cdi/Target.java create mode 100644 integrationtest/src/main/java/org/mapstruct/itest/cdi/other/DateMapper.java create mode 100644 integrationtest/src/test/java/org/mapstruct/itest/cdi/CdiBasedMapperTest.java create mode 100644 processor/src/main/java/org/mapstruct/ap/model/Annotation.java create mode 100644 processor/src/main/java/org/mapstruct/ap/model/CdiMapperReference.java create mode 100644 processor/src/main/java/org/mapstruct/ap/model/DefaultMapperReference.java create mode 100644 processor/src/main/java/org/mapstruct/ap/model/MapperReference.java create mode 100644 processor/src/main/java/org/mapstruct/ap/processor/CdiComponentProcessor.java create mode 100644 processor/src/main/java/org/mapstruct/ap/util/Collections.java create mode 100644 processor/src/main/resources/org.mapstruct.ap.model.Annotation.ftl create mode 100644 processor/src/main/resources/org.mapstruct.ap.model.CdiMapperReference.ftl create mode 100644 processor/src/main/resources/org.mapstruct.ap.model.DefaultMapperReference.ftl rename processor/src/test/java/org/mapstruct/ap/test/complex/{ => other}/DateMapper.java (96%) diff --git a/core/src/main/java/org/mapstruct/Mapper.java b/core/src/main/java/org/mapstruct/Mapper.java index 39d111aa6..8d438d261 100644 --- a/core/src/main/java/org/mapstruct/Mapper.java +++ b/core/src/main/java/org/mapstruct/Mapper.java @@ -47,4 +47,19 @@ public @interface Mapper { * @return The reporting policy for unmapped target properties. */ ReportingPolicy unmappedTargetPolicy() default ReportingPolicy.WARN; + + /** + * Specifies the component model to which the generated mapper should + * adhere. Supported values are + * + * + * @return The component model for the generated mapper. + */ + String componentModel() default "default"; } diff --git a/integrationtest/pom.xml b/integrationtest/pom.xml index 67875b954..3a320144f 100644 --- a/integrationtest/pom.xml +++ b/integrationtest/pom.xml @@ -39,6 +39,7 @@ mapstruct provided + org.testng testng @@ -49,6 +50,26 @@ fest-assert test + + + javax.enterprise + cdi-api + + + org.jboss.arquillian.testng + arquillian-testng-container + test + + + org.jboss.arquillian.container + arquillian-weld-se-embedded-1.1 + test + + + org.jboss.weld + weld-core + test + diff --git a/integrationtest/src/main/java/org/mapstruct/itest/cdi/Source.java b/integrationtest/src/main/java/org/mapstruct/itest/cdi/Source.java new file mode 100644 index 000000000..01e34c7ad --- /dev/null +++ b/integrationtest/src/main/java/org/mapstruct/itest/cdi/Source.java @@ -0,0 +1,37 @@ +/** + * Copyright 2012-2013 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.itest.cdi; + +import java.util.Date; +import java.util.GregorianCalendar; + +public class Source { + + private int foo = 42; + + private Date date = new GregorianCalendar( 1980, 0, 1 ).getTime(); + + public int getFoo() { + return foo; + } + + public Date getDate() { + return date; + } +} diff --git a/integrationtest/src/main/java/org/mapstruct/itest/cdi/SourceTargetMapper.java b/integrationtest/src/main/java/org/mapstruct/itest/cdi/SourceTargetMapper.java new file mode 100644 index 000000000..a9453f703 --- /dev/null +++ b/integrationtest/src/main/java/org/mapstruct/itest/cdi/SourceTargetMapper.java @@ -0,0 +1,28 @@ +/** + * Copyright 2012-2013 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.itest.cdi; + +import org.mapstruct.Mapper; +import org.mapstruct.itest.cdi.other.DateMapper; + +@Mapper(componentModel = "cdi", uses = DateMapper.class) +public interface SourceTargetMapper { + + Target sourceToTarget(Source source); +} diff --git a/integrationtest/src/main/java/org/mapstruct/itest/cdi/Target.java b/integrationtest/src/main/java/org/mapstruct/itest/cdi/Target.java new file mode 100644 index 000000000..b40dfb5ea --- /dev/null +++ b/integrationtest/src/main/java/org/mapstruct/itest/cdi/Target.java @@ -0,0 +1,42 @@ +/** + * Copyright 2012-2013 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.itest.cdi; + +public class Target { + + private Long foo; + + private String date; + + public void setFoo(Long foo) { + this.foo = foo; + } + + public Long getFoo() { + return foo; + } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } +} diff --git a/integrationtest/src/main/java/org/mapstruct/itest/cdi/other/DateMapper.java b/integrationtest/src/main/java/org/mapstruct/itest/cdi/other/DateMapper.java new file mode 100644 index 000000000..b1d89d201 --- /dev/null +++ b/integrationtest/src/main/java/org/mapstruct/itest/cdi/other/DateMapper.java @@ -0,0 +1,41 @@ +/** + * Copyright 2012-2013 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.itest.cdi.other; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import javax.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class DateMapper { + + public String asString(Date date) { + return date != null ? new SimpleDateFormat( "yyyy" ).format( date ) : null; + } + + public Date asDate(String date) { + try { + return date != null ? new SimpleDateFormat( "yyyy" ).parse( date ) : null; + } + catch ( ParseException e ) { + throw new RuntimeException( e ); + } + } +} diff --git a/integrationtest/src/test/java/org/mapstruct/itest/cdi/CdiBasedMapperTest.java b/integrationtest/src/test/java/org/mapstruct/itest/cdi/CdiBasedMapperTest.java new file mode 100644 index 000000000..761b88620 --- /dev/null +++ b/integrationtest/src/test/java/org/mapstruct/itest/cdi/CdiBasedMapperTest.java @@ -0,0 +1,61 @@ +/** + * Copyright 2012-2013 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.itest.cdi; + +import javax.inject.Inject; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.testng.Arquillian; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.mapstruct.itest.cdi.other.DateMapper; +import org.testng.annotations.Test; + +import static org.fest.assertions.Assertions.assertThat; + +/** + * Test for generation of CDI-based mapper implementations. + * + * @author Gunnar Morling + */ +public class CdiBasedMapperTest extends Arquillian { + + @Inject + private SourceTargetMapper mapper; + + @Deployment + public static JavaArchive createDeployment() { + return ShrinkWrap.create( JavaArchive.class ) + .addPackage( SourceTargetMapper.class.getPackage() ) + .addPackage( DateMapper.class.getPackage() ) + .addAsManifestResource( EmptyAsset.INSTANCE, "beans.xml" ); + } + + @Test + public void shouldCreateCdiBasedMapper() { + Source source = new Source(); + + Target target = mapper.sourceToTarget( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 42 ) ); + assertThat( target.getDate() ).isEqualTo( "1980" ); + } +} diff --git a/parent/pom.xml b/parent/pom.xml index 362fe8248..6583c9373 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -117,6 +117,32 @@ hickory ${com.jolira.hickory.version} + + + + javax.enterprise + cdi-api + 1.1-PFD + + + org.jboss.arquillian + arquillian-bom + 1.0.4.Final + import + pom + + + org.jboss.arquillian.container + arquillian-weld-se-embedded-1.1 + 1.0.0.CR3 + + + org.jboss.weld + weld-core + 1.1.5.Final + + + ${project.groupId} mapstruct @@ -127,6 +153,18 @@ mapstruct-processor ${project.version} + + + + org.slf4j + slf4j-api + 1.6.1 + + + ch.qos.cal10n + cal10n-api + 0.7.4 + diff --git a/processor/src/main/java/org/mapstruct/ap/MappingProcessor.java b/processor/src/main/java/org/mapstruct/ap/MappingProcessor.java index e3f42776a..81886f1ea 100644 --- a/processor/src/main/java/org/mapstruct/ap/MappingProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/MappingProcessor.java @@ -39,6 +39,7 @@ import org.mapstruct.Mappings; import org.mapstruct.ap.model.Mapper; import org.mapstruct.ap.model.Options; import org.mapstruct.ap.model.ReportingPolicy; +import org.mapstruct.ap.processor.CdiComponentProcessor; import org.mapstruct.ap.processor.DefaultModelElementProcessorContext; import org.mapstruct.ap.processor.MapperCreationProcessor; import org.mapstruct.ap.processor.MapperRenderingProcessor; @@ -146,6 +147,7 @@ public class MappingProcessor extends AbstractProcessor { return Arrays.>asList( new MethodRetrievalProcessor(), new MapperCreationProcessor(), + new CdiComponentProcessor(), new MapperRenderingProcessor() ); } diff --git a/processor/src/main/java/org/mapstruct/ap/model/AbstractModelElement.java b/processor/src/main/java/org/mapstruct/ap/model/AbstractModelElement.java index 596c603f5..9bfeff754 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/AbstractModelElement.java +++ b/processor/src/main/java/org/mapstruct/ap/model/AbstractModelElement.java @@ -30,7 +30,7 @@ import org.mapstruct.ap.writer.FreeMarkerModelElementWriter; * * @author Gunnar Morling */ -public class AbstractModelElement implements ModelElement { +public abstract class AbstractModelElement implements ModelElement { @Override public void write(Context context, Writer writer) throws Exception { diff --git a/processor/src/main/java/org/mapstruct/ap/model/Annotation.java b/processor/src/main/java/org/mapstruct/ap/model/Annotation.java new file mode 100644 index 000000000..3d1fad1b3 --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/model/Annotation.java @@ -0,0 +1,41 @@ +/** + * Copyright 2012-2013 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.util.Set; + +import org.mapstruct.ap.util.Collections; + +public class Annotation extends AbstractModelElement { + + private Type type; + + public Annotation(Type type) { + this.type = type; + } + + public Type getType() { + return type; + } + + @Override + public Set getImportTypes() { + return Collections.asSet( type ); + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java index 619ac6e82..1cd7134c9 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java @@ -43,12 +43,11 @@ public class BeanMappingMethod extends MappingMethod { } @Override - public Set getReferencedTypes() { - Set types = super.getReferencedTypes(); + public Set getImportTypes() { + Set types = super.getImportTypes(); for ( PropertyMapping propertyMapping : propertyMappings ) { - types.add( propertyMapping.getSourceType() ); - types.add( propertyMapping.getTargetType() ); + types.addAll( propertyMapping.getImportTypes() ); } return types; diff --git a/processor/src/main/java/org/mapstruct/ap/model/CdiMapperReference.java b/processor/src/main/java/org/mapstruct/ap/model/CdiMapperReference.java new file mode 100644 index 000000000..121cde86d --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/model/CdiMapperReference.java @@ -0,0 +1,49 @@ +/** + * Copyright 2012-2013 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.util.Set; + +import org.mapstruct.ap.util.Collections; + +/** + * Mapper reference which is retrieved via CDI-based dependency injection. + * method. Used if "cdi" is specified as component model via + * {@code Mapper#uses()}. + * + * @author Gunnar Morling + */ +public class CdiMapperReference extends AbstractModelElement implements MapperReference { + + private Type type; + + public CdiMapperReference(Type type) { + this.type = type; + } + + @Override + public Type getMapperType() { + return type; + } + + @Override + public Set getImportTypes() { + return Collections.asSet( type, new Type( "javax.inject", "Inject" ) ); + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/model/DefaultMapperReference.java b/processor/src/main/java/org/mapstruct/ap/model/DefaultMapperReference.java new file mode 100644 index 000000000..42c053d21 --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/model/DefaultMapperReference.java @@ -0,0 +1,49 @@ +/** + * Copyright 2012-2013 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.util.Set; + +import org.mapstruct.ap.util.Collections; + +/** + * Mapper reference which is retrieved via the {@code Mappers#getMapper()} + * method. Used by default if no other component model is specified via + * {@code Mapper#uses()}. + * + * @author Gunnar Morling + */ +public class DefaultMapperReference extends AbstractModelElement implements MapperReference { + + private Type type; + + public DefaultMapperReference(Type type) { + this.type = type; + } + + @Override + public Type getMapperType() { + return type; + } + + @Override + public Set getImportTypes() { + return Collections.asSet( type ); + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/model/Mapper.java b/processor/src/main/java/org/mapstruct/ap/model/Mapper.java index d330504b1..103884325 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/Mapper.java +++ b/processor/src/main/java/org/mapstruct/ap/model/Mapper.java @@ -18,6 +18,7 @@ */ package org.mapstruct.ap.model; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.SortedSet; @@ -29,36 +30,46 @@ public class Mapper extends AbstractModelElement { private final String packageName; private final String interfaceName; private final String implementationName; + private final List annotations; private final List mappingMethods; - private final List usedMapperTypes; + private final List referencedMappers; private final Options options; - private final SortedSet importedTypes; private final boolean isErroneous; - public Mapper(String packageName, String interfaceName, - String implementationName, List mappingMethods, List usedMapperTypes, - Options options, boolean isErroneous) { + public Mapper(String packageName, String interfaceName, String implementationName, + List mappingMethods, List referencedMappers, Options options, + boolean isErroneous) { this.packageName = packageName; this.interfaceName = interfaceName; this.implementationName = implementationName; + this.annotations = new ArrayList(); this.mappingMethods = mappingMethods; - this.usedMapperTypes = usedMapperTypes; + this.referencedMappers = referencedMappers; this.options = options; - this.importedTypes = determineImportedTypes(); this.isErroneous = isErroneous; } - private SortedSet determineImportedTypes() { + @Override + public SortedSet getImportTypes() { SortedSet importedTypes = new TreeSet(); importedTypes.add( Type.forClass( Generated.class ) ); for ( MappingMethod mappingMethod : mappingMethods ) { - - for ( Type type : mappingMethod.getReferencedTypes() ) { + for ( Type type : mappingMethod.getImportTypes() ) { addWithDependents( importedTypes, type ); } } + for ( MapperReference mapperReference : referencedMappers ) { + for ( Type type : mapperReference.getImportTypes() ) { + addWithDependents( importedTypes, type ); + } + } + + for ( Annotation annotation : annotations ) { + addWithDependents( importedTypes, annotation.getType() ); + } + return importedTypes; } @@ -91,7 +102,7 @@ public class Mapper extends AbstractModelElement { sb.append( "\n " + beanMapping.toString().replaceAll( "\n", "\n " ) ); } sb.append( "\n ]" ); - sb.append( "\n usedMapperTypes=" + usedMapperTypes ); + sb.append( "\n referencedMappers=" + referencedMappers ); sb.append( "\n}," ); return sb.toString(); @@ -113,19 +124,23 @@ public class Mapper extends AbstractModelElement { return mappingMethods; } - public List getUsedMapperTypes() { - return usedMapperTypes; + public List getReferencedMappers() { + return referencedMappers; } public Options getOptions() { return options; } - public SortedSet getImportedTypes() { - return importedTypes; - } - public boolean isErroneous() { return isErroneous; } + + public void addAnnotation(Annotation annotation) { + annotations.add( annotation ); + } + + public List getAnnotations() { + return annotations; + } } diff --git a/processor/src/main/java/org/mapstruct/ap/model/MapperReference.java b/processor/src/main/java/org/mapstruct/ap/model/MapperReference.java new file mode 100644 index 000000000..383e66a3d --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/model/MapperReference.java @@ -0,0 +1,30 @@ +/** + * Copyright 2012-2013 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; + +/** + * A reference to another mapper class, which itself may be generated or + * hand-written. + * + * @author Gunnar Morling + */ +public interface MapperReference extends ModelElement { + + Type getMapperType(); +} diff --git a/processor/src/main/java/org/mapstruct/ap/model/MappingMethod.java b/processor/src/main/java/org/mapstruct/ap/model/MappingMethod.java index 652cc3bd5..5a57d02d3 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/MappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/model/MappingMethod.java @@ -56,7 +56,8 @@ public abstract class MappingMethod extends AbstractModelElement { return targetType; } - public Set getReferencedTypes() { + @Override + public Set getImportTypes() { Set types = new HashSet(); types.add( getSourceType() ); types.add( getTargetType() ); diff --git a/processor/src/main/java/org/mapstruct/ap/model/ModelElement.java b/processor/src/main/java/org/mapstruct/ap/model/ModelElement.java index f89c1a653..fa12ff483 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/ModelElement.java +++ b/processor/src/main/java/org/mapstruct/ap/model/ModelElement.java @@ -19,6 +19,7 @@ package org.mapstruct.ap.model; import java.io.Writer; +import java.util.Set; /** * A model element with the ability to write itself into a given {@link Writer}. @@ -54,4 +55,13 @@ public interface ModelElement { * implementations. */ void write(Context context, Writer writer) throws Exception; + + /** + * Returns a set containing those {@link Type}s referenced by this model + * element for which an import statement needs to be declared. + * + * @return A set with type referenced by this model element. Must not be + * {@code null.} + */ + Set getImportTypes(); } diff --git a/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java b/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java index e33b653d2..7844e7855 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java +++ b/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java @@ -18,6 +18,10 @@ */ package org.mapstruct.ap.model; +import java.util.Set; + +import org.mapstruct.ap.util.Collections; + /** * Represents the mapping between a source and target property, e.g. from * {@code String Source#foo} to {@code int Target#bar}. Name and type of source @@ -100,6 +104,11 @@ public class PropertyMapping extends AbstractModelElement { return conversion; } + @Override + public Set getImportTypes() { + return Collections.asSet( sourceType, targetType ); + } + @Override public String toString() { return "PropertyMapping {" + diff --git a/processor/src/main/java/org/mapstruct/ap/processor/CdiComponentProcessor.java b/processor/src/main/java/org/mapstruct/ap/processor/CdiComponentProcessor.java new file mode 100644 index 000000000..39577fdda --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/processor/CdiComponentProcessor.java @@ -0,0 +1,59 @@ +/** + * Copyright 2012-2013 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.processor; + +import java.util.ListIterator; +import javax.lang.model.element.TypeElement; + +import org.mapstruct.ap.MapperPrism; +import org.mapstruct.ap.model.Annotation; +import org.mapstruct.ap.model.CdiMapperReference; +import org.mapstruct.ap.model.Mapper; +import org.mapstruct.ap.model.MapperReference; +import org.mapstruct.ap.model.Type; + +/** + * A {@link ModelElementProcessor} which converts the given {@link Mapper} + * object into an application-scoped CDI bean in case CDI is configured as the + * target component model for this mapper. + * + * @author Gunnar Morling + */ +public class CdiComponentProcessor implements ModelElementProcessor { + + @Override + public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, Mapper mapper) { + String componentModel = MapperPrism.getInstanceOn( mapperTypeElement ).componentModel(); + + if ( !componentModel.equals( "cdi" ) ) { + return mapper; + } + + mapper.addAnnotation( new Annotation( new Type( "javax.enterprise.context", "ApplicationScoped" ) ) ); + + ListIterator iterator = mapper.getReferencedMappers().listIterator(); + while ( iterator.hasNext() ) { + MapperReference reference = iterator.next(); + iterator.remove(); + iterator.add( new CdiMapperReference( reference.getMapperType() ) ); + } + + return mapper; + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java b/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java index 185012996..82380ab7e 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java @@ -41,8 +41,10 @@ import org.mapstruct.ap.MapperPrism; import org.mapstruct.ap.conversion.Conversion; import org.mapstruct.ap.conversion.Conversions; import org.mapstruct.ap.model.BeanMappingMethod; +import org.mapstruct.ap.model.DefaultMapperReference; import org.mapstruct.ap.model.IterableMappingMethod; import org.mapstruct.ap.model.Mapper; +import org.mapstruct.ap.model.MapperReference; import org.mapstruct.ap.model.MappingMethod; import org.mapstruct.ap.model.MappingMethodReference; import org.mapstruct.ap.model.Options; @@ -91,17 +93,17 @@ public class MapperCreationProcessor implements ModelElementProcessor methods) { - List usedMapperTypes = getUsedMapperTypes( element ); - + private Mapper getMapper(TypeElement element, List methods) { ReportingPolicy unmappedTargetPolicy = getEffectiveUnmappedTargetPolicy( element ); + List mappingMethods = getMappingMethods( methods, unmappedTargetPolicy ); + List mapperReferences = getReferencedMappers( element ); return new Mapper( elementUtils.getPackageOf( element ).getQualifiedName().toString(), element.getSimpleName().toString(), element.getSimpleName() + IMPLEMENTATION_SUFFIX, - getMappingMethods( methods, unmappedTargetPolicy ), - usedMapperTypes, + mappingMethods, + mapperReferences, options, isErroneous ); @@ -132,13 +134,15 @@ public class MapperCreationProcessor implements ModelElementProcessor getUsedMapperTypes(TypeElement element) { - List usedMapperTypes = new LinkedList(); + private List getReferencedMappers(TypeElement element) { + List mapperReferences = new LinkedList(); MapperPrism mapperPrism = MapperPrism.getInstanceOn( element ); + for ( TypeMirror usedMapper : mapperPrism.uses() ) { - usedMapperTypes.add( typeUtil.retrieveType( usedMapper ) ); + mapperReferences.add( new DefaultMapperReference( typeUtil.retrieveType( usedMapper ) ) ); } - return usedMapperTypes; + + return mapperReferences; } private List getMappingMethods(List methods, ReportingPolicy unmappedTargetPolicy) { diff --git a/processor/src/main/java/org/mapstruct/ap/util/Collections.java b/processor/src/main/java/org/mapstruct/ap/util/Collections.java new file mode 100644 index 000000000..4821660f4 --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/util/Collections.java @@ -0,0 +1,43 @@ +/** + * Copyright 2012-2013 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.util; + +import java.util.HashSet; +import java.util.Set; + +/** + * Provides utility methods around collections. + * + * @author Gunnar Morling + */ +public class Collections { + + private Collections() { + } + + public static Set asSet(T... elements) { + Set set = new HashSet(); + + for ( T element : elements ) { + set.add( element ); + } + + return set; + } +} diff --git a/processor/src/main/resources/org.mapstruct.ap.model.Annotation.ftl b/processor/src/main/resources/org.mapstruct.ap.model.Annotation.ftl new file mode 100644 index 000000000..a32b62b77 --- /dev/null +++ b/processor/src/main/resources/org.mapstruct.ap.model.Annotation.ftl @@ -0,0 +1,21 @@ +<#-- + + Copyright 2012-2013 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. + +--> +@${type.name} diff --git a/processor/src/main/resources/org.mapstruct.ap.model.CdiMapperReference.ftl b/processor/src/main/resources/org.mapstruct.ap.model.CdiMapperReference.ftl new file mode 100644 index 000000000..72f7427b9 --- /dev/null +++ b/processor/src/main/resources/org.mapstruct.ap.model.CdiMapperReference.ftl @@ -0,0 +1,22 @@ +<#-- + + Copyright 2012-2013 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. + +--> + @Inject + private ${mapperType.name} ${mapperType.name?uncap_first}; \ No newline at end of file diff --git a/processor/src/main/resources/org.mapstruct.ap.model.DefaultMapperReference.ftl b/processor/src/main/resources/org.mapstruct.ap.model.DefaultMapperReference.ftl new file mode 100644 index 000000000..5c8a8bde7 --- /dev/null +++ b/processor/src/main/resources/org.mapstruct.ap.model.DefaultMapperReference.ftl @@ -0,0 +1,21 @@ +<#-- + + Copyright 2012-2013 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. + +--> + private final ${mapperType.name} ${mapperType.name?uncap_first} = new ${mapperType.name}(); \ No newline at end of file diff --git a/processor/src/main/resources/org.mapstruct.ap.model.Mapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.Mapper.ftl index b5f90d200..797d74cff 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.Mapper.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.Mapper.ftl @@ -20,7 +20,7 @@ --> package ${packageName}; -<#list importedTypes as importedType> +<#list importTypes as importedType> import ${importedType.fullyQualifiedName}; @@ -28,10 +28,13 @@ import ${importedType.fullyQualifiedName}; value = "org.mapstruct.ap.MappingProcessor"<#if options.suppressGeneratorTimestamp == false>, date = "${.now?string("yyyy-MM-dd'T'HH:mm:ssZ")}" ) +<#list annotations as annotation> +<@includeModel object=annotation/> + public class ${implementationName} implements ${interfaceName} { -<#list usedMapperTypes as mapperType> - private final ${mapperType.name} ${mapperType.name?uncap_first} = new ${mapperType.name}(); +<#list referencedMappers as mapper> + <@includeModel object=mapper/> <#list mappingMethods as mappingMethod> diff --git a/processor/src/test/java/org/mapstruct/ap/test/complex/CarMapper.java b/processor/src/test/java/org/mapstruct/ap/test/complex/CarMapper.java index 394124289..e354fd215 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/complex/CarMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/complex/CarMapper.java @@ -24,6 +24,7 @@ import org.mapstruct.Mapper; import org.mapstruct.Mappers; import org.mapstruct.Mapping; import org.mapstruct.Mappings; +import org.mapstruct.ap.test.complex.other.DateMapper; import org.mapstruct.ap.test.complex.source.Car; import org.mapstruct.ap.test.complex.source.Person; import org.mapstruct.ap.test.complex.target.CarDto; diff --git a/processor/src/test/java/org/mapstruct/ap/test/complex/CarMapperTest.java b/processor/src/test/java/org/mapstruct/ap/test/complex/CarMapperTest.java index 56df15c3d..ee28e8a93 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/complex/CarMapperTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/complex/CarMapperTest.java @@ -23,6 +23,7 @@ import java.util.Arrays; import java.util.GregorianCalendar; import java.util.List; +import org.mapstruct.ap.test.complex.other.DateMapper; import org.mapstruct.ap.test.complex.source.Car; import org.mapstruct.ap.test.complex.source.Category; import org.mapstruct.ap.test.complex.source.Person; diff --git a/processor/src/test/java/org/mapstruct/ap/test/complex/DateMapper.java b/processor/src/test/java/org/mapstruct/ap/test/complex/other/DateMapper.java similarity index 96% rename from processor/src/test/java/org/mapstruct/ap/test/complex/DateMapper.java rename to processor/src/test/java/org/mapstruct/ap/test/complex/other/DateMapper.java index a5594bce2..78370585d 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/complex/DateMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/complex/other/DateMapper.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.mapstruct.ap.test.complex; +package org.mapstruct.ap.test.complex.other; import java.text.ParseException; import java.text.SimpleDateFormat;