mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
* #37 Rudimentary logging in mapstruct * #37 Rudimentary logging in mapstruct changed order * #37 rework * #37 documentation * #37 comments * #37 docmentation revisited * #37 review comments * #37 unit test * #37 unit test fixing empty mapper * #37 rework comments christian * #37 adding deferred mapper logging * #37 adding unit test for deferred mapper logging * #37 processing comments Filip
This commit is contained in:
parent
bc010a52dc
commit
b53741d960
@ -223,6 +223,8 @@ When invoking javac directly, these options are passed to the compiler in the fo
|
||||
<version>${org.mapstruct.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
<!-- due to problem in maven-compiler-plugin, for verbose mode add showWarnings -->
|
||||
<showWarnings>true</showWarnings>
|
||||
<compilerArgs>
|
||||
<compilerArg>
|
||||
-Amapstruct.suppressGeneratorTimestamp=true
|
||||
@ -230,6 +232,9 @@ When invoking javac directly, these options are passed to the compiler in the fo
|
||||
<compilerArg>
|
||||
-Amapstruct.suppressGeneratorVersionInfoComment=true
|
||||
</compilerArg>
|
||||
<compilerArg>
|
||||
-Amapstruct.verbose=true
|
||||
</compilerArg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
@ -246,7 +251,8 @@ When invoking javac directly, these options are passed to the compiler in the fo
|
||||
compileJava {
|
||||
options.compilerArgs = [
|
||||
'-Amapstruct.suppressGeneratorTimestamp=true',
|
||||
'-Amapstruct.suppressGeneratorVersionInfoComment=true'
|
||||
'-Amapstruct.suppressGeneratorVersionInfoComment=true',
|
||||
'-Amapstruct.verbose=true'
|
||||
]
|
||||
}
|
||||
...
|
||||
@ -265,6 +271,10 @@ suppressGeneratorTimestamp`
|
||||
|If set to `true`, the creation of a time stamp in the `@Generated` annotation in the generated mapper classes is suppressed.
|
||||
|`false`
|
||||
|
||||
|`mapstruct.verbose`
|
||||
|If set to `true`, MapStruct in which MapStruct logs its major decisions. Note, at the moment of writing in Maven, also `showWarnings` needs to be added due to a problem in the maven-compiler-plugin configuration.
|
||||
|`false`
|
||||
|
||||
|`mapstruct.
|
||||
suppressGeneratorVersionInfoComment`
|
||||
|If set to `true`, the creation of the `comment` attribute in the `@Generated` annotation in the generated mapper classes is suppressed. The comment contains information about the version of MapStruct and about the compiler used for the annotation processing.
|
||||
|
@ -82,7 +82,8 @@ import static javax.lang.model.element.ElementKind.CLASS;
|
||||
MappingProcessor.SUPPRESS_GENERATOR_TIMESTAMP,
|
||||
MappingProcessor.SUPPRESS_GENERATOR_VERSION_INFO_COMMENT,
|
||||
MappingProcessor.UNMAPPED_TARGET_POLICY,
|
||||
MappingProcessor.DEFAULT_COMPONENT_MODEL
|
||||
MappingProcessor.DEFAULT_COMPONENT_MODEL,
|
||||
MappingProcessor.VERBOSE
|
||||
})
|
||||
public class MappingProcessor extends AbstractProcessor {
|
||||
|
||||
@ -97,6 +98,7 @@ public class MappingProcessor extends AbstractProcessor {
|
||||
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";
|
||||
protected static final String VERBOSE = "mapstruct.verbose";
|
||||
|
||||
private Options options;
|
||||
|
||||
@ -120,7 +122,9 @@ public class MappingProcessor extends AbstractProcessor {
|
||||
options = createOptions();
|
||||
annotationProcessorContext = new AnnotationProcessorContext(
|
||||
processingEnv.getElementUtils(),
|
||||
processingEnv.getTypeUtils()
|
||||
processingEnv.getTypeUtils(),
|
||||
processingEnv.getMessager(),
|
||||
options.isVerbose()
|
||||
);
|
||||
}
|
||||
|
||||
@ -132,7 +136,8 @@ public class MappingProcessor extends AbstractProcessor {
|
||||
Boolean.valueOf( processingEnv.getOptions().get( SUPPRESS_GENERATOR_VERSION_INFO_COMMENT ) ),
|
||||
unmappedTargetPolicy != null ? ReportingPolicyPrism.valueOf( unmappedTargetPolicy.toUpperCase() ) : null,
|
||||
processingEnv.getOptions().get( DEFAULT_COMPONENT_MODEL ),
|
||||
Boolean.valueOf( processingEnv.getOptions().get( ALWAYS_GENERATE_SERVICE_FILE ) )
|
||||
Boolean.valueOf( processingEnv.getOptions().get( ALWAYS_GENERATE_SERVICE_FILE ) ),
|
||||
Boolean.valueOf( processingEnv.getOptions().get( VERBOSE ) )
|
||||
);
|
||||
}
|
||||
|
||||
@ -221,6 +226,11 @@ public class MappingProcessor extends AbstractProcessor {
|
||||
processMapperTypeElement( context, mapperElement );
|
||||
}
|
||||
catch ( TypeHierarchyErroneousException thie ) {
|
||||
if ( options.isVerbose() ) {
|
||||
processingEnv.getMessager().printMessage(
|
||||
Kind.NOTE, "MapStruct: referred types not available (yet), deferring mapper: "
|
||||
+ mapperElement );
|
||||
}
|
||||
deferredMappers.add( mapperElement );
|
||||
}
|
||||
catch ( Throwable t ) {
|
||||
@ -242,7 +252,7 @@ public class MappingProcessor extends AbstractProcessor {
|
||||
StringWriter sw = new StringWriter();
|
||||
thrown.printStackTrace( new PrintWriter( sw ) );
|
||||
|
||||
String reportableStacktrace = sw.toString().replace( System.getProperty( "line.separator" ), " " );
|
||||
String reportableStacktrace = sw.toString().replace( System.lineSeparator( ), " " );
|
||||
|
||||
processingEnv.getMessager().printMessage(
|
||||
Kind.ERROR, "Internal error in the mapping processor: " + reportableStacktrace, element );
|
||||
|
@ -20,6 +20,7 @@ import org.mapstruct.ap.internal.model.source.ForgedMethod;
|
||||
import org.mapstruct.ap.internal.model.source.Method;
|
||||
import org.mapstruct.ap.internal.model.source.SelectionParameters;
|
||||
import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism;
|
||||
import org.mapstruct.ap.internal.util.Message;
|
||||
import org.mapstruct.ap.internal.util.Strings;
|
||||
|
||||
/**
|
||||
@ -94,6 +95,12 @@ public abstract class ContainerMappingMethodBuilder<B extends ContainerMappingMe
|
||||
|
||||
if ( assignment == null ) {
|
||||
assignment = forgeMapping( sourceRHS, sourceElementType, targetElementType );
|
||||
if ( assignment != null ) {
|
||||
ctx.getMessager().note( 2, Message.ITERABLEMAPPING_CREATE_ELEMENT_NOTE, assignment );
|
||||
}
|
||||
}
|
||||
else {
|
||||
ctx.getMessager().note( 2, Message.ITERABLEMAPPING_SELECT_ELEMENT_NOTE, assignment );
|
||||
}
|
||||
|
||||
if ( assignment == null ) {
|
||||
|
@ -23,6 +23,7 @@ import org.mapstruct.ap.internal.model.source.ForgedMethod;
|
||||
import org.mapstruct.ap.internal.model.source.Method;
|
||||
import org.mapstruct.ap.internal.model.source.SelectionParameters;
|
||||
import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism;
|
||||
import org.mapstruct.ap.internal.util.Message;
|
||||
import org.mapstruct.ap.internal.util.Strings;
|
||||
|
||||
/**
|
||||
@ -98,8 +99,13 @@ public class MapMappingMethod extends NormalTypeMappingMethod {
|
||||
|
||||
if ( keyAssignment == null ) {
|
||||
keyAssignment = forgeMapping( keySourceRHS, keySourceType, keyTargetType );
|
||||
if ( keyAssignment != null ) {
|
||||
ctx.getMessager().note( 2, Message.MAPMAPPING_CREATE_KEY_NOTE, keyAssignment );
|
||||
}
|
||||
}
|
||||
else {
|
||||
ctx.getMessager().note( 2, Message.MAPMAPPING_SELECT_KEY_NOTE, keyAssignment );
|
||||
}
|
||||
|
||||
|
||||
if ( keyAssignment == null ) {
|
||||
if ( method instanceof ForgedMethod ) {
|
||||
@ -150,6 +156,12 @@ public class MapMappingMethod extends NormalTypeMappingMethod {
|
||||
|
||||
if ( valueAssignment == null ) {
|
||||
valueAssignment = forgeMapping( valueSourceRHS, valueSourceType, valueTargetType );
|
||||
if ( valueAssignment != null ) {
|
||||
ctx.getMessager().note( 2, Message.MAPMAPPING_CREATE_VALUE_NOTE, valueAssignment );
|
||||
}
|
||||
}
|
||||
else {
|
||||
ctx.getMessager().note( 2, Message.MAPMAPPING_SELECT_VALUE_NOTE, valueAssignment );
|
||||
}
|
||||
|
||||
if ( valueAssignment == null ) {
|
||||
|
@ -10,6 +10,7 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.mapstruct.ap.internal.model.common.Assignment;
|
||||
import org.mapstruct.ap.internal.model.common.ConversionContext;
|
||||
@ -19,6 +20,7 @@ import org.mapstruct.ap.internal.model.common.ParameterBinding;
|
||||
import org.mapstruct.ap.internal.model.common.Type;
|
||||
import org.mapstruct.ap.internal.model.source.Method;
|
||||
import org.mapstruct.ap.internal.model.source.builtin.BuiltInMethod;
|
||||
import org.mapstruct.ap.internal.util.Strings;
|
||||
|
||||
/**
|
||||
* Represents a reference to another method, e.g. used to map a bean property from source to target type or to
|
||||
@ -348,4 +350,15 @@ public class MethodReference extends ModelElement implements Assignment {
|
||||
return new MethodReference( methodName, null, false );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String mapper = declaringMapper != null ? declaringMapper.getType().getName().toString() : "";
|
||||
String argument = getAssignment() != null ? getAssignment().toString() : getSourceReference();
|
||||
String returnTypeAsString = returnType != null ? returnType.toString() : "";
|
||||
List<String> arguments = sourceParameters.stream()
|
||||
.map( p -> p.isMappingContext() || p.isMappingTarget() || p.isTargetType() ? p.getName() : argument )
|
||||
.collect( Collectors.toList() );
|
||||
|
||||
return returnTypeAsString + " " + mapper + "#" + name + "(" + Strings.join( arguments, "," ) + ")";
|
||||
}
|
||||
}
|
||||
|
@ -295,6 +295,9 @@ public class PropertyMapping extends ModelElement {
|
||||
|
||||
// handle source
|
||||
this.rightHandSide = getSourceRHS( sourceReference );
|
||||
|
||||
ctx.getMessager().note( 2, Message.PROPERTYMAPPING_MAPPING_NOTE, rightHandSide, targetWriteAccessor );
|
||||
|
||||
rightHandSide.setUseElementAsSourceTypeForMatching(
|
||||
targetWriteAccessorType == TargetWriteAccessorType.ADDER );
|
||||
|
||||
@ -339,6 +342,12 @@ public class PropertyMapping extends ModelElement {
|
||||
else {
|
||||
assignment = forgeMapping( rightHandSide );
|
||||
}
|
||||
if ( assignment != null ) {
|
||||
ctx.getMessager().note( 2, Message.PROPERTYMAPPING_CREATE_NOTE, assignment );
|
||||
}
|
||||
}
|
||||
else {
|
||||
ctx.getMessager().note( 2, Message.PROPERTYMAPPING_SELECT_NOTE, assignment );
|
||||
}
|
||||
|
||||
if ( assignment != null ) {
|
||||
|
@ -140,4 +140,10 @@ public class TypeConversion extends ModelElement implements Assignment {
|
||||
public boolean isCallingUpdateMethod() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String argument = getAssignment() != null ? getAssignment().toString() : getSourceReference();
|
||||
return openExpression + argument + closeExpression;
|
||||
}
|
||||
}
|
||||
|
@ -19,15 +19,17 @@ public class Options {
|
||||
private final ReportingPolicyPrism unmappedTargetPolicy;
|
||||
private final boolean alwaysGenerateSpi;
|
||||
private final String defaultComponentModel;
|
||||
private final boolean verbose;
|
||||
|
||||
public Options(boolean suppressGeneratorTimestamp, boolean suppressGeneratorVersionComment,
|
||||
ReportingPolicyPrism unmappedTargetPolicy,
|
||||
String defaultComponentModel, boolean alwaysGenerateSpi) {
|
||||
String defaultComponentModel, boolean alwaysGenerateSpi, boolean verbose) {
|
||||
this.suppressGeneratorTimestamp = suppressGeneratorTimestamp;
|
||||
this.suppressGeneratorVersionComment = suppressGeneratorVersionComment;
|
||||
this.unmappedTargetPolicy = unmappedTargetPolicy;
|
||||
this.defaultComponentModel = defaultComponentModel;
|
||||
this.alwaysGenerateSpi = alwaysGenerateSpi;
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
public boolean isSuppressGeneratorTimestamp() {
|
||||
@ -49,4 +51,8 @@ public class Options {
|
||||
public boolean isAlwaysGenerateSpi() {
|
||||
return alwaysGenerateSpi;
|
||||
}
|
||||
|
||||
public boolean isVerbose() {
|
||||
return verbose;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
package org.mapstruct.ap.internal.processor;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.stream.IntStream;
|
||||
import javax.annotation.processing.Filer;
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
@ -45,7 +46,7 @@ public class DefaultModelElementProcessorContext implements ProcessorContext {
|
||||
RoundContext roundContext, Map<String, String> notToBeImported) {
|
||||
|
||||
this.processingEnvironment = processingEnvironment;
|
||||
this.messager = new DelegatingMessager( processingEnvironment.getMessager() );
|
||||
this.messager = new DelegatingMessager( processingEnvironment.getMessager(), options.isVerbose() );
|
||||
this.accessorNaming = roundContext.getAnnotationProcessorContext().getAccessorNaming();
|
||||
this.versionInformation = DefaultVersionInformation.fromProcessingEnvironment( processingEnvironment );
|
||||
this.delegatingTypes = new TypesDecorator( processingEnvironment, versionInformation );
|
||||
@ -108,9 +109,11 @@ public class DefaultModelElementProcessorContext implements ProcessorContext {
|
||||
|
||||
private final Messager delegate;
|
||||
private boolean isErroneous = false;
|
||||
private final boolean verbose;
|
||||
|
||||
DelegatingMessager(Messager delegate) {
|
||||
DelegatingMessager(Messager delegate, boolean verbose) {
|
||||
this.delegate = delegate;
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -155,6 +158,15 @@ public class DefaultModelElementProcessorContext implements ProcessorContext {
|
||||
}
|
||||
}
|
||||
|
||||
public void note( int level, Message msg, Object... args ) {
|
||||
if ( verbose ) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
IntStream.range( 0, level ).mapToObj( i -> "-" ).forEach( builder::append );
|
||||
builder.append( " MapStruct: " ).append( String.format( msg.getDescription(), args ) );
|
||||
delegate.printMessage( Kind.NOTE, builder.toString() );
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isErroneous() {
|
||||
return isErroneous;
|
||||
}
|
||||
|
@ -38,9 +38,9 @@ import org.mapstruct.ap.internal.model.MappingMethod;
|
||||
import org.mapstruct.ap.internal.model.StreamMappingMethod;
|
||||
import org.mapstruct.ap.internal.model.SupportingConstructorFragment;
|
||||
import org.mapstruct.ap.internal.model.ValueMappingMethod;
|
||||
import org.mapstruct.ap.internal.model.common.FormattingParameters;
|
||||
import org.mapstruct.ap.internal.model.common.Type;
|
||||
import org.mapstruct.ap.internal.model.common.TypeFactory;
|
||||
import org.mapstruct.ap.internal.model.common.FormattingParameters;
|
||||
import org.mapstruct.ap.internal.model.source.MappingOptions;
|
||||
import org.mapstruct.ap.internal.model.source.Method;
|
||||
import org.mapstruct.ap.internal.model.source.SelectionParameters;
|
||||
@ -286,6 +286,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
boolean hasFactoryMethod = false;
|
||||
|
||||
if ( method.isIterableMapping() ) {
|
||||
this.messager.note( 1, Message.ITERABLEMAPPING_CREATE_NOTE, method );
|
||||
IterableMappingMethod iterableMappingMethod = createWithElementMappingMethod(
|
||||
method,
|
||||
mappingOptions,
|
||||
@ -313,6 +314,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
nullValueMappingStrategy = mappingOptions.getMapMapping().getNullValueMappingStrategy();
|
||||
}
|
||||
|
||||
this.messager.note( 1, Message.MAPMAPPING_CREATE_NOTE, method );
|
||||
MapMappingMethod mapMappingMethod = builder
|
||||
.mappingContext( mappingContext )
|
||||
.method( method )
|
||||
@ -328,6 +330,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
}
|
||||
else if ( method.isValueMapping() ) {
|
||||
// prefer value mappings over enum mapping
|
||||
this.messager.note( 1, Message.VALUEMAPPING_CREATE_NOTE, method );
|
||||
ValueMappingMethod valueMappingMethod = new ValueMappingMethod.Builder()
|
||||
.mappingContext( mappingContext )
|
||||
.method( method )
|
||||
@ -352,6 +355,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
}
|
||||
}
|
||||
else if ( method.isStreamMapping() ) {
|
||||
this.messager.note( 1, Message.STREAMMAPPING_CREATE_NOTE, method );
|
||||
StreamMappingMethod streamMappingMethod = createWithElementMappingMethod(
|
||||
method,
|
||||
mappingOptions,
|
||||
@ -364,8 +368,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
mappingMethods.add( streamMappingMethod );
|
||||
}
|
||||
else {
|
||||
|
||||
|
||||
this.messager.note( 1, Message.BEANMAPPING_CREATE_NOTE, method );
|
||||
BeanMappingMethod.Builder builder = new BeanMappingMethod.Builder();
|
||||
BeanMappingMethod beanMappingMethod = builder
|
||||
.mappingContext( mappingContext )
|
||||
|
@ -72,8 +72,14 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
||||
this.typeUtils = context.getTypeUtils();
|
||||
this.elementUtils = context.getElementUtils();
|
||||
|
||||
this.messager.note( 0, Message.PROCESSING_NOTE, mapperTypeElement );
|
||||
|
||||
MapperConfiguration mapperConfig = MapperConfiguration.getInstanceOn( mapperTypeElement );
|
||||
|
||||
if ( mapperConfig != null ) {
|
||||
this.messager.note( 0, Message.CONFIG_NOTE, mapperConfig.getClass().getName() );
|
||||
}
|
||||
|
||||
if ( !mapperConfig.isValid() ) {
|
||||
throw new AnnotationProcessingException(
|
||||
"Couldn't retrieve @Mapper annotation",
|
||||
|
@ -10,8 +10,10 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
import org.mapstruct.ap.spi.AccessorNamingStrategy;
|
||||
import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor;
|
||||
@ -39,12 +41,16 @@ public class AnnotationProcessorContext implements MapStructProcessingEnvironmen
|
||||
private AccessorNamingUtils accessorNaming;
|
||||
private Elements elementUtils;
|
||||
private Types typeUtils;
|
||||
private Messager messager;
|
||||
private boolean verbose;
|
||||
|
||||
public AnnotationProcessorContext(Elements elementUtils, Types typeUtils) {
|
||||
public AnnotationProcessorContext(Elements elementUtils, Types typeUtils, Messager messager, boolean verbose) {
|
||||
astModifyingAnnotationProcessors = java.util.Collections.unmodifiableList(
|
||||
findAstModifyingAnnotationProcessors() );
|
||||
this.elementUtils = elementUtils;
|
||||
this.typeUtils = typeUtils;
|
||||
this.messager = messager;
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -64,10 +70,16 @@ public class AnnotationProcessorContext implements MapStructProcessingEnvironmen
|
||||
if ( elementUtils.getTypeElement( ImmutablesConstants.IMMUTABLE_FQN ) != null ) {
|
||||
defaultAccessorNamingStrategy = new ImmutablesAccessorNamingStrategy();
|
||||
defaultBuilderProvider = new ImmutablesBuilderProvider();
|
||||
if ( verbose ) {
|
||||
messager.printMessage( Diagnostic.Kind.NOTE, "MapStruct: Immutables found on classpath" );
|
||||
}
|
||||
}
|
||||
else if ( elementUtils.getTypeElement( FreeBuilderConstants.FREE_BUILDER_FQN ) != null ) {
|
||||
defaultAccessorNamingStrategy = new FreeBuilderAccessorNamingStrategy();
|
||||
defaultBuilderProvider = new DefaultBuilderProvider();
|
||||
if ( verbose ) {
|
||||
messager.printMessage( Diagnostic.Kind.NOTE, "MapStruct: Freebuilder found on classpath" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
defaultAccessorNamingStrategy = new DefaultAccessorNamingStrategy();
|
||||
@ -75,8 +87,21 @@ public class AnnotationProcessorContext implements MapStructProcessingEnvironmen
|
||||
}
|
||||
this.accessorNamingStrategy = Services.get( AccessorNamingStrategy.class, defaultAccessorNamingStrategy );
|
||||
this.accessorNamingStrategy.init( this );
|
||||
if ( verbose ) {
|
||||
messager.printMessage(
|
||||
Diagnostic.Kind.NOTE,
|
||||
"MapStruct: Using accessor naming strategy: "
|
||||
+ this.accessorNamingStrategy.getClass().getCanonicalName()
|
||||
);
|
||||
}
|
||||
this.builderProvider = Services.get( BuilderProvider.class, defaultBuilderProvider );
|
||||
this.builderProvider.init( this );
|
||||
if ( verbose ) {
|
||||
messager.printMessage(
|
||||
Diagnostic.Kind.NOTE,
|
||||
"MapStruct: Using builder provider: " + this.builderProvider.getClass().getCanonicalName()
|
||||
);
|
||||
}
|
||||
this.accessorNaming = new AccessorNamingUtils( this.accessorNamingStrategy );
|
||||
this.initialized = true;
|
||||
}
|
||||
|
@ -67,4 +67,12 @@ public interface FormattingMessager {
|
||||
AnnotationValue v,
|
||||
Message msg,
|
||||
Object... args);
|
||||
|
||||
/**
|
||||
* Just log as plain note
|
||||
* @param level nesting level
|
||||
* @param log the log message
|
||||
* @param args the arguments
|
||||
*/
|
||||
void note(int level, Message log, Object... args);
|
||||
}
|
||||
|
@ -15,6 +15,10 @@ import javax.tools.Diagnostic;
|
||||
public enum Message {
|
||||
|
||||
// CHECKSTYLE:OFF
|
||||
PROCESSING_NOTE( "processing: %s.", Diagnostic.Kind.NOTE ),
|
||||
CONFIG_NOTE( "applying mapper configuration: %s.", Diagnostic.Kind.NOTE ),
|
||||
|
||||
BEANMAPPING_CREATE_NOTE( "creating bean mapping method implementation for %s.", Diagnostic.Kind.NOTE ),
|
||||
BEANMAPPING_NO_ELEMENTS( "'nullValueMappingStrategy', 'nullValuePropertyMappingStrategy', 'resultType' and 'qualifiedBy' are undefined in @BeanMapping, define at least one of them." ),
|
||||
BEANMAPPING_NOT_ASSIGNABLE( "%s not assignable to: %s." ),
|
||||
BEANMAPPING_ABSTRACT( "The result type %s may not be an abstract class nor interface." ),
|
||||
@ -31,6 +35,9 @@ public enum Message {
|
||||
BEANMAPPING_CYCLE_BETWEEN_PROPERTIES( "Cycle(s) between properties given via dependsOn(): %s." ),
|
||||
BEANMAPPING_UNKNOWN_PROPERTY_IN_DEPENDS_ON( "\"%s\" is no property of the method return type." ),
|
||||
|
||||
PROPERTYMAPPING_MAPPING_NOTE( "mapping property: %s to: %s.", Diagnostic.Kind.NOTE ),
|
||||
PROPERTYMAPPING_CREATE_NOTE( "creating property mapping: %s.", Diagnostic.Kind.NOTE ),
|
||||
PROPERTYMAPPING_SELECT_NOTE( "selecting property mapping: %s.", Diagnostic.Kind.NOTE ),
|
||||
PROPERTYMAPPING_MAPPING_NOT_FOUND( "Can't map %s to \"%s %s\". Consider to declare/implement a mapping method: \"%s map(%s value)\"." ),
|
||||
PROPERTYMAPPING_FORGED_MAPPING_NOT_FOUND( "Can't map %s to %s. Consider to implement a mapping method: \"%s map(%s value)\"." ),
|
||||
PROPERTYMAPPING_DUPLICATE_TARGETS( "Target property \"%s\" must not be mapped more than once." ),
|
||||
@ -67,10 +74,19 @@ public enum Message {
|
||||
CONSTANTMAPPING_NO_READ_ACCESSOR_FOR_TARGET_TYPE( "No read accessor found for property \"%s\" in target type." ),
|
||||
CONSTANTMAPPING_NON_EXISTING_CONSTANT( "Constant %s doesn't exist in enum type %s for property \"%s\"." ),
|
||||
|
||||
MAPMAPPING_CREATE_NOTE( "creating map mapping method implementation for %s.", Diagnostic.Kind.NOTE ),
|
||||
MAPMAPPING_KEY_MAPPING_NOT_FOUND( "No implementation can be generated for this method. Found no method nor implicit conversion for mapping source key type to target key type." ),
|
||||
MAPMAPPING_VALUE_MAPPING_NOT_FOUND( "No implementation can be generated for this method. Found no method nor implicit conversion for mapping source value type to target value type." ),
|
||||
MAPMAPPING_NO_ELEMENTS( "'nullValueMappingStrategy', 'keyDateFormat', 'keyQualifiedBy', 'keyTargetType', 'valueDateFormat', 'valueQualfiedBy' and 'valueTargetType' are all undefined in @MapMapping, define at least one of them." ),
|
||||
MAPMAPPING_SELECT_KEY_NOTE( "selecting key mapping: %s.", Diagnostic.Kind.NOTE ),
|
||||
MAPMAPPING_SELECT_VALUE_NOTE( "selecting value mapping: %s.", Diagnostic.Kind.NOTE ),
|
||||
MAPMAPPING_CREATE_KEY_NOTE( "creating key mapping: %s.", Diagnostic.Kind.NOTE ),
|
||||
MAPMAPPING_CREATE_VALUE_NOTE( "creating value mapping: %s.", Diagnostic.Kind.NOTE ),
|
||||
|
||||
STREAMMAPPING_CREATE_NOTE( "creating stream mapping method implementation for %s.", Diagnostic.Kind.NOTE ),
|
||||
ITERABLEMAPPING_CREATE_NOTE( "creating iterable mapping method implementation for %s.", Diagnostic.Kind.NOTE ),
|
||||
ITERABLEMAPPING_SELECT_ELEMENT_NOTE( "selecting element mapping: %s.", Diagnostic.Kind.NOTE ),
|
||||
ITERABLEMAPPING_CREATE_ELEMENT_NOTE( "creating element mapping: %s.", Diagnostic.Kind.NOTE ),
|
||||
ITERABLEMAPPING_MAPPING_NOT_FOUND( "No implementation can be generated for this method. Found no method nor implicit conversion for mapping source element type into target element type." ),
|
||||
ITERABLEMAPPING_NO_ELEMENTS( "'nullValueMappingStrategy','dateformat', 'qualifiedBy' and 'elementTargetType' are undefined in @IterableMapping, define at least one of them." ),
|
||||
|
||||
@ -128,6 +144,7 @@ public enum Message {
|
||||
INHERITINVERSECONFIGURATION_MULTIPLE_PROTOTYPE_METHODS_MATCH( "More than one configuration prototype method is applicable. Use @InheritInverseConfiguration to select one of them explicitly: %s." ),
|
||||
INHERITCONFIGURATION_CYCLE( "Cycle detected while evaluating inherited configurations. Inheritance path: %s" ),
|
||||
|
||||
VALUEMAPPING_CREATE_NOTE( "creating value mapping method implementation for %s.", Diagnostic.Kind.NOTE ),
|
||||
VALUEMAPPING_DUPLICATE_SOURCE( "Source value mapping: \"%s\" cannot be mapped more than once." ),
|
||||
VALUEMAPPING_ANY_AREADY_DEFINED( "Source = \"<ANY_REMAINING>\" or \"<ANY_UNMAPPED>\" can only be used once." ),
|
||||
VALUE_MAPPING_UNMAPPED_SOURCES( "The following constants from the %s enum have no corresponding constant in the %s enum and must be be mapped via adding additional mappings: %s." ),
|
||||
|
@ -28,4 +28,9 @@ public class ExecutableElementAccessor extends AbstractAccessor<ExecutableElemen
|
||||
public ExecutableElement getExecutable() {
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return element.toString();
|
||||
}
|
||||
}
|
||||
|
@ -29,4 +29,9 @@ public class VariableElementAccessor extends AbstractAccessor<VariableElement> {
|
||||
public ExecutableElement getExecutable() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return element.toString();
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ class IndentationCorrectingWriter extends Writer {
|
||||
* Set to true to enable output of written characters on the console.
|
||||
*/
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String LINE_SEPARATOR = System.getProperty( "line.separator" );
|
||||
private static final String LINE_SEPARATOR = System.lineSeparator( );
|
||||
private static final boolean IS_WINDOWS = System.getProperty( "os.name" ).startsWith( "Windows" );
|
||||
|
||||
private State currentState = State.START_OF_LINE;
|
||||
|
@ -280,4 +280,5 @@ public class DefaultBuilderProvider implements BuilderProvider {
|
||||
protected boolean shouldIgnore(TypeElement typeElement) {
|
||||
return typeElement == null || JAVA_JAVAX_PACKAGE.matcher( typeElement.getQualifiedName() ).matches();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -35,4 +35,5 @@ public class FreeBuilderAccessorNamingStrategy extends DefaultAccessorNamingStra
|
||||
// with set
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,4 +23,5 @@ public class ImmutablesAccessorNamingStrategy extends DefaultAccessorNamingStrat
|
||||
protected boolean isFluentSetter(ExecutableElement method) {
|
||||
return super.isFluentSetter( method ) && !method.getSimpleName().toString().equals( "from" );
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -83,4 +83,5 @@ public class ImmutablesBuilderProvider extends DefaultBuilderProvider {
|
||||
builderQualifiedName.append( "Immutable" ).append( typeElement.getSimpleName() );
|
||||
return elementUtils.getTypeElement( builderQualifiedName );
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,5 +23,6 @@ public class NoOpBuilderProvider implements BuilderProvider {
|
||||
public BuilderInfo findBuilderInfo(TypeMirror type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
// end::documentation[]
|
||||
|
@ -153,6 +153,11 @@ public class DefaultConversionContextTest {
|
||||
lastKindPrinted = msg.getDiagnosticKind();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void note(int level, Message msg, Object... args) {
|
||||
throw new UnsupportedOperationException( "Should not be called" );
|
||||
}
|
||||
|
||||
public Diagnostic.Kind getLastKindPrinted() {
|
||||
return lastKindPrinted;
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.verbose;
|
||||
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
|
||||
import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor;
|
||||
|
||||
public class AstModifyingAnnotationProcessorSaysNo implements AstModifyingAnnotationProcessor {
|
||||
|
||||
@Override
|
||||
public boolean isTypeComplete(TypeMirror type) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.verbose;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface CreateBeanMapping {
|
||||
|
||||
CreateBeanMapping INSTANCE = Mappers.getMapper( CreateBeanMapping.class );
|
||||
|
||||
Target map(Source source);
|
||||
|
||||
class Source {
|
||||
private NestedSource nested;
|
||||
|
||||
public NestedSource getNested() {
|
||||
return nested;
|
||||
}
|
||||
|
||||
public void setNested(NestedSource nested) {
|
||||
this.nested = nested;
|
||||
}
|
||||
}
|
||||
|
||||
class Target {
|
||||
private NestedTarget nested;
|
||||
|
||||
public NestedTarget getNested() {
|
||||
return nested;
|
||||
}
|
||||
|
||||
public void setNested(NestedTarget nested) {
|
||||
this.nested = nested;
|
||||
}
|
||||
}
|
||||
|
||||
class NestedSource {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
class NestedTarget {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.verbose;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface CreateIterableMapping {
|
||||
|
||||
CreateIterableMapping INSTANCE = Mappers.getMapper( CreateIterableMapping.class );
|
||||
|
||||
List<TargetElement> map(List<SourceElement> source);
|
||||
|
||||
class SourceElement {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
class TargetElement {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.verbose;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface CreateMapMapping {
|
||||
|
||||
CreateMapMapping INSTANCE = Mappers.getMapper( CreateMapMapping.class );
|
||||
|
||||
Map<TargetKey, TargetValue> map(Map<SourceKey, SourceValue> source);
|
||||
|
||||
// empty beans fail.. TODO check
|
||||
class SourceKey {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
class SourceValue {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
class TargetKey {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
class TargetValue {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.verbose;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface SelectBeanMapping {
|
||||
|
||||
SelectBeanMapping INSTANCE = Mappers.getMapper( SelectBeanMapping.class );
|
||||
|
||||
Target map(Source source);
|
||||
|
||||
NestedTarget map(NestedSource source);
|
||||
|
||||
class Source {
|
||||
private NestedSource nested;
|
||||
|
||||
public NestedSource getNested() {
|
||||
return nested;
|
||||
}
|
||||
|
||||
public void setNested(NestedSource nested) {
|
||||
this.nested = nested;
|
||||
}
|
||||
}
|
||||
|
||||
class Target {
|
||||
private NestedTarget nested;
|
||||
|
||||
public NestedTarget getNested() {
|
||||
return nested;
|
||||
}
|
||||
|
||||
public void setNested(NestedTarget nested) {
|
||||
this.nested = nested;
|
||||
}
|
||||
}
|
||||
|
||||
class NestedSource {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
class NestedTarget {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.verbose;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface SelectIterableMapping {
|
||||
|
||||
SelectIterableMapping INSTANCE = Mappers.getMapper( SelectIterableMapping.class );
|
||||
|
||||
List<TargetElement> map(List<SourceElement> source);
|
||||
|
||||
default TargetElement map(SourceElement sourceKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
class SourceElement {
|
||||
}
|
||||
|
||||
class TargetElement {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.verbose;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface SelectMapMapping {
|
||||
|
||||
SelectMapMapping INSTANCE = Mappers.getMapper( SelectMapMapping.class );
|
||||
|
||||
Map<TargetKey, TargetValue> map(Map<SourceKey, SourceValue> source);
|
||||
|
||||
default TargetKey map(SourceKey sourceKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default TargetValue map(SourceValue sourceValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
class SourceKey {
|
||||
}
|
||||
|
||||
class SourceValue {
|
||||
}
|
||||
|
||||
class TargetKey {
|
||||
}
|
||||
|
||||
class TargetValue {
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.verbose;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface SelectStreamMapping {
|
||||
|
||||
SelectStreamMapping INSTANCE = Mappers.getMapper( SelectStreamMapping.class );
|
||||
|
||||
Stream<TargetElement> map(Stream<SourceElement> source);
|
||||
|
||||
default TargetElement map(SourceElement sourceKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
class SourceElement {
|
||||
}
|
||||
|
||||
class TargetElement {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.verbose;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface ValueMapping {
|
||||
|
||||
ValueMapping INSTANCE = Mappers.getMapper( ValueMapping.class );
|
||||
|
||||
TargetEnum map(SourceEnum source);
|
||||
|
||||
enum TargetEnum { VALUE }
|
||||
|
||||
enum SourceEnum { VALUE }
|
||||
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.verbose;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mapstruct.ap.spi.AccessorNamingStrategy;
|
||||
import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor;
|
||||
import org.mapstruct.ap.spi.BuilderProvider;
|
||||
import org.mapstruct.ap.spi.ImmutablesAccessorNamingStrategy;
|
||||
import org.mapstruct.ap.spi.ImmutablesBuilderProvider;
|
||||
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
import org.mapstruct.ap.testutil.WithServiceImplementation;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedNote;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
||||
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
||||
import org.mapstruct.ap.testutil.runner.Compiler;
|
||||
import org.mapstruct.ap.testutil.runner.DisabledOnCompiler;
|
||||
|
||||
@IssueKey("37")
|
||||
@RunWith(AnnotationProcessorTestRunner.class)
|
||||
public class VerboseTest {
|
||||
|
||||
@Test
|
||||
@DisabledOnCompiler( Compiler.ECLIPSE )
|
||||
@ProcessorOption(name = "mapstruct.verbose", value = "true")
|
||||
@WithClasses(CreateBeanMapping.class)
|
||||
@ExpectedNote("^MapStruct: Using accessor naming strategy:.*DefaultAccessorNamingStrategy.*$")
|
||||
@ExpectedNote("^MapStruct: Using builder provider:.*DefaultBuilderProvider.*$")
|
||||
@ExpectedNote("^ MapStruct: processing:.*.CreateBeanMapping.*$")
|
||||
@ExpectedNote("^ MapStruct: applying mapper configuration:.*MapperConfiguration.*$")
|
||||
public void testGeneralMessages() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledOnCompiler( Compiler.ECLIPSE )
|
||||
@WithServiceImplementation(provides = BuilderProvider.class, value = ImmutablesBuilderProvider.class)
|
||||
@WithServiceImplementation(provides = AccessorNamingStrategy.class, value = ImmutablesAccessorNamingStrategy.class)
|
||||
@ProcessorOption(name = "mapstruct.verbose", value = "true")
|
||||
@WithClasses(CreateBeanMapping.class)
|
||||
@ExpectedNote("^MapStruct: Using accessor naming strategy:.*ImmutablesAccessorNamingStrategy.*$")
|
||||
@ExpectedNote("^MapStruct: Using builder provider:.*ImmutablesBuilderProvider.*$")
|
||||
@ExpectedNote("^ MapStruct: processing:.*.CreateBeanMapping.*$")
|
||||
@ExpectedNote("^ MapStruct: applying mapper configuration:.*MapperConfiguration.*$")
|
||||
public void testGeneralWithOtherSPI() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledOnCompiler( Compiler.ECLIPSE )
|
||||
@WithServiceImplementation(provides = AstModifyingAnnotationProcessor.class,
|
||||
value = AstModifyingAnnotationProcessorSaysNo.class)
|
||||
@ProcessorOption(name = "mapstruct.verbose", value = "true")
|
||||
@WithClasses(CreateBeanMapping.class)
|
||||
@ExpectedNote("^MapStruct: referred types not available \\(yet\\), deferring mapper:.*CreateBeanMapping.*$")
|
||||
public void testDeferred() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledOnCompiler( Compiler.ECLIPSE )
|
||||
@ProcessorOption(name = "mapstruct.verbose", value = "true")
|
||||
@WithClasses(CreateBeanMapping.class)
|
||||
@ExpectedNote("^- MapStruct: creating bean mapping method implementation for.*$")
|
||||
@ExpectedNote("^-- MapStruct: creating property mapping.*$")
|
||||
public void testCreateBeanMapping() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledOnCompiler( Compiler.ECLIPSE )
|
||||
@ProcessorOption(name = "mapstruct.verbose", value = "true")
|
||||
@WithClasses(SelectBeanMapping.class)
|
||||
@ExpectedNote("^- MapStruct: creating bean mapping method implementation for.*$")
|
||||
@ExpectedNote("^-- MapStruct: selecting property mapping.*$")
|
||||
public void testSelectBeanMapping() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledOnCompiler( Compiler.ECLIPSE )
|
||||
@ProcessorOption(name = "mapstruct.verbose", value = "true")
|
||||
@WithClasses(ValueMapping.class)
|
||||
@ExpectedNote("^- MapStruct: creating value mapping method implementation for.*$")
|
||||
public void testValueMapping() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledOnCompiler( Compiler.ECLIPSE )
|
||||
@ProcessorOption(name = "mapstruct.verbose", value = "true")
|
||||
@WithClasses(CreateIterableMapping.class)
|
||||
@ExpectedNote("^- MapStruct: creating iterable mapping method implementation for.*$")
|
||||
@ExpectedNote("^-- MapStruct: creating element mapping.*$")
|
||||
public void testVerboseCreateIterableMapping() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledOnCompiler( Compiler.ECLIPSE )
|
||||
@ProcessorOption(name = "mapstruct.verbose", value = "true")
|
||||
@WithClasses(SelectIterableMapping.class)
|
||||
@ExpectedNote("^- MapStruct: creating iterable mapping method implementation for.*$")
|
||||
@ExpectedNote("^-- MapStruct: selecting element mapping.*$")
|
||||
public void testVerboseSelectingIterableMapping() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledOnCompiler( Compiler.ECLIPSE )
|
||||
@ProcessorOption(name = "mapstruct.verbose", value = "true")
|
||||
@WithClasses(SelectStreamMapping.class)
|
||||
@ExpectedNote("^- MapStruct: creating stream mapping method implementation for.*$")
|
||||
public void testVerboseSelectingStreamMapping() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledOnCompiler( Compiler.ECLIPSE )
|
||||
@ProcessorOption(name = "mapstruct.verbose", value = "true")
|
||||
@WithClasses(CreateMapMapping.class)
|
||||
@ExpectedNote("^- MapStruct: creating map mapping method implementation for.*$")
|
||||
@ExpectedNote("^-- MapStruct: creating key mapping.*$")
|
||||
@ExpectedNote("^-- MapStruct: creating value mapping.*$")
|
||||
public void testVerboseCreateMapMapping() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledOnCompiler( Compiler.ECLIPSE )
|
||||
@ProcessorOption(name = "mapstruct.verbose", value = "true")
|
||||
@WithClasses(SelectMapMapping.class)
|
||||
@ExpectedNote("^- MapStruct: creating map mapping method implementation for.*$")
|
||||
@ExpectedNote("^-- MapStruct: selecting key mapping.*$")
|
||||
@ExpectedNote("^-- MapStruct: selecting value mapping.*$")
|
||||
public void testVerboseSelectingMapMapping() {
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
package org.mapstruct.ap.testutil;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@ -17,6 +18,7 @@ import java.lang.annotation.Target;
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Repeatable( WithServiceImplementations.class )
|
||||
public @interface WithServiceImplementation {
|
||||
/**
|
||||
* @return The service implementation class that is to be made available during the annotation processing.
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.testutil.compilation.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An expected {@link javax.tools.Diagnostic.Kind#NOTE}.
|
||||
*
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
|
||||
@Repeatable(ExpectedNote.ExpectedNotes.class)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface ExpectedNote {
|
||||
|
||||
String value();
|
||||
|
||||
/**
|
||||
* The notes in the order they are expected
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface ExpectedNotes {
|
||||
|
||||
/**
|
||||
* Regexp for the note to match.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
ExpectedNote[] value();
|
||||
}
|
||||
}
|
@ -8,6 +8,8 @@ package org.mapstruct.ap.testutil.compilation.model;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
@ -17,6 +19,7 @@ import org.codehaus.plexus.compiler.CompilerMessage;
|
||||
import org.codehaus.plexus.compiler.CompilerResult;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedNote;
|
||||
|
||||
/**
|
||||
* Represents the outcome of a compilation.
|
||||
@ -25,21 +28,37 @@ import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutco
|
||||
*/
|
||||
public class CompilationOutcomeDescriptor {
|
||||
|
||||
private static final String LINE_SEPARATOR = System.lineSeparator( );
|
||||
|
||||
private CompilationResult compilationResult;
|
||||
private List<DiagnosticDescriptor> diagnostics;
|
||||
private List<String> notes;
|
||||
|
||||
private CompilationOutcomeDescriptor(CompilationResult compilationResult,
|
||||
List<DiagnosticDescriptor> diagnostics) {
|
||||
List<DiagnosticDescriptor> diagnostics,
|
||||
List<String> notes) {
|
||||
this.compilationResult = compilationResult;
|
||||
this.diagnostics = diagnostics;
|
||||
this.notes = notes;
|
||||
}
|
||||
|
||||
public static CompilationOutcomeDescriptor forExpectedCompilationResult(
|
||||
ExpectedCompilationOutcome expectedCompilationResult) {
|
||||
ExpectedCompilationOutcome expectedCompilationResult, ExpectedNote.ExpectedNotes expectedNotes,
|
||||
ExpectedNote expectedNote) {
|
||||
List<String> notes = new ArrayList<>();
|
||||
if ( expectedNotes != null ) {
|
||||
notes.addAll( Stream.of( expectedNotes.value() )
|
||||
.map( ExpectedNote::value )
|
||||
.collect( Collectors.toList() ) );
|
||||
}
|
||||
if ( expectedNote != null ) {
|
||||
notes.add( expectedNote.value() );
|
||||
}
|
||||
if ( expectedCompilationResult == null ) {
|
||||
return new CompilationOutcomeDescriptor(
|
||||
CompilationResult.SUCCEEDED,
|
||||
Collections.<DiagnosticDescriptor>emptyList()
|
||||
Collections.<DiagnosticDescriptor>emptyList(),
|
||||
notes
|
||||
);
|
||||
}
|
||||
else {
|
||||
@ -48,8 +67,7 @@ public class CompilationOutcomeDescriptor {
|
||||
expectedCompilationResult.diagnostics() ) {
|
||||
diagnosticDescriptors.add( DiagnosticDescriptor.forDiagnostic( diagnostic ) );
|
||||
}
|
||||
|
||||
return new CompilationOutcomeDescriptor( expectedCompilationResult.value(), diagnosticDescriptors );
|
||||
return new CompilationOutcomeDescriptor( expectedCompilationResult.value(), diagnosticDescriptors, notes );
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,31 +75,34 @@ public class CompilationOutcomeDescriptor {
|
||||
List<Diagnostic<? extends JavaFileObject>> diagnostics) {
|
||||
CompilationResult compilationResult =
|
||||
compilationSuccessful ? CompilationResult.SUCCEEDED : CompilationResult.FAILED;
|
||||
|
||||
List<String> notes = new ArrayList<>();
|
||||
List<DiagnosticDescriptor> diagnosticDescriptors = new ArrayList<DiagnosticDescriptor>();
|
||||
for ( Diagnostic<? extends JavaFileObject> diagnostic : diagnostics ) {
|
||||
//ignore notes created by the compiler
|
||||
if ( diagnostic.getKind() != Kind.NOTE ) {
|
||||
diagnosticDescriptors.add( DiagnosticDescriptor.forDiagnostic( sourceDir, diagnostic ) );
|
||||
}
|
||||
else {
|
||||
notes.add( diagnostic.getMessage( null ) );
|
||||
}
|
||||
}
|
||||
|
||||
return new CompilationOutcomeDescriptor( compilationResult, diagnosticDescriptors );
|
||||
return new CompilationOutcomeDescriptor( compilationResult, diagnosticDescriptors, notes );
|
||||
}
|
||||
|
||||
public static CompilationOutcomeDescriptor forResult(String sourceDir, CompilerResult compilerResult) {
|
||||
CompilationResult compilationResult =
|
||||
compilerResult.isSuccess() ? CompilationResult.SUCCEEDED : CompilationResult.FAILED;
|
||||
|
||||
List<DiagnosticDescriptor> diagnosticDescriptors = new ArrayList<DiagnosticDescriptor>();
|
||||
|
||||
for ( CompilerMessage message : compilerResult.getCompilerMessages() ) {
|
||||
if ( message.getKind() != CompilerMessage.Kind.NOTE ) {
|
||||
diagnosticDescriptors.add( DiagnosticDescriptor.forCompilerMessage( sourceDir, message ) );
|
||||
}
|
||||
// the eclipse compiler does not support NOTE (it is never actually set).
|
||||
}
|
||||
|
||||
return new CompilationOutcomeDescriptor( compilationResult, diagnosticDescriptors );
|
||||
return new CompilationOutcomeDescriptor( compilationResult, diagnosticDescriptors, Collections.emptyList() );
|
||||
}
|
||||
|
||||
public CompilationResult getCompilationResult() {
|
||||
@ -92,6 +113,10 @@ public class CompilationOutcomeDescriptor {
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
public List<String> getNotes() {
|
||||
return notes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
|
@ -23,6 +23,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.runners.model.FrameworkMethod;
|
||||
import org.junit.runners.model.Statement;
|
||||
@ -32,6 +33,7 @@ import org.mapstruct.ap.testutil.WithServiceImplementations;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.DisableCheckstyle;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedNote;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOptions;
|
||||
import org.mapstruct.ap.testutil.compilation.model.CompilationOutcomeDescriptor;
|
||||
@ -54,7 +56,7 @@ abstract class CompilingStatement extends Statement {
|
||||
|
||||
private static final String TARGET_COMPILATION_TESTS = "/target/compilation-tests/";
|
||||
|
||||
private static final String LINE_SEPARATOR = System.getProperty( "line.separator" );
|
||||
private static final String LINE_SEPARATOR = System.lineSeparator( );
|
||||
|
||||
private static final DiagnosticDescriptorComparator COMPARATOR = new DiagnosticDescriptorComparator();
|
||||
|
||||
@ -175,7 +177,9 @@ abstract class CompilingStatement extends Statement {
|
||||
|
||||
CompilationOutcomeDescriptor expectedResult =
|
||||
CompilationOutcomeDescriptor.forExpectedCompilationResult(
|
||||
method.getAnnotation( ExpectedCompilationOutcome.class )
|
||||
method.getAnnotation( ExpectedCompilationOutcome.class ),
|
||||
method.getAnnotation( ExpectedNote.ExpectedNotes.class ),
|
||||
method.getAnnotation( ExpectedNote.class )
|
||||
);
|
||||
|
||||
if ( expectedResult.getCompilationResult() == CompilationResult.SUCCEEDED ) {
|
||||
@ -192,6 +196,7 @@ abstract class CompilingStatement extends Statement {
|
||||
}
|
||||
|
||||
assertDiagnostics( actualResult.getDiagnostics(), expectedResult.getDiagnostics() );
|
||||
assertNotes( actualResult.getNotes(), expectedResult.getNotes() );
|
||||
|
||||
if ( runCheckstyle ) {
|
||||
assertCheckstyleRules();
|
||||
@ -239,6 +244,30 @@ abstract class CompilingStatement extends Statement {
|
||||
return files;
|
||||
}
|
||||
|
||||
private void assertNotes(List<String> actualNotes, List<String> expectedNotes) {
|
||||
List<String> expectedNotesRemaining = new ArrayList<>( expectedNotes );
|
||||
Iterator<String> expectedNotesIterator = expectedNotesRemaining.iterator();
|
||||
if ( expectedNotesIterator.hasNext() ) {
|
||||
String expectedNoteRegexp = expectedNotesIterator.next();
|
||||
for ( String actualNote : actualNotes ) {
|
||||
if ( actualNote.matches( expectedNoteRegexp ) ) {
|
||||
expectedNotesIterator.remove();
|
||||
if ( expectedNotesIterator.hasNext() ) {
|
||||
expectedNoteRegexp = expectedNotesIterator.next();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertThat( expectedNotesRemaining )
|
||||
.describedAs( "There are unmatched notes: " +
|
||||
expectedNotesRemaining.stream().collect( Collectors.joining( LINE_SEPARATOR ) ).toString() )
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
private void assertDiagnostics(List<DiagnosticDescriptor> actualDiagnostics,
|
||||
List<DiagnosticDescriptor> expectedDiagnostics) {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user