diff --git a/core-common/src/main/java/org/mapstruct/Mapper.java b/core-common/src/main/java/org/mapstruct/Mapper.java index b7b992c87..20ccbfc4f 100644 --- a/core-common/src/main/java/org/mapstruct/Mapper.java +++ b/core-common/src/main/java/org/mapstruct/Mapper.java @@ -84,6 +84,28 @@ public @interface Mapper { */ String componentModel() default "default"; + /** + * Specifies the name of the implementation class. The {@code } will be replaced by the + * interface/abstract class name. + *

+ * Defaults to postfixing the name with {@code Impl}: {@code Impl} + * + * @return The implementation name. + * @see #implementationPackage() + */ + String implementationName() default "Impl"; + + /** + * Specifies the target package for the generated implementation. The {@code } will be replaced + * by the interface's or abstract class' package. + *

+ * Defaults to using the same package as the mapper interface/abstract class + * + * @return the implementation package. + * @see #implementationName() + */ + String implementationPackage() default ""; + /** * A class annotated with {@link MapperConfig} which should be used as configuration template. Any settings given * via {@link Mapper} will take precedence over the settings from the referenced configuration source. The list of diff --git a/core-common/src/main/java/org/mapstruct/MapperConfig.java b/core-common/src/main/java/org/mapstruct/MapperConfig.java index 3cee92c29..cbbedeacf 100644 --- a/core-common/src/main/java/org/mapstruct/MapperConfig.java +++ b/core-common/src/main/java/org/mapstruct/MapperConfig.java @@ -84,6 +84,28 @@ public @interface MapperConfig { */ String componentModel() default "default"; + /** + * Specifies the name of the implementation class. The {@code } will be replaced by the + * interface/abstract class name. + *

+ * Defaults to postfixing the name with {@code Impl}: {@code Impl} + * + * @return The implementation name. + * @see #implementationPackage() + */ + String implementationName() default "Impl"; + + /** + * Specifies the target package for the generated implementation. The {@code } will be replaced + * by the interface's or abstract class' package. + *

+ * Defaults to using the same package as the mapper interface/abstract class + * + * @return the implementation package. + * @see #implementationName() + */ + String implementationPackage() default ""; + /** * The strategy to be applied when propagating the value of collection-typed properties. By default, only JavaBeans * accessor methods (setters or getters) will be used, but it is also possible to invoke a corresponding adder diff --git a/core-common/src/main/java/org/mapstruct/factory/Mappers.java b/core-common/src/main/java/org/mapstruct/factory/Mappers.java index 7afe79a9f..ab87cf1e5 100644 --- a/core-common/src/main/java/org/mapstruct/factory/Mappers.java +++ b/core-common/src/main/java/org/mapstruct/factory/Mappers.java @@ -20,6 +20,8 @@ package org.mapstruct.factory; import org.mapstruct.Mapper; +import java.util.ServiceLoader; + /** * Factory for obtaining mapper instances if no explicit component model such as CDI is configured via * {@link Mapper#componentModel()}. @@ -73,10 +75,24 @@ public class Mappers { classLoader = Mappers.class.getClassLoader(); } - @SuppressWarnings("unchecked") - T mapper = (T) classLoader.loadClass( clazz.getName() + IMPLEMENTATION_SUFFIX ).newInstance(); + try { + @SuppressWarnings("unchecked") + T mapper = (T) classLoader.loadClass( clazz.getName() + IMPLEMENTATION_SUFFIX ).newInstance(); + return mapper; + } + catch (ClassNotFoundException e) { + ServiceLoader loader = ServiceLoader.load( clazz, classLoader ); - return mapper; + if ( loader != null ) { + for ( T mapper : loader ) { + if ( mapper != null ) { + return mapper; + } + } + } + + throw new ClassNotFoundException("Cannot find implementation for " + clazz.getName()); + } } catch ( Exception e ) { throw new RuntimeException( e ); diff --git a/core-common/src/test/java/org/mapstruct/MappersTest.java b/core-common/src/test/java/org/mapstruct/factory/MappersTest.java similarity index 95% rename from core-common/src/test/java/org/mapstruct/MappersTest.java rename to core-common/src/test/java/org/mapstruct/factory/MappersTest.java index 1860f68a3..c6df4703e 100644 --- a/core-common/src/test/java/org/mapstruct/MappersTest.java +++ b/core-common/src/test/java/org/mapstruct/factory/MappersTest.java @@ -16,12 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.mapstruct; +package org.mapstruct.factory; import static org.fest.assertions.Assertions.assertThat; import org.junit.Test; -import org.mapstruct.factory.Mappers; import org.mapstruct.test.model.Foo; /** diff --git a/processor/src/main/java/org/mapstruct/ap/MappingProcessor.java b/processor/src/main/java/org/mapstruct/ap/MappingProcessor.java index 2aac44df2..12cddbf9a 100644 --- a/processor/src/main/java/org/mapstruct/ap/MappingProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/MappingProcessor.java @@ -101,6 +101,7 @@ public class MappingProcessor extends AbstractProcessor { "mapstruct.suppressGeneratorVersionInfoComment"; protected static final String UNMAPPED_TARGET_POLICY = "mapstruct.unmappedTargetPolicy"; protected static final String DEFAULT_COMPONENT_MODEL = "mapstruct.defaultComponentModel"; + protected static final String ALWAYS_GENERATE_SERVICE_FILE = "mapstruct.alwaysGenerateServicesFile"; private Options options; @@ -113,12 +114,14 @@ public class MappingProcessor extends AbstractProcessor { private Options createOptions() { String unmappedTargetPolicy = processingEnv.getOptions().get( UNMAPPED_TARGET_POLICY ); + String defaultComponentModel = processingEnv.getOptions().get( DEFAULT_COMPONENT_MODEL ); return new Options( Boolean.valueOf( processingEnv.getOptions().get( SUPPRESS_GENERATOR_TIMESTAMP ) ), Boolean.valueOf( processingEnv.getOptions().get( SUPPRESS_GENERATOR_VERSION_INFO_COMMENT ) ), unmappedTargetPolicy != null ? ReportingPolicy.valueOf( unmappedTargetPolicy ) : null, - processingEnv.getOptions().get( DEFAULT_COMPONENT_MODEL ) + defaultComponentModel == null ? "default" : defaultComponentModel, + Boolean.valueOf( processingEnv.getOptions().get( ALWAYS_GENERATE_SERVICE_FILE ) ) ); } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/Decorator.java b/processor/src/main/java/org/mapstruct/ap/internal/model/Decorator.java index 58adb44df..454b9b600 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/Decorator.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/Decorator.java @@ -18,15 +18,6 @@ */ package org.mapstruct.ap.internal.model; -import java.util.Arrays; -import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; - -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; - import org.mapstruct.ap.internal.model.common.Accessibility; import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.TypeFactory; @@ -34,6 +25,13 @@ import org.mapstruct.ap.internal.option.Options; import org.mapstruct.ap.internal.prism.DecoratedWithPrism; import org.mapstruct.ap.internal.version.VersionInformation; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; +import java.util.Arrays; +import java.util.List; +import java.util.SortedSet; + /** * Represents a decorator applied to a generated mapper type. * @@ -41,8 +39,6 @@ import org.mapstruct.ap.internal.version.VersionInformation; */ public class Decorator extends GeneratedType { - private static final String IMPLEMENTATION_SUFFIX = "Impl"; - public static class Builder { private Elements elementUtils; @@ -53,6 +49,9 @@ public class Decorator extends GeneratedType { private Options options; private VersionInformation versionInformation; private boolean hasDelegateConstructor; + private String implName; + private String implPackage; + private SortedSet extraImportedTypes; public Builder elementUtils(Elements elementUtils) { this.elementUtils = elementUtils; @@ -94,25 +93,48 @@ public class Decorator extends GeneratedType { return this; } + public Builder implName(String implName) { + this.implName = "default".equals( implName ) ? Mapper.DEFAULT_IMPLEMENTATION_CLASS : implName; + return this; + } + + public Builder implPackage(String implPackage) { + this.implPackage = "default".equals( implPackage ) ? Mapper.DEFAULT_IMPLEMENTATION_PACKAGE : implPackage; + return this; + } + + public Builder extraImports(SortedSet extraImportedTypes) { + this.extraImportedTypes = extraImportedTypes; + return this; + } + public Decorator build() { + String implementationName = implName.replace( Mapper.CLASS_NAME_PLACEHOLDER, + mapperElement.getSimpleName() ); + Type decoratorType = typeFactory.getType( decoratorPrism.value() ); DecoratorConstructor decoratorConstructor = new DecoratorConstructor( - mapperElement.getSimpleName().toString() + IMPLEMENTATION_SUFFIX, - mapperElement.getSimpleName().toString() + "Impl_", + implementationName, + implementationName + "_", hasDelegateConstructor ); + String elementPackage = elementUtils.getPackageOf( mapperElement ).getQualifiedName().toString(); + String packageName = implPackage.replace( Mapper.PACKAGE_NAME_PLACEHOLDER, elementPackage ); + return new Decorator( typeFactory, - elementUtils.getPackageOf( mapperElement ).getQualifiedName().toString(), - mapperElement.getSimpleName().toString() + IMPLEMENTATION_SUFFIX, + packageName, + implementationName, decoratorType, + elementPackage, mapperElement.getKind() == ElementKind.INTERFACE ? mapperElement.getSimpleName().toString() : null, methods, Arrays.asList( new Field( typeFactory.getType( mapperElement ), "delegate", true ) ) , options, versionInformation, Accessibility.fromModifiers( mapperElement.getModifiers() ), + extraImportedTypes, decoratorConstructor ); } @@ -122,21 +144,23 @@ public class Decorator extends GeneratedType { @SuppressWarnings( "checkstyle:parameternumber" ) private Decorator(TypeFactory typeFactory, String packageName, String name, Type decoratorType, - String interfaceName, List methods, List fields, - Options options, VersionInformation versionInformation, Accessibility accessibility, - DecoratorConstructor decoratorConstructor) { + String interfacePackage, String interfaceName, List methods, + List fields, Options options, VersionInformation versionInformation, + Accessibility accessibility, SortedSet extraImports, + DecoratorConstructor decoratorConstructor) { super( typeFactory, packageName, name, decoratorType.getName(), + interfacePackage, interfaceName, methods, fields, options, versionInformation, accessibility, - new TreeSet(), + extraImports, decoratorConstructor ); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/GeneratedType.java b/processor/src/main/java/org/mapstruct/ap/internal/model/GeneratedType.java index 4d9e0c88d..e09386322 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/GeneratedType.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/GeneratedType.java @@ -45,6 +45,7 @@ public abstract class GeneratedType extends ModelElement { private final String packageName; private final String name; private final String superClassName; + private final String interfacePackage; private final String interfaceName; private final List annotations; @@ -65,7 +66,7 @@ public abstract class GeneratedType extends ModelElement { // CHECKSTYLE:OFF protected GeneratedType(TypeFactory typeFactory, String packageName, String name, String superClassName, - String interfaceName, + String interfacePackage, String interfaceName, List methods, List fields, Options options, @@ -76,6 +77,7 @@ public abstract class GeneratedType extends ModelElement { this.packageName = packageName; this.name = name; this.superClassName = superClassName; + this.interfacePackage = interfacePackage; this.interfaceName = interfaceName; this.extraImportedTypes = extraImportedTypes; @@ -106,6 +108,10 @@ public abstract class GeneratedType extends ModelElement { return superClassName; } + public String getInterfacePackage() { + return interfacePackage; + } + public String getInterfaceName() { return interfaceName; } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/Mapper.java b/processor/src/main/java/org/mapstruct/ap/internal/model/Mapper.java index a8a57cc32..ada616ee0 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/Mapper.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/Mapper.java @@ -39,24 +39,29 @@ import org.mapstruct.ap.internal.version.VersionInformation; */ public class Mapper extends GeneratedType { - private static final String IMPLEMENTATION_SUFFIX = "Impl"; - private static final String DECORATED_IMPLEMENTATION_SUFFIX = "Impl_"; + static final String CLASS_NAME_PLACEHOLDER = ""; + static final String PACKAGE_NAME_PLACEHOLDER = ""; + static final String DEFAULT_IMPLEMENTATION_CLASS = CLASS_NAME_PLACEHOLDER + "Impl"; + static final String DEFAULT_IMPLEMENTATION_PACKAGE = PACKAGE_NAME_PLACEHOLDER; + private final boolean customPackage; + private final boolean customImplName; private final List referencedMappers; private Decorator decorator; @SuppressWarnings( "checkstyle:parameternumber" ) private Mapper(TypeFactory typeFactory, String packageName, String name, String superClassName, - String interfaceName, List methods, Options options, - VersionInformation versionInformation, Accessibility accessibility, - List referencedMappers, Decorator decorator, - SortedSet extraImportedTypes ) { + String interfacePackage, String interfaceName, boolean customPackage, boolean customImplName, + List methods, Options options, VersionInformation versionInformation, + Accessibility accessibility, List referencedMappers, Decorator decorator, + SortedSet extraImportedTypes) { super( typeFactory, packageName, name, superClassName, + interfacePackage, interfaceName, methods, referencedMappers, @@ -66,6 +71,8 @@ public class Mapper extends GeneratedType { extraImportedTypes, null ); + this.customPackage = customPackage; + this.customImplName = customImplName; this.referencedMappers = referencedMappers; this.decorator = decorator; @@ -83,6 +90,10 @@ public class Mapper extends GeneratedType { private Options options; private VersionInformation versionInformation; private Decorator decorator; + private String implName; + private boolean customName; + private String implPackage; + private boolean customPackage; public Builder element(TypeElement element) { this.element = element; @@ -129,16 +140,34 @@ public class Mapper extends GeneratedType { return this; } + public Builder implName(String implName) { + this.implName = implName; + this.customName = !DEFAULT_IMPLEMENTATION_CLASS.equals( this.implName ); + return this; + } + + public Builder implPackage(String implPackage) { + this.implPackage = implPackage; + this.customPackage = !DEFAULT_IMPLEMENTATION_PACKAGE.equals( this.implPackage ); + return this; + } + public Mapper build() { - String implementationName = element.getSimpleName() - + ( decorator == null ? IMPLEMENTATION_SUFFIX : DECORATED_IMPLEMENTATION_SUFFIX ); + String implementationName = implName.replace( CLASS_NAME_PLACEHOLDER, element.getSimpleName() ) + + ( decorator == null ? "" : "_" ); + + String elementPackage = elementUtils.getPackageOf( element ).getQualifiedName().toString(); + String packageName = implPackage.replace( PACKAGE_NAME_PLACEHOLDER, elementPackage ); return new Mapper( typeFactory, - elementUtils.getPackageOf( element ).getQualifiedName().toString(), + packageName, implementationName, element.getKind() != ElementKind.INTERFACE ? element.getSimpleName().toString() : null, + elementPackage, element.getKind() == ElementKind.INTERFACE ? element.getSimpleName().toString() : null, + customPackage, + customName, mappingMethods, options, versionInformation, @@ -162,6 +191,15 @@ public class Mapper extends GeneratedType { this.decorator = null; } + /** + * Checks if the mapper has a custom implementation that is a custom suffix of an explicit destination package. + * + * @return + */ + public boolean hasCustomImplementation() { + return customImplName || customPackage; + } + @Override protected String getTemplateName() { return getTemplateNameForClass( GeneratedType.class ); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/ServicesEntry.java b/processor/src/main/java/org/mapstruct/ap/internal/model/ServicesEntry.java new file mode 100644 index 000000000..a22f053e9 --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/ServicesEntry.java @@ -0,0 +1,66 @@ +/** + * Copyright 2012-2015 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.internal.model; + +import org.mapstruct.ap.internal.model.common.ModelElement; +import org.mapstruct.ap.internal.model.common.Type; + +import java.util.Collections; +import java.util.Set; + +/** + * @author Christophe Labouisse on 14/07/2015. + */ +public class ServicesEntry extends ModelElement { + private final String packageName; + + private final String name; + + private final String implementationPackage; + + private final String implementationName; + + public ServicesEntry(String packageName, String name, String implementationPackage, String implementationName) { + this.packageName = packageName; + this.name = name; + this.implementationPackage = implementationPackage; + this.implementationName = implementationName; + } + + @Override + public Set getImportTypes() { + return Collections.emptySet(); + } + + public String getPackageName() { + return packageName; + } + + public String getName() { + return name; + } + + public String getImplementationPackage() { + return implementationPackage; + } + + public String getImplementationName() { + return implementationName; + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/internal/option/Options.java b/processor/src/main/java/org/mapstruct/ap/internal/option/Options.java index 2575864ff..3871c999e 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/option/Options.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/option/Options.java @@ -29,15 +29,17 @@ public class Options { private final boolean suppressGeneratorTimestamp; private final boolean suppressGeneratorVersionComment; private final ReportingPolicy unmappedTargetPolicy; + private final boolean alwaysGenerateSpi; private final String defaultComponentModel; public Options(boolean suppressGeneratorTimestamp, boolean suppressGeneratorVersionComment, ReportingPolicy unmappedTargetPolicy, - String defaultComponentModel) { + String defaultComponentModel, boolean alwaysGenerateSpi) { this.suppressGeneratorTimestamp = suppressGeneratorTimestamp; this.suppressGeneratorVersionComment = suppressGeneratorVersionComment; this.unmappedTargetPolicy = unmappedTargetPolicy; this.defaultComponentModel = defaultComponentModel; + this.alwaysGenerateSpi = alwaysGenerateSpi; } public boolean isSuppressGeneratorTimestamp() { @@ -55,4 +57,8 @@ public class Options { public String getDefaultComponentModel() { return defaultComponentModel; } + + public boolean isAlwaysGenerateSpi() { + return alwaysGenerateSpi; + } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java index 838f68ca9..198a26fd1 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java @@ -150,16 +150,20 @@ public class MapperCreationProcessor implements ModelElementProcessor methods) { + private Decorator getDecorator(TypeElement element, List methods, String implName, + String implPackage) { DecoratedWithPrism decoratorPrism = DecoratedWithPrism.getInstanceOn( element ); if ( decoratorPrism == null ) { @@ -219,6 +223,9 @@ public class MapperCreationProcessor implements ModelElementProcessor { +public class MapperRenderingProcessor implements ModelElementProcessor { @Override - public Void process(ProcessorContext context, TypeElement mapperTypeElement, Mapper mapper) { + public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, Mapper mapper) { if ( !context.isErroneous() ) { writeToSourceFile( context.getFiler(), mapper ); + return mapper; } return null; @@ -71,6 +72,6 @@ public class MapperRenderingProcessor implements ModelElementProcessor { + @Override + public Void process(ProcessorContext context, TypeElement mapperTypeElement, Mapper mapper) { + boolean spiGenerationNeeded; + + if ( context.getOptions().isAlwaysGenerateSpi() ) { + spiGenerationNeeded = true; + } + else { + String componentModel = MapperConfiguration.getInstanceOn( mapperTypeElement ).componentModel(); + String effectiveComponentModel = OptionsHelper.getEffectiveComponentModel( + context.getOptions(), + componentModel + ); + + spiGenerationNeeded = "default".equals( effectiveComponentModel ); + } + + if ( !context.isErroneous() && spiGenerationNeeded && mapper.hasCustomImplementation() ) { + writeToSourceFile( context.getFiler(), mapper ); + } + return null; + } + + @Override + public int getPriority() { + return 10000; + } + + private void writeToSourceFile(Filer filer, Mapper model) { + ModelWriter modelWriter = new ModelWriter(); + ServicesEntry servicesEntry = getServicesEntry( model.getDecorator() == null ? model : model.getDecorator() ); + + createSourceFile( servicesEntry, modelWriter, filer ); + } + + private ServicesEntry getServicesEntry(GeneratedType model) { + return new ServicesEntry(model.getInterfacePackage(), model.getInterfaceName(), + model.getPackageName(), model.getName()); + } + + private void createSourceFile(ServicesEntry model, ModelWriter modelWriter, Filer filer) { + String fileName = model.getPackageName() + "." + model.getName(); + + FileObject sourceFile; + try { + sourceFile = filer.createResource( StandardLocation.CLASS_OUTPUT, "", "META-INF/services/" + fileName ); + } + catch ( IOException e ) { + throw new RuntimeException( e ); + } + + modelWriter.writeModel( sourceFile, model ); + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/MapperConfiguration.java b/processor/src/main/java/org/mapstruct/ap/internal/util/MapperConfiguration.java index 045f3c6b0..e79a6fe8f 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/MapperConfiguration.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/MapperConfiguration.java @@ -18,22 +18,21 @@ */ package org.mapstruct.ap.internal.util; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; +import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism; +import org.mapstruct.ap.internal.prism.MapperConfigPrism; +import org.mapstruct.ap.internal.prism.MapperPrism; +import org.mapstruct.ap.internal.prism.MappingInheritanceStrategyPrism; +import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; - -import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism; -import org.mapstruct.ap.internal.prism.MapperConfigPrism; -import org.mapstruct.ap.internal.prism.MapperPrism; -import org.mapstruct.ap.internal.prism.MappingInheritanceStrategyPrism; -import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; /** * Provides an aggregated view to the settings given via {@link org.mapstruct.Mapper} and @@ -65,6 +64,24 @@ public class MapperConfiguration { } } + public String implementationName() { + if ( mapperConfigPrism != null && mapperPrism.values.implementationName() == null ) { + return mapperConfigPrism.implementationName(); + } + else { + return mapperPrism.implementationName(); + } + } + + public String implementationPackage() { + if ( mapperConfigPrism != null && mapperPrism.values.implementationPackage() == null ) { + return mapperConfigPrism.implementationPackage(); + } + else { + return mapperPrism.implementationPackage(); + } + } + public List uses() { Set uses = new LinkedHashSet( mapperPrism.uses() ); if ( mapperConfigPrism != null ) { diff --git a/processor/src/main/java/org/mapstruct/ap/internal/writer/ModelWriter.java b/processor/src/main/java/org/mapstruct/ap/internal/writer/ModelWriter.java index cbb75710a..28f2d3082 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/writer/ModelWriter.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/writer/ModelWriter.java @@ -29,7 +29,7 @@ import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; -import javax.tools.JavaFileObject; +import javax.tools.FileObject; import org.mapstruct.ap.internal.writer.Writable.Context; @@ -74,7 +74,7 @@ public class ModelWriter { CONFIGURATION.setLocalizedLookup( false ); } - public void writeModel(JavaFileObject sourceFile, Writable model) { + public void writeModel(FileObject sourceFile, Writable model) { try { BufferedWriter writer = new BufferedWriter( new IndentationCorrectingWriter( sourceFile.openWriter() ) ); diff --git a/processor/src/main/resources/META-INF/services/org.mapstruct.ap.internal.processor.ModelElementProcessor b/processor/src/main/resources/META-INF/services/org.mapstruct.ap.internal.processor.ModelElementProcessor index 20b315ca9..faccd7a3e 100644 --- a/processor/src/main/resources/META-INF/services/org.mapstruct.ap.internal.processor.ModelElementProcessor +++ b/processor/src/main/resources/META-INF/services/org.mapstruct.ap.internal.processor.ModelElementProcessor @@ -21,3 +21,4 @@ org.mapstruct.ap.internal.processor.MapperCreationProcessor org.mapstruct.ap.internal.processor.MapperRenderingProcessor org.mapstruct.ap.internal.processor.MethodRetrievalProcessor org.mapstruct.ap.internal.processor.SpringComponentProcessor +org.mapstruct.ap.internal.processor.MapperServiceProcessor diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/ServicesEntry.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/ServicesEntry.ftl new file mode 100644 index 000000000..007cd60ac --- /dev/null +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/ServicesEntry.ftl @@ -0,0 +1,21 @@ +<#-- + + Copyright 2012-2015 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. + +--> +${implementationPackage}.${implementationName} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapper.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapper.java new file mode 100644 index 000000000..05360810e --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapper.java @@ -0,0 +1,32 @@ +/** + * Copyright 2012-2015 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.destination; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * @author Christophe Labouisse on 27/05/2015. + */ +@Mapper(implementationName = "MyCustomImpl") +public interface DestinationClassNameMapper { + DestinationClassNameMapper INSTANCE = Mappers.getMapper( DestinationClassNameMapper.class ); + + String intToString(Integer source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperConfig.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperConfig.java new file mode 100644 index 000000000..6b1cba45d --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperConfig.java @@ -0,0 +1,28 @@ +/** + * Copyright 2012-2015 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.destination; + +import org.mapstruct.MapperConfig; + +/** + * @author Christophe Labouisse on 30/05/2015. + */ +@MapperConfig(implementationName = "MyConfigImpl") +public interface DestinationClassNameMapperConfig { +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperDecorated.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperDecorated.java new file mode 100644 index 000000000..d8fd67d9b --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperDecorated.java @@ -0,0 +1,34 @@ +/** + * Copyright 2012-2015 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.destination; + +import org.mapstruct.DecoratedWith; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * @author Christophe Labouisse on 27/05/2015. + */ +@Mapper(implementationName = "MyCustomImpl") +@DecoratedWith(DestinationClassNameMapperDecorator.class) +public interface DestinationClassNameMapperDecorated { + DestinationClassNameMapperDecorated INSTANCE = Mappers.getMapper( DestinationClassNameMapperDecorated.class ); + + String intToString(Integer source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperDecorator.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperDecorator.java new file mode 100644 index 000000000..681ccd0fb --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperDecorator.java @@ -0,0 +1,35 @@ +/** + * Copyright 2012-2015 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.destination; + +/** + * @author Christophe Labouisse on 31/05/2015. + */ +public abstract class DestinationClassNameMapperDecorator implements DestinationClassNameMapperDecorated { + final DestinationClassNameMapperDecorated delegate; + + protected DestinationClassNameMapperDecorator(DestinationClassNameMapperDecorated delegate) { + this.delegate = delegate; + } + + @Override + public String intToString(Integer source) { + return delegate.intToString( source ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperWithConfig.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperWithConfig.java new file mode 100644 index 000000000..0e2170989 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperWithConfig.java @@ -0,0 +1,32 @@ +/** + * Copyright 2012-2015 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.destination; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * @author Christophe Labouisse on 27/05/2015. + */ +@Mapper(config = DestinationClassNameMapperConfig.class) +public interface DestinationClassNameMapperWithConfig { + DestinationClassNameMapperWithConfig INSTANCE = Mappers.getMapper( DestinationClassNameMapperWithConfig.class ); + + String intToString(Integer source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperWithConfigOverride.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperWithConfigOverride.java new file mode 100644 index 000000000..1523012f0 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameMapperWithConfigOverride.java @@ -0,0 +1,33 @@ +/** + * Copyright 2012-2015 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.destination; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * @author Christophe Labouisse on 27/05/2015. + */ +@Mapper(config = DestinationClassNameMapperConfig.class, implementationName = "CustomMyImpl") +public interface DestinationClassNameMapperWithConfigOverride { + DestinationClassNameMapperWithConfigOverride INSTANCE = + Mappers.getMapper( DestinationClassNameMapperWithConfigOverride.class ); + + String intToString(Integer source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameTest.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameTest.java new file mode 100644 index 000000000..3da2072b7 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameTest.java @@ -0,0 +1,88 @@ +/** + * Copyright 2012-2015 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.destination; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mapstruct.ap.testutil.WithClasses; +import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; +import org.mapstruct.factory.Mappers; + +import static org.fest.assertions.Assertions.assertThat; + +/** + * @author Christophe Labouisse on 27/05/2015. + */ +@RunWith(AnnotationProcessorTestRunner.class) +public class DestinationClassNameTest { + @Test + @WithClasses({ DestinationClassNameMapper.class }) + public void shouldGenerateRightName() throws Exception { + DestinationClassNameMapper instance = DestinationClassNameMapper.INSTANCE; + assertThat( instance.getClass().getSimpleName() ).isEqualTo( "MyDestinationClassNameMapperCustomImpl" ); + } + + @Test + @WithClasses({ DestinationClassNameWithJsr330Mapper.class }) + public void shouldNotGenerateSpi() throws Exception { + + Class clazz = DestinationClassNameWithJsr330Mapper.class; + try { + Mappers.getMapper( clazz ); + Assert.fail( "Should have thrown an ClassNotFoundException" ); + } + catch ( RuntimeException e ) { + assertThat( e.getCause() ).isNotNull() + .isExactlyInstanceOf( ClassNotFoundException.class ) + .hasMessage( "Cannot find implementation for " + clazz.getName() ); + } + + DestinationClassNameWithJsr330Mapper instance = (DestinationClassNameWithJsr330Mapper) Class + .forName( clazz.getName() + "Jsr330Impl" ).newInstance(); + assertThat( instance.getClass().getSimpleName() ).isEqualTo( "DestinationClassNameWithJsr330MapperJsr330Impl" ); + } + + @Test + @WithClasses({ DestinationClassNameMapperConfig.class, DestinationClassNameMapperWithConfig.class }) + public void shouldGenerateRightNameWithConfig() throws Exception { + DestinationClassNameMapperWithConfig instance = DestinationClassNameMapperWithConfig.INSTANCE; + assertThat( instance.getClass().getSimpleName() ) + .isEqualTo( "MyDestinationClassNameMapperWithConfigConfigImpl" ); + } + + @Test + @WithClasses({ DestinationClassNameMapperConfig.class, DestinationClassNameMapperWithConfigOverride.class }) + public void shouldGenerateRightNameWithConfigOverride() throws Exception { + DestinationClassNameMapperWithConfigOverride instance = DestinationClassNameMapperWithConfigOverride.INSTANCE; + assertThat( instance.getClass().getSimpleName() ) + .isEqualTo( "CustomDestinationClassNameMapperWithConfigOverrideMyImpl" ); + } + + @Test + @WithClasses({ DestinationClassNameMapperDecorated.class, DestinationClassNameMapperDecorator.class }) + public void shouldGenerateRightNameWithDecorator() throws Exception { + DestinationClassNameMapperDecorated instance = DestinationClassNameMapperDecorated.INSTANCE; + assertThat( instance.getClass().getSimpleName() ) + .isEqualTo( "MyDestinationClassNameMapperDecoratedCustomImpl" ); + assertThat( instance ).isInstanceOf( DestinationClassNameMapperDecorator.class ); + assertThat( ( (DestinationClassNameMapperDecorator) instance ).delegate.getClass().getSimpleName() ) + .isEqualTo( "MyDestinationClassNameMapperDecoratedCustomImpl_" ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameWithJsr330Mapper.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameWithJsr330Mapper.java new file mode 100644 index 000000000..ba0d0d32a --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationClassNameWithJsr330Mapper.java @@ -0,0 +1,29 @@ +/** + * Copyright 2012-2015 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.destination; + +import org.mapstruct.Mapper; + +/** + * @author Christophe Labouisse on 27/05/2015. + */ +@Mapper(implementationName = "Jsr330Impl", componentModel = "jsr330") +public interface DestinationClassNameWithJsr330Mapper { + String intToString(Integer source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapper.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapper.java new file mode 100644 index 000000000..8950f049d --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapper.java @@ -0,0 +1,32 @@ +/** + * Copyright 2012-2015 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.destination; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * @author Christophe Labouisse on 27/05/2015. + */ +@Mapper(implementationPackage = ".dest") +public interface DestinationPackageNameMapper { + DestinationPackageNameMapper INSTANCE = Mappers.getMapper( DestinationPackageNameMapper.class ); + + String intToString(Integer source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperConfig.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperConfig.java new file mode 100644 index 000000000..2c062384b --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperConfig.java @@ -0,0 +1,28 @@ +/** + * Copyright 2012-2015 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.destination; + +import org.mapstruct.MapperConfig; + +/** + * @author Christophe Labouisse on 30/05/2015. + */ +@MapperConfig(implementationPackage = ".dest") +public interface DestinationPackageNameMapperConfig { +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperDecorated.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperDecorated.java new file mode 100644 index 000000000..1ffd457a8 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperDecorated.java @@ -0,0 +1,34 @@ +/** + * Copyright 2012-2015 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.destination; + +import org.mapstruct.DecoratedWith; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * @author Christophe Labouisse on 27/05/2015. + */ +@Mapper(implementationPackage = ".dest") +@DecoratedWith(DestinationPackageNameMapperDecorator.class) +public interface DestinationPackageNameMapperDecorated { + DestinationPackageNameMapperDecorated INSTANCE = Mappers.getMapper( DestinationPackageNameMapperDecorated.class ); + + String intToString(Integer source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperDecorator.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperDecorator.java new file mode 100644 index 000000000..645428b63 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperDecorator.java @@ -0,0 +1,35 @@ +/** + * Copyright 2012-2015 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.destination; + +/** + * @author Christophe Labouisse on 31/05/2015. + */ +public abstract class DestinationPackageNameMapperDecorator implements DestinationPackageNameMapperDecorated { + final DestinationPackageNameMapperDecorated delegate; + + protected DestinationPackageNameMapperDecorator(DestinationPackageNameMapperDecorated delegate) { + this.delegate = delegate; + } + + @Override + public String intToString(Integer source) { + return delegate.intToString( source ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperWithConfig.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperWithConfig.java new file mode 100644 index 000000000..20291acca --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperWithConfig.java @@ -0,0 +1,32 @@ +/** + * Copyright 2012-2015 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.destination; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * @author Christophe Labouisse on 27/05/2015. + */ +@Mapper(config = DestinationPackageNameMapperConfig.class) +public interface DestinationPackageNameMapperWithConfig { + DestinationPackageNameMapperWithConfig INSTANCE = Mappers.getMapper( DestinationPackageNameMapperWithConfig.class ); + + String intToString(Integer source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperWithConfigOverride.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperWithConfigOverride.java new file mode 100644 index 000000000..5dcfacf2f --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperWithConfigOverride.java @@ -0,0 +1,33 @@ +/** + * Copyright 2012-2015 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.destination; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * @author Christophe Labouisse on 27/05/2015. + */ +@Mapper(config = DestinationPackageNameMapperConfig.class, implementationPackage = ".my_dest") +public interface DestinationPackageNameMapperWithConfigOverride { + DestinationPackageNameMapperWithConfigOverride INSTANCE = + Mappers.getMapper( DestinationPackageNameMapperWithConfigOverride.class ); + + String intToString(Integer source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperWithSuffix.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperWithSuffix.java new file mode 100644 index 000000000..b1e7cc353 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameMapperWithSuffix.java @@ -0,0 +1,32 @@ +/** + * Copyright 2012-2015 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.destination; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * @author Christophe Labouisse on 27/05/2015. + */ +@Mapper(implementationName = "MyImpl", implementationPackage = ".dest") +public interface DestinationPackageNameMapperWithSuffix { + DestinationPackageNameMapperWithSuffix INSTANCE = Mappers.getMapper( DestinationPackageNameMapperWithSuffix.class ); + + String intToString(Integer source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameTest.java b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameTest.java new file mode 100644 index 000000000..06815307a --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/destination/DestinationPackageNameTest.java @@ -0,0 +1,80 @@ +/** + * Copyright 2012-2015 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.destination; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mapstruct.ap.testutil.IssueKey; +import org.mapstruct.ap.testutil.WithClasses; +import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; + +import static org.fest.assertions.Assertions.assertThat; + +/** + * @author Christophe Labouisse on 27/05/2015. + */ +@IssueKey( "556" ) +@RunWith(AnnotationProcessorTestRunner.class) +public class DestinationPackageNameTest { + @Test + @WithClasses({ DestinationPackageNameMapper.class }) + public void shouldGenerateInRightPackage() throws Exception { + DestinationPackageNameMapper instance = DestinationPackageNameMapper.INSTANCE; + assertThat( instance.getClass().getName() ) + .isEqualTo( "org.mapstruct.ap.test.destination.dest.DestinationPackageNameMapperImpl" ); + } + + @Test + @WithClasses({ DestinationPackageNameMapperWithSuffix.class }) + public void shouldGenerateInRightPackageWithSuffix() throws Exception { + DestinationPackageNameMapperWithSuffix instance = DestinationPackageNameMapperWithSuffix.INSTANCE; + assertThat( instance.getClass().getName() ) + .isEqualTo( "org.mapstruct.ap.test.destination.dest.DestinationPackageNameMapperWithSuffixMyImpl" ); + } + + @Test + @WithClasses({ DestinationPackageNameMapperConfig.class, DestinationPackageNameMapperWithConfig.class }) + public void shouldGenerateRightSuffixWithConfig() throws Exception { + DestinationPackageNameMapperWithConfig instance = DestinationPackageNameMapperWithConfig.INSTANCE; + assertThat( instance.getClass().getName() ) + .isEqualTo( "org.mapstruct.ap.test.destination.dest.DestinationPackageNameMapperWithConfigImpl" ); + } + + @Test + @WithClasses({ DestinationPackageNameMapperConfig.class, DestinationPackageNameMapperWithConfigOverride.class }) + public void shouldGenerateRightSuffixWithConfigOverride() throws Exception { + DestinationPackageNameMapperWithConfigOverride instance = + DestinationPackageNameMapperWithConfigOverride.INSTANCE; + assertThat( instance.getClass().getName() ) + .isEqualTo( + "org.mapstruct.ap.test.destination.my_dest.DestinationPackageNameMapperWithConfigOverrideImpl" + ); + } + + @Test + @WithClasses({ DestinationPackageNameMapperDecorated.class, DestinationPackageNameMapperDecorator.class }) + public void shouldGenerateRightSuffixWithDecorator() throws Exception { + DestinationPackageNameMapperDecorated instance = DestinationPackageNameMapperDecorated.INSTANCE; + assertThat( instance.getClass().getName() ) + .isEqualTo( "org.mapstruct.ap.test.destination.dest.DestinationPackageNameMapperDecoratedImpl" ); + assertThat( instance ).isInstanceOf( DestinationPackageNameMapperDecorator.class ); + assertThat( ( (DestinationPackageNameMapperDecorator) instance ).delegate.getClass().getName() ) + .isEqualTo( "org.mapstruct.ap.test.destination.dest.DestinationPackageNameMapperDecoratedImpl_" ); + } +}