#472, #556 Make implementation package and name configurable

- Add `implementationName` & `implementationPackage` to `@Mapper` and
`@MapperConfig'

- Generate a file in `META-INF/services` when a custom name or package
has been configured

- `Mappers` use `ServiceLoader` first in order to get a mapper's
  implementation before falling back to the former method

- Change the `MapperServiceProcess` behaviour to return `default` rather
  than `null` when no component model is defined
This commit is contained in:
Christophe Labouisse 2015-07-14 17:45:49 +02:00 committed by Andreas Gudian
parent 9578f9b452
commit 29f720b35e
33 changed files with 1021 additions and 53 deletions

View File

@ -84,6 +84,28 @@ public @interface Mapper {
*/ */
String componentModel() default "default"; String componentModel() default "default";
/**
* Specifies the name of the implementation class. The {@code <CLASS_NAME>} will be replaced by the
* interface/abstract class name.
* <p>
* Defaults to postfixing the name with {@code Impl}: {@code <CLASS_NAME>Impl}
*
* @return The implementation name.
* @see #implementationPackage()
*/
String implementationName() default "<CLASS_NAME>Impl";
/**
* Specifies the target package for the generated implementation. The {@code <CLASS_NAME>} will be replaced
* by the interface's or abstract class' package.
* <p>
* Defaults to using the same package as the mapper interface/abstract class
*
* @return the implementation package.
* @see #implementationName()
*/
String implementationPackage() default "<PACKAGE_NAME>";
/** /**
* A class annotated with {@link MapperConfig} which should be used as configuration template. Any settings given * 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 * via {@link Mapper} will take precedence over the settings from the referenced configuration source. The list of

View File

@ -84,6 +84,28 @@ public @interface MapperConfig {
*/ */
String componentModel() default "default"; String componentModel() default "default";
/**
* Specifies the name of the implementation class. The {@code <CLASS_NAME>} will be replaced by the
* interface/abstract class name.
* <p>
* Defaults to postfixing the name with {@code Impl}: {@code <CLASS_NAME>Impl}
*
* @return The implementation name.
* @see #implementationPackage()
*/
String implementationName() default "<CLASS_NAME>Impl";
/**
* Specifies the target package for the generated implementation. The {@code <CLASS_NAME>} will be replaced
* by the interface's or abstract class' package.
* <p>
* Defaults to using the same package as the mapper interface/abstract class
*
* @return the implementation package.
* @see #implementationName()
*/
String implementationPackage() default "<PACKAGE_NAME>";
/** /**
* The strategy to be applied when propagating the value of collection-typed properties. By default, only JavaBeans * 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 * accessor methods (setters or getters) will be used, but it is also possible to invoke a corresponding adder

View File

@ -20,6 +20,8 @@ package org.mapstruct.factory;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import java.util.ServiceLoader;
/** /**
* Factory for obtaining mapper instances if no explicit component model such as CDI is configured via * Factory for obtaining mapper instances if no explicit component model such as CDI is configured via
* {@link Mapper#componentModel()}. * {@link Mapper#componentModel()}.
@ -73,11 +75,25 @@ public class Mappers {
classLoader = Mappers.class.getClassLoader(); classLoader = Mappers.class.getClassLoader();
} }
try {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
T mapper = (T) classLoader.loadClass( clazz.getName() + IMPLEMENTATION_SUFFIX ).newInstance(); T mapper = (T) classLoader.loadClass( clazz.getName() + IMPLEMENTATION_SUFFIX ).newInstance();
return mapper; return mapper;
} }
catch (ClassNotFoundException e) {
ServiceLoader<T> loader = ServiceLoader.load( clazz, classLoader );
if ( loader != null ) {
for ( T mapper : loader ) {
if ( mapper != null ) {
return mapper;
}
}
}
throw new ClassNotFoundException("Cannot find implementation for " + clazz.getName());
}
}
catch ( Exception e ) { catch ( Exception e ) {
throw new RuntimeException( e ); throw new RuntimeException( e );
} }

View File

@ -16,12 +16,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.mapstruct; package org.mapstruct.factory;
import static org.fest.assertions.Assertions.assertThat; import static org.fest.assertions.Assertions.assertThat;
import org.junit.Test; import org.junit.Test;
import org.mapstruct.factory.Mappers;
import org.mapstruct.test.model.Foo; import org.mapstruct.test.model.Foo;
/** /**

View File

@ -101,6 +101,7 @@ public class MappingProcessor extends AbstractProcessor {
"mapstruct.suppressGeneratorVersionInfoComment"; "mapstruct.suppressGeneratorVersionInfoComment";
protected static final String UNMAPPED_TARGET_POLICY = "mapstruct.unmappedTargetPolicy"; protected static final String UNMAPPED_TARGET_POLICY = "mapstruct.unmappedTargetPolicy";
protected static final String DEFAULT_COMPONENT_MODEL = "mapstruct.defaultComponentModel"; protected static final String DEFAULT_COMPONENT_MODEL = "mapstruct.defaultComponentModel";
protected static final String ALWAYS_GENERATE_SERVICE_FILE = "mapstruct.alwaysGenerateServicesFile";
private Options options; private Options options;
@ -113,12 +114,14 @@ public class MappingProcessor extends AbstractProcessor {
private Options createOptions() { private Options createOptions() {
String unmappedTargetPolicy = processingEnv.getOptions().get( UNMAPPED_TARGET_POLICY ); String unmappedTargetPolicy = processingEnv.getOptions().get( UNMAPPED_TARGET_POLICY );
String defaultComponentModel = processingEnv.getOptions().get( DEFAULT_COMPONENT_MODEL );
return new Options( return new Options(
Boolean.valueOf( processingEnv.getOptions().get( SUPPRESS_GENERATOR_TIMESTAMP ) ), Boolean.valueOf( processingEnv.getOptions().get( SUPPRESS_GENERATOR_TIMESTAMP ) ),
Boolean.valueOf( processingEnv.getOptions().get( SUPPRESS_GENERATOR_VERSION_INFO_COMMENT ) ), Boolean.valueOf( processingEnv.getOptions().get( SUPPRESS_GENERATOR_VERSION_INFO_COMMENT ) ),
unmappedTargetPolicy != null ? ReportingPolicy.valueOf( unmappedTargetPolicy ) : null, 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 ) )
); );
} }

View File

@ -18,15 +18,6 @@
*/ */
package org.mapstruct.ap.internal.model; 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.Accessibility;
import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.common.TypeFactory; 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.prism.DecoratedWithPrism;
import org.mapstruct.ap.internal.version.VersionInformation; 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. * 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 { public class Decorator extends GeneratedType {
private static final String IMPLEMENTATION_SUFFIX = "Impl";
public static class Builder { public static class Builder {
private Elements elementUtils; private Elements elementUtils;
@ -53,6 +49,9 @@ public class Decorator extends GeneratedType {
private Options options; private Options options;
private VersionInformation versionInformation; private VersionInformation versionInformation;
private boolean hasDelegateConstructor; private boolean hasDelegateConstructor;
private String implName;
private String implPackage;
private SortedSet<Type> extraImportedTypes;
public Builder elementUtils(Elements elementUtils) { public Builder elementUtils(Elements elementUtils) {
this.elementUtils = elementUtils; this.elementUtils = elementUtils;
@ -94,25 +93,48 @@ public class Decorator extends GeneratedType {
return this; 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<Type> extraImportedTypes) {
this.extraImportedTypes = extraImportedTypes;
return this;
}
public Decorator build() { public Decorator build() {
String implementationName = implName.replace( Mapper.CLASS_NAME_PLACEHOLDER,
mapperElement.getSimpleName() );
Type decoratorType = typeFactory.getType( decoratorPrism.value() ); Type decoratorType = typeFactory.getType( decoratorPrism.value() );
DecoratorConstructor decoratorConstructor = new DecoratorConstructor( DecoratorConstructor decoratorConstructor = new DecoratorConstructor(
mapperElement.getSimpleName().toString() + IMPLEMENTATION_SUFFIX, implementationName,
mapperElement.getSimpleName().toString() + "Impl_", implementationName + "_",
hasDelegateConstructor ); hasDelegateConstructor );
String elementPackage = elementUtils.getPackageOf( mapperElement ).getQualifiedName().toString();
String packageName = implPackage.replace( Mapper.PACKAGE_NAME_PLACEHOLDER, elementPackage );
return new Decorator( return new Decorator(
typeFactory, typeFactory,
elementUtils.getPackageOf( mapperElement ).getQualifiedName().toString(), packageName,
mapperElement.getSimpleName().toString() + IMPLEMENTATION_SUFFIX, implementationName,
decoratorType, decoratorType,
elementPackage,
mapperElement.getKind() == ElementKind.INTERFACE ? mapperElement.getSimpleName().toString() : null, mapperElement.getKind() == ElementKind.INTERFACE ? mapperElement.getSimpleName().toString() : null,
methods, methods,
Arrays.asList( new Field( typeFactory.getType( mapperElement ), "delegate", true ) ) , Arrays.asList( new Field( typeFactory.getType( mapperElement ), "delegate", true ) ) ,
options, options,
versionInformation, versionInformation,
Accessibility.fromModifiers( mapperElement.getModifiers() ), Accessibility.fromModifiers( mapperElement.getModifiers() ),
extraImportedTypes,
decoratorConstructor decoratorConstructor
); );
} }
@ -122,21 +144,23 @@ public class Decorator extends GeneratedType {
@SuppressWarnings( "checkstyle:parameternumber" ) @SuppressWarnings( "checkstyle:parameternumber" )
private Decorator(TypeFactory typeFactory, String packageName, String name, Type decoratorType, private Decorator(TypeFactory typeFactory, String packageName, String name, Type decoratorType,
String interfaceName, List<MappingMethod> methods, List<? extends Field> fields, String interfacePackage, String interfaceName, List<MappingMethod> methods,
Options options, VersionInformation versionInformation, Accessibility accessibility, List<? extends Field> fields, Options options, VersionInformation versionInformation,
Accessibility accessibility, SortedSet<Type> extraImports,
DecoratorConstructor decoratorConstructor) { DecoratorConstructor decoratorConstructor) {
super( super(
typeFactory, typeFactory,
packageName, packageName,
name, name,
decoratorType.getName(), decoratorType.getName(),
interfacePackage,
interfaceName, interfaceName,
methods, methods,
fields, fields,
options, options,
versionInformation, versionInformation,
accessibility, accessibility,
new TreeSet<Type>(), extraImports,
decoratorConstructor decoratorConstructor
); );

View File

@ -45,6 +45,7 @@ public abstract class GeneratedType extends ModelElement {
private final String packageName; private final String packageName;
private final String name; private final String name;
private final String superClassName; private final String superClassName;
private final String interfacePackage;
private final String interfaceName; private final String interfaceName;
private final List<Annotation> annotations; private final List<Annotation> annotations;
@ -65,7 +66,7 @@ public abstract class GeneratedType extends ModelElement {
// CHECKSTYLE:OFF // CHECKSTYLE:OFF
protected GeneratedType(TypeFactory typeFactory, String packageName, String name, String superClassName, protected GeneratedType(TypeFactory typeFactory, String packageName, String name, String superClassName,
String interfaceName, String interfacePackage, String interfaceName,
List<MappingMethod> methods, List<MappingMethod> methods,
List<? extends Field> fields, List<? extends Field> fields,
Options options, Options options,
@ -76,6 +77,7 @@ public abstract class GeneratedType extends ModelElement {
this.packageName = packageName; this.packageName = packageName;
this.name = name; this.name = name;
this.superClassName = superClassName; this.superClassName = superClassName;
this.interfacePackage = interfacePackage;
this.interfaceName = interfaceName; this.interfaceName = interfaceName;
this.extraImportedTypes = extraImportedTypes; this.extraImportedTypes = extraImportedTypes;
@ -106,6 +108,10 @@ public abstract class GeneratedType extends ModelElement {
return superClassName; return superClassName;
} }
public String getInterfacePackage() {
return interfacePackage;
}
public String getInterfaceName() { public String getInterfaceName() {
return interfaceName; return interfaceName;
} }

View File

@ -39,24 +39,29 @@ import org.mapstruct.ap.internal.version.VersionInformation;
*/ */
public class Mapper extends GeneratedType { public class Mapper extends GeneratedType {
private static final String IMPLEMENTATION_SUFFIX = "Impl"; static final String CLASS_NAME_PLACEHOLDER = "<CLASS_NAME>";
private static final String DECORATED_IMPLEMENTATION_SUFFIX = "Impl_"; static final String PACKAGE_NAME_PLACEHOLDER = "<PACKAGE_NAME>";
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<MapperReference> referencedMappers; private final List<MapperReference> referencedMappers;
private Decorator decorator; private Decorator decorator;
@SuppressWarnings( "checkstyle:parameternumber" ) @SuppressWarnings( "checkstyle:parameternumber" )
private Mapper(TypeFactory typeFactory, String packageName, String name, String superClassName, private Mapper(TypeFactory typeFactory, String packageName, String name, String superClassName,
String interfaceName, List<MappingMethod> methods, Options options, String interfacePackage, String interfaceName, boolean customPackage, boolean customImplName,
VersionInformation versionInformation, Accessibility accessibility, List<MappingMethod> methods, Options options, VersionInformation versionInformation,
List<MapperReference> referencedMappers, Decorator decorator, Accessibility accessibility, List<MapperReference> referencedMappers, Decorator decorator,
SortedSet<Type> extraImportedTypes ) { SortedSet<Type> extraImportedTypes) {
super( super(
typeFactory, typeFactory,
packageName, packageName,
name, name,
superClassName, superClassName,
interfacePackage,
interfaceName, interfaceName,
methods, methods,
referencedMappers, referencedMappers,
@ -66,6 +71,8 @@ public class Mapper extends GeneratedType {
extraImportedTypes, extraImportedTypes,
null null
); );
this.customPackage = customPackage;
this.customImplName = customImplName;
this.referencedMappers = referencedMappers; this.referencedMappers = referencedMappers;
this.decorator = decorator; this.decorator = decorator;
@ -83,6 +90,10 @@ public class Mapper extends GeneratedType {
private Options options; private Options options;
private VersionInformation versionInformation; private VersionInformation versionInformation;
private Decorator decorator; private Decorator decorator;
private String implName;
private boolean customName;
private String implPackage;
private boolean customPackage;
public Builder element(TypeElement element) { public Builder element(TypeElement element) {
this.element = element; this.element = element;
@ -129,16 +140,34 @@ public class Mapper extends GeneratedType {
return this; 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() { public Mapper build() {
String implementationName = element.getSimpleName() String implementationName = implName.replace( CLASS_NAME_PLACEHOLDER, element.getSimpleName() ) +
+ ( decorator == null ? IMPLEMENTATION_SUFFIX : DECORATED_IMPLEMENTATION_SUFFIX ); ( decorator == null ? "" : "_" );
String elementPackage = elementUtils.getPackageOf( element ).getQualifiedName().toString();
String packageName = implPackage.replace( PACKAGE_NAME_PLACEHOLDER, elementPackage );
return new Mapper( return new Mapper(
typeFactory, typeFactory,
elementUtils.getPackageOf( element ).getQualifiedName().toString(), packageName,
implementationName, implementationName,
element.getKind() != ElementKind.INTERFACE ? element.getSimpleName().toString() : null, element.getKind() != ElementKind.INTERFACE ? element.getSimpleName().toString() : null,
elementPackage,
element.getKind() == ElementKind.INTERFACE ? element.getSimpleName().toString() : null, element.getKind() == ElementKind.INTERFACE ? element.getSimpleName().toString() : null,
customPackage,
customName,
mappingMethods, mappingMethods,
options, options,
versionInformation, versionInformation,
@ -162,6 +191,15 @@ public class Mapper extends GeneratedType {
this.decorator = null; 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 @Override
protected String getTemplateName() { protected String getTemplateName() {
return getTemplateNameForClass( GeneratedType.class ); return getTemplateNameForClass( GeneratedType.class );

View File

@ -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<Type> getImportTypes() {
return Collections.emptySet();
}
public String getPackageName() {
return packageName;
}
public String getName() {
return name;
}
public String getImplementationPackage() {
return implementationPackage;
}
public String getImplementationName() {
return implementationName;
}
}

View File

@ -29,15 +29,17 @@ public class Options {
private final boolean suppressGeneratorTimestamp; private final boolean suppressGeneratorTimestamp;
private final boolean suppressGeneratorVersionComment; private final boolean suppressGeneratorVersionComment;
private final ReportingPolicy unmappedTargetPolicy; private final ReportingPolicy unmappedTargetPolicy;
private final boolean alwaysGenerateSpi;
private final String defaultComponentModel; private final String defaultComponentModel;
public Options(boolean suppressGeneratorTimestamp, boolean suppressGeneratorVersionComment, public Options(boolean suppressGeneratorTimestamp, boolean suppressGeneratorVersionComment,
ReportingPolicy unmappedTargetPolicy, ReportingPolicy unmappedTargetPolicy,
String defaultComponentModel) { String defaultComponentModel, boolean alwaysGenerateSpi) {
this.suppressGeneratorTimestamp = suppressGeneratorTimestamp; this.suppressGeneratorTimestamp = suppressGeneratorTimestamp;
this.suppressGeneratorVersionComment = suppressGeneratorVersionComment; this.suppressGeneratorVersionComment = suppressGeneratorVersionComment;
this.unmappedTargetPolicy = unmappedTargetPolicy; this.unmappedTargetPolicy = unmappedTargetPolicy;
this.defaultComponentModel = defaultComponentModel; this.defaultComponentModel = defaultComponentModel;
this.alwaysGenerateSpi = alwaysGenerateSpi;
} }
public boolean isSuppressGeneratorTimestamp() { public boolean isSuppressGeneratorTimestamp() {
@ -55,4 +57,8 @@ public class Options {
public String getDefaultComponentModel() { public String getDefaultComponentModel() {
return defaultComponentModel; return defaultComponentModel;
} }
public boolean isAlwaysGenerateSpi() {
return alwaysGenerateSpi;
}
} }

View File

@ -150,16 +150,20 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
.mapperReferences( mapperReferences ) .mapperReferences( mapperReferences )
.options( options ) .options( options )
.versionInformation( versionInformation ) .versionInformation( versionInformation )
.decorator( getDecorator( element, methods ) ) .decorator( getDecorator( element, methods, mapperConfig.implementationName(),
mapperConfig.implementationPackage() ) )
.typeFactory( typeFactory ) .typeFactory( typeFactory )
.elementUtils( elementUtils ) .elementUtils( elementUtils )
.extraImports( getExtraImports( element ) ) .extraImports( getExtraImports( element ) )
.implName( mapperConfig.implementationName() )
.implPackage( mapperConfig.implementationPackage() )
.build(); .build();
return mapper; return mapper;
} }
private Decorator getDecorator(TypeElement element, List<SourceMethod> methods) { private Decorator getDecorator(TypeElement element, List<SourceMethod> methods, String implName,
String implPackage) {
DecoratedWithPrism decoratorPrism = DecoratedWithPrism.getInstanceOn( element ); DecoratedWithPrism decoratorPrism = DecoratedWithPrism.getInstanceOn( element );
if ( decoratorPrism == null ) { if ( decoratorPrism == null ) {
@ -219,6 +223,9 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
.hasDelegateConstructor( hasDelegateConstructor ) .hasDelegateConstructor( hasDelegateConstructor )
.options( options ) .options( options )
.versionInformation( versionInformation ) .versionInformation( versionInformation )
.implName( implName )
.implPackage( implPackage )
.extraImports( getExtraImports( element ) )
.build(); .build();
return decorator; return decorator;
@ -234,6 +241,11 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
extraImports.add( type ); extraImports.add( type );
} }
// Add original package if a dest package has been set
if ( !"default".equals( mapperConfiguration.implementationPackage() ) ) {
extraImports.add( typeFactory.getType( element ) );
}
return extraImports; return extraImports;
} }

View File

@ -34,12 +34,13 @@ import org.mapstruct.ap.internal.writer.ModelWriter;
* *
* @author Gunnar Morling * @author Gunnar Morling
*/ */
public class MapperRenderingProcessor implements ModelElementProcessor<Mapper, Void> { public class MapperRenderingProcessor implements ModelElementProcessor<Mapper, Mapper> {
@Override @Override
public Void process(ProcessorContext context, TypeElement mapperTypeElement, Mapper mapper) { public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, Mapper mapper) {
if ( !context.isErroneous() ) { if ( !context.isErroneous() ) {
writeToSourceFile( context.getFiler(), mapper ); writeToSourceFile( context.getFiler(), mapper );
return mapper;
} }
return null; return null;
@ -71,6 +72,6 @@ public class MapperRenderingProcessor implements ModelElementProcessor<Mapper, V
@Override @Override
public int getPriority() { public int getPriority() {
return 10000; return 9999;
} }
} }

View File

@ -0,0 +1,97 @@
/**
* 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.processor;
import org.mapstruct.ap.internal.model.GeneratedType;
import org.mapstruct.ap.internal.model.Mapper;
import org.mapstruct.ap.internal.model.ServicesEntry;
import org.mapstruct.ap.internal.option.OptionsHelper;
import org.mapstruct.ap.internal.util.MapperConfiguration;
import org.mapstruct.ap.internal.writer.ModelWriter;
import javax.annotation.processing.Filer;
import javax.lang.model.element.TypeElement;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.IOException;
/**
* A {@link ModelElementProcessor} which creates files in the {@code META-INF/services}
* hierarchy for classes with custom implementation class or package name.
*
* Service files will only be generated for mappers with the default component model
* unless force using the {@code mapstruct.alwaysGenerateServicesFile} option.
*
* @author Christophe Labouisse on 12/07/2015.
*/
public class MapperServiceProcessor implements ModelElementProcessor<Mapper, Void> {
@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 );
}
}

View File

@ -18,22 +18,21 @@
*/ */
package org.mapstruct.ap.internal.util; package org.mapstruct.ap.internal.util;
import java.util.ArrayList; import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism;
import java.util.LinkedHashSet; import org.mapstruct.ap.internal.prism.MapperConfigPrism;
import java.util.List; import org.mapstruct.ap.internal.prism.MapperPrism;
import java.util.Set; 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.AnnotationMirror;
import javax.lang.model.element.Element; import javax.lang.model.element.Element;
import javax.lang.model.type.DeclaredType; import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import java.util.ArrayList;
import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism; import java.util.LinkedHashSet;
import org.mapstruct.ap.internal.prism.MapperConfigPrism; import java.util.List;
import org.mapstruct.ap.internal.prism.MapperPrism; import java.util.Set;
import org.mapstruct.ap.internal.prism.MappingInheritanceStrategyPrism;
import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism;
/** /**
* Provides an aggregated view to the settings given via {@link org.mapstruct.Mapper} and * 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<TypeMirror> uses() { public List<TypeMirror> uses() {
Set<TypeMirror> uses = new LinkedHashSet<TypeMirror>( mapperPrism.uses() ); Set<TypeMirror> uses = new LinkedHashSet<TypeMirror>( mapperPrism.uses() );
if ( mapperConfigPrism != null ) { if ( mapperConfigPrism != null ) {

View File

@ -29,7 +29,7 @@ import java.nio.charset.Charset;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.tools.JavaFileObject; import javax.tools.FileObject;
import org.mapstruct.ap.internal.writer.Writable.Context; import org.mapstruct.ap.internal.writer.Writable.Context;
@ -74,7 +74,7 @@ public class ModelWriter {
CONFIGURATION.setLocalizedLookup( false ); CONFIGURATION.setLocalizedLookup( false );
} }
public void writeModel(JavaFileObject sourceFile, Writable model) { public void writeModel(FileObject sourceFile, Writable model) {
try { try {
BufferedWriter writer = new BufferedWriter( new IndentationCorrectingWriter( sourceFile.openWriter() ) ); BufferedWriter writer = new BufferedWriter( new IndentationCorrectingWriter( sourceFile.openWriter() ) );

View File

@ -21,3 +21,4 @@ org.mapstruct.ap.internal.processor.MapperCreationProcessor
org.mapstruct.ap.internal.processor.MapperRenderingProcessor org.mapstruct.ap.internal.processor.MapperRenderingProcessor
org.mapstruct.ap.internal.processor.MethodRetrievalProcessor org.mapstruct.ap.internal.processor.MethodRetrievalProcessor
org.mapstruct.ap.internal.processor.SpringComponentProcessor org.mapstruct.ap.internal.processor.SpringComponentProcessor
org.mapstruct.ap.internal.processor.MapperServiceProcessor

View File

@ -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}

View File

@ -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 = "My<CLASS_NAME>CustomImpl")
public interface DestinationClassNameMapper {
DestinationClassNameMapper INSTANCE = Mappers.getMapper( DestinationClassNameMapper.class );
String intToString(Integer source);
}

View File

@ -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 = "My<CLASS_NAME>ConfigImpl")
public interface DestinationClassNameMapperConfig {
}

View File

@ -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 = "My<CLASS_NAME>CustomImpl")
@DecoratedWith(DestinationClassNameMapperDecorator.class)
public interface DestinationClassNameMapperDecorated {
DestinationClassNameMapperDecorated INSTANCE = Mappers.getMapper( DestinationClassNameMapperDecorated.class );
String intToString(Integer source);
}

View File

@ -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 );
}
}

View File

@ -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);
}

View File

@ -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 = "Custom<CLASS_NAME>MyImpl")
public interface DestinationClassNameMapperWithConfigOverride {
DestinationClassNameMapperWithConfigOverride INSTANCE =
Mappers.getMapper( DestinationClassNameMapperWithConfigOverride.class );
String intToString(Integer source);
}

View File

@ -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<DestinationClassNameWithJsr330Mapper> 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_" );
}
}

View File

@ -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 = "<CLASS_NAME>Jsr330Impl", componentModel = "jsr330")
public interface DestinationClassNameWithJsr330Mapper {
String intToString(Integer source);
}

View File

@ -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 = "<PACKAGE_NAME>.dest")
public interface DestinationPackageNameMapper {
DestinationPackageNameMapper INSTANCE = Mappers.getMapper( DestinationPackageNameMapper.class );
String intToString(Integer source);
}

View File

@ -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 = "<PACKAGE_NAME>.dest")
public interface DestinationPackageNameMapperConfig {
}

View File

@ -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 = "<PACKAGE_NAME>.dest")
@DecoratedWith(DestinationPackageNameMapperDecorator.class)
public interface DestinationPackageNameMapperDecorated {
DestinationPackageNameMapperDecorated INSTANCE = Mappers.getMapper( DestinationPackageNameMapperDecorated.class );
String intToString(Integer source);
}

View File

@ -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 );
}
}

View File

@ -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);
}

View File

@ -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 = "<PACKAGE_NAME>.my_dest")
public interface DestinationPackageNameMapperWithConfigOverride {
DestinationPackageNameMapperWithConfigOverride INSTANCE =
Mappers.getMapper( DestinationPackageNameMapperWithConfigOverride.class );
String intToString(Integer source);
}

View File

@ -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 = "<CLASS_NAME>MyImpl", implementationPackage = "<PACKAGE_NAME>.dest")
public interface DestinationPackageNameMapperWithSuffix {
DestinationPackageNameMapperWithSuffix INSTANCE = Mappers.getMapper( DestinationPackageNameMapperWithSuffix.class );
String intToString(Integer source);
}

View File

@ -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_" );
}
}