Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 34 additions & 67 deletions processor/src/main/java/org/mapstruct/ap/MappingProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,16 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
Expand All @@ -35,9 +34,8 @@
import javax.tools.Diagnostic.Kind;

import org.mapstruct.ap.internal.gem.MapperGem;
import org.mapstruct.ap.internal.gem.NullValueMappingStrategyGem;
import org.mapstruct.ap.internal.gem.ReportingPolicyGem;
import org.mapstruct.ap.internal.model.Mapper;
import org.mapstruct.ap.internal.option.MappingOption;
import org.mapstruct.ap.internal.option.Options;
import org.mapstruct.ap.internal.processor.DefaultModelElementProcessorContext;
import org.mapstruct.ap.internal.processor.ModelElementProcessor;
Expand Down Expand Up @@ -84,40 +82,39 @@
* @author Gunnar Morling
*/
@SupportedAnnotationTypes("org.mapstruct.Mapper")
@SupportedOptions({
MappingProcessor.SUPPRESS_GENERATOR_TIMESTAMP,
MappingProcessor.SUPPRESS_GENERATOR_VERSION_INFO_COMMENT,
MappingProcessor.UNMAPPED_TARGET_POLICY,
MappingProcessor.UNMAPPED_SOURCE_POLICY,
MappingProcessor.DEFAULT_COMPONENT_MODEL,
MappingProcessor.DEFAULT_INJECTION_STRATEGY,
MappingProcessor.DISABLE_BUILDERS,
MappingProcessor.VERBOSE,
MappingProcessor.NULL_VALUE_ITERABLE_MAPPING_STRATEGY,
MappingProcessor.NULL_VALUE_MAP_MAPPING_STRATEGY,
MappingProcessor.DISABLE_LIFECYCLE_OVERLOAD_DEDUPLICATE_SELECTOR,
})
public class MappingProcessor extends AbstractProcessor {

/**
* Whether this processor claims all processed annotations exclusively or not.
*/
private static final boolean ANNOTATIONS_CLAIMED_EXCLUSIVELY = false;

protected static final String SUPPRESS_GENERATOR_TIMESTAMP = "mapstruct.suppressGeneratorTimestamp";
protected static final String SUPPRESS_GENERATOR_VERSION_INFO_COMMENT =
"mapstruct.suppressGeneratorVersionInfoComment";
protected static final String UNMAPPED_TARGET_POLICY = "mapstruct.unmappedTargetPolicy";
protected static final String UNMAPPED_SOURCE_POLICY = "mapstruct.unmappedSourcePolicy";
protected static final String DEFAULT_COMPONENT_MODEL = "mapstruct.defaultComponentModel";
protected static final String DEFAULT_INJECTION_STRATEGY = "mapstruct.defaultInjectionStrategy";
protected static final String ALWAYS_GENERATE_SERVICE_FILE = "mapstruct.alwaysGenerateServicesFile";
protected static final String DISABLE_BUILDERS = "mapstruct.disableBuilders";
protected static final String VERBOSE = "mapstruct.verbose";
protected static final String NULL_VALUE_ITERABLE_MAPPING_STRATEGY = "mapstruct.nullValueIterableMappingStrategy";
protected static final String NULL_VALUE_MAP_MAPPING_STRATEGY = "mapstruct.nullValueMapMappingStrategy";
protected static final String DISABLE_LIFECYCLE_OVERLOAD_DEDUPLICATE_SELECTOR =
"mapstruct.disableLifecycleOverloadDeduplicateSelector";
// CHECKSTYLE:OFF
// Deprecated options, kept for backwards compatibility.
// They will be removed in a future release.
@Deprecated
protected static final String SUPPRESS_GENERATOR_TIMESTAMP = MappingOption.SUPPRESS_GENERATOR_TIMESTAMP.getOptionName();
@Deprecated
protected static final String SUPPRESS_GENERATOR_VERSION_INFO_COMMENT = MappingOption.SUPPRESS_GENERATOR_VERSION_INFO_COMMENT.getOptionName();
@Deprecated
protected static final String UNMAPPED_TARGET_POLICY = MappingOption.UNMAPPED_TARGET_POLICY.getOptionName();
@Deprecated
protected static final String UNMAPPED_SOURCE_POLICY = MappingOption.UNMAPPED_SOURCE_POLICY.getOptionName();
@Deprecated
protected static final String DEFAULT_COMPONENT_MODEL = MappingOption.DEFAULT_COMPONENT_MODEL.getOptionName();
@Deprecated
protected static final String DEFAULT_INJECTION_STRATEGY = MappingOption.DEFAULT_INJECTION_STRATEGY.getOptionName();
@Deprecated
protected static final String ALWAYS_GENERATE_SERVICE_FILE = MappingOption.ALWAYS_GENERATE_SERVICE_FILE.getOptionName();
@Deprecated
protected static final String DISABLE_BUILDERS = MappingOption.DISABLE_BUILDERS.getOptionName();
@Deprecated
protected static final String VERBOSE = MappingOption.VERBOSE.getOptionName();
@Deprecated
protected static final String NULL_VALUE_ITERABLE_MAPPING_STRATEGY = MappingOption.NULL_VALUE_ITERABLE_MAPPING_STRATEGY.getOptionName();
@Deprecated
protected static final String NULL_VALUE_MAP_MAPPING_STRATEGY = MappingOption.NULL_VALUE_MAP_MAPPING_STRATEGY.getOptionName();
// CHECKSTYLE:ON

private final Set<String> additionalSupportedOptions;
private final String additionalSupportedOptionsError;
Expand Down Expand Up @@ -156,7 +153,7 @@ public MappingProcessor() {
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init( processingEnv );

options = createOptions();
options = new Options( processingEnv.getOptions() );
annotationProcessorContext = new AnnotationProcessorContext(
processingEnv.getElementUtils(),
processingEnv.getTypeUtils(),
Expand All @@ -171,34 +168,6 @@ public synchronized void init(ProcessingEnvironment processingEnv) {
}
}

private Options createOptions() {
String unmappedTargetPolicy = processingEnv.getOptions().get( UNMAPPED_TARGET_POLICY );
String unmappedSourcePolicy = processingEnv.getOptions().get( UNMAPPED_SOURCE_POLICY );
String nullValueIterableMappingStrategy = processingEnv.getOptions()
.get( NULL_VALUE_ITERABLE_MAPPING_STRATEGY );
String nullValueMapMappingStrategy = processingEnv.getOptions().get( NULL_VALUE_MAP_MAPPING_STRATEGY );
String disableLifecycleOverloadDeduplicateSelector = processingEnv.getOptions()
.get( DISABLE_LIFECYCLE_OVERLOAD_DEDUPLICATE_SELECTOR );

return new Options(
Boolean.parseBoolean( processingEnv.getOptions().get( SUPPRESS_GENERATOR_TIMESTAMP ) ),
Boolean.parseBoolean( processingEnv.getOptions().get( SUPPRESS_GENERATOR_VERSION_INFO_COMMENT ) ),
unmappedTargetPolicy != null ? ReportingPolicyGem.valueOf( unmappedTargetPolicy.toUpperCase() ) : null,
unmappedSourcePolicy != null ? ReportingPolicyGem.valueOf( unmappedSourcePolicy.toUpperCase() ) : null,
processingEnv.getOptions().get( DEFAULT_COMPONENT_MODEL ),
processingEnv.getOptions().get( DEFAULT_INJECTION_STRATEGY ),
Boolean.parseBoolean( processingEnv.getOptions().get( ALWAYS_GENERATE_SERVICE_FILE ) ),
Boolean.parseBoolean( processingEnv.getOptions().get( DISABLE_BUILDERS ) ),
Boolean.parseBoolean( processingEnv.getOptions().get( VERBOSE ) ),
nullValueIterableMappingStrategy != null ?
NullValueMappingStrategyGem.valueOf( nullValueIterableMappingStrategy.toUpperCase( Locale.ROOT ) ) :
null,
nullValueMapMappingStrategy != null ?
NullValueMappingStrategyGem.valueOf( nullValueMapMappingStrategy.toUpperCase( Locale.ROOT ) ) : null,
Boolean.parseBoolean( disableLifecycleOverloadDeduplicateSelector )
);
}

@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
Expand Down Expand Up @@ -259,13 +228,11 @@ else if ( !deferredMappers.isEmpty() ) {

@Override
public Set<String> getSupportedOptions() {
Set<String> supportedOptions = super.getSupportedOptions();
if ( additionalSupportedOptions.isEmpty() ) {
return supportedOptions;
}
Set<String> allSupportedOptions = new HashSet<>( supportedOptions );
allSupportedOptions.addAll( additionalSupportedOptions );
return allSupportedOptions;
return Stream.concat(
Stream.of( MappingOption.values() ).map( MappingOption::getOptionName ),
additionalSupportedOptions.stream()
)
.collect( Collectors.toSet() );
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,18 @@ public Set<DeclaredType> imports() {

@Override
public ReportingPolicyGem unmappedTargetPolicy() {
if ( options.getUnmappedTargetPolicy() != null ) {
return options.getUnmappedTargetPolicy();
ReportingPolicyGem unmappedTargetPolicy = options.getUnmappedTargetPolicy();
if ( unmappedTargetPolicy != null ) {
return unmappedTargetPolicy;
}
return ReportingPolicyGem.valueOf( mapper.unmappedTargetPolicy().getDefaultValue() );
}

@Override
public ReportingPolicyGem unmappedSourcePolicy() {
if ( options.getUnmappedSourcePolicy() != null ) {
return options.getUnmappedSourcePolicy();
ReportingPolicyGem unmappedSourcePolicy = options.getUnmappedSourcePolicy();
if ( unmappedSourcePolicy != null ) {
return unmappedSourcePolicy;
}
return ReportingPolicyGem.valueOf( mapper.unmappedSourcePolicy().getDefaultValue() );
}
Expand All @@ -77,8 +79,9 @@ public ReportingPolicyGem typeConversionPolicy() {

@Override
public String componentModel() {
if ( options.getDefaultComponentModel() != null ) {
return options.getDefaultComponentModel();
String defaultComponentModel = options.getDefaultComponentModel();
if ( defaultComponentModel != null ) {
return defaultComponentModel;
}
return mapper.componentModel().getDefaultValue();
}
Expand All @@ -97,8 +100,9 @@ public MappingInheritanceStrategyGem getMappingInheritanceStrategy() {

@Override
public InjectionStrategyGem getInjectionStrategy() {
if ( options.getDefaultInjectionStrategy() != null ) {
return InjectionStrategyGem.valueOf( options.getDefaultInjectionStrategy().toUpperCase() );
String defaultInjectionStrategy = options.getDefaultInjectionStrategy();
if ( defaultInjectionStrategy != null ) {
return InjectionStrategyGem.valueOf( defaultInjectionStrategy.toUpperCase() );
}
return InjectionStrategyGem.valueOf( mapper.injectionStrategy().getDefaultValue() );
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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.internal.option;

/**
* @author Filip Hrisafov
*/
public enum MappingOption {

// CHECKSTYLE:OFF
SUPPRESS_GENERATOR_TIMESTAMP( "mapstruct.suppressGeneratorTimestamp" ),
SUPPRESS_GENERATOR_VERSION_INFO_COMMENT( "mapstruct.suppressGeneratorVersionInfoComment" ),
UNMAPPED_TARGET_POLICY("mapstruct.unmappedTargetPolicy"),
UNMAPPED_SOURCE_POLICY("mapstruct.unmappedSourcePolicy"),
DEFAULT_COMPONENT_MODEL("mapstruct.defaultComponentModel"),
DEFAULT_INJECTION_STRATEGY("mapstruct.defaultInjectionStrategy"),
ALWAYS_GENERATE_SERVICE_FILE("mapstruct.alwaysGenerateServicesFile"),
DISABLE_BUILDERS("mapstruct.disableBuilders"),
VERBOSE("mapstruct.verbose"),
NULL_VALUE_ITERABLE_MAPPING_STRATEGY("mapstruct.nullValueIterableMappingStrategy"),
NULL_VALUE_MAP_MAPPING_STRATEGY("mapstruct.nullValueMapMappingStrategy"),
DISABLE_LIFECYCLE_OVERLOAD_DEDUPLICATE_SELECTOR("mapstruct.disableLifecycleOverloadDeduplicateSelector"),
;
// CHECKSTYLE:ON

private final String optionName;

MappingOption(String optionName) {
this.optionName = optionName;
}

/**
* Returns the name of the option, which can be used in the compiler arguments.
*
* @return the name of the option
*/
public String getOptionName() {
return optionName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
*/
package org.mapstruct.ap.internal.option;

import java.util.Locale;
import java.util.Map;

import org.mapstruct.ap.internal.gem.NullValueMappingStrategyGem;
import org.mapstruct.ap.internal.gem.ReportingPolicyGem;

Expand All @@ -13,93 +16,79 @@
*
* @author Andreas Gudian
* @author Gunnar Morling
* @author Filip Hrisafov
*/
public class Options {
private final boolean suppressGeneratorTimestamp;
private final boolean suppressGeneratorVersionComment;
private final ReportingPolicyGem unmappedTargetPolicy;
private final ReportingPolicyGem unmappedSourcePolicy;
private final boolean alwaysGenerateSpi;
private final String defaultComponentModel;
private final String defaultInjectionStrategy;
private final boolean disableBuilders;
private final boolean verbose;
private final NullValueMappingStrategyGem nullValueIterableMappingStrategy;
private final NullValueMappingStrategyGem nullValueMapMappingStrategy;
private final boolean disableLifecycleOverloadDeduplicateSelector;

//CHECKSTYLE:OFF
public Options(boolean suppressGeneratorTimestamp, boolean suppressGeneratorVersionComment,
ReportingPolicyGem unmappedTargetPolicy,
ReportingPolicyGem unmappedSourcePolicy,
String defaultComponentModel, String defaultInjectionStrategy,
boolean alwaysGenerateSpi,
boolean disableBuilders,
boolean verbose,
NullValueMappingStrategyGem nullValueIterableMappingStrategy,
NullValueMappingStrategyGem nullValueMapMappingStrategy,
boolean disableLifecycleOverloadDeduplicateSelector
) {
//CHECKSTYLE:ON
this.suppressGeneratorTimestamp = suppressGeneratorTimestamp;
this.suppressGeneratorVersionComment = suppressGeneratorVersionComment;
this.unmappedTargetPolicy = unmappedTargetPolicy;
this.unmappedSourcePolicy = unmappedSourcePolicy;
this.defaultComponentModel = defaultComponentModel;
this.defaultInjectionStrategy = defaultInjectionStrategy;
this.alwaysGenerateSpi = alwaysGenerateSpi;
this.disableBuilders = disableBuilders;
this.verbose = verbose;
this.nullValueIterableMappingStrategy = nullValueIterableMappingStrategy;
this.nullValueMapMappingStrategy = nullValueMapMappingStrategy;
this.disableLifecycleOverloadDeduplicateSelector = disableLifecycleOverloadDeduplicateSelector;

private final Map<String, String> options;

public Options(Map<String, String> options) {
this.options = options;
}

public boolean isSuppressGeneratorTimestamp() {
return suppressGeneratorTimestamp;
return parseBoolean( MappingOption.SUPPRESS_GENERATOR_TIMESTAMP );
}

public boolean isSuppressGeneratorVersionComment() {
return suppressGeneratorVersionComment;
return parseBoolean( MappingOption.SUPPRESS_GENERATOR_VERSION_INFO_COMMENT );
}

public ReportingPolicyGem getUnmappedTargetPolicy() {
return unmappedTargetPolicy;
return parseEnum( MappingOption.UNMAPPED_TARGET_POLICY, ReportingPolicyGem.class );
}

public ReportingPolicyGem getUnmappedSourcePolicy() {
return unmappedSourcePolicy;
return parseEnum( MappingOption.UNMAPPED_SOURCE_POLICY, ReportingPolicyGem.class );
}

public String getDefaultComponentModel() {
return defaultComponentModel;
return options.get( MappingOption.DEFAULT_COMPONENT_MODEL.getOptionName() );
}

public String getDefaultInjectionStrategy() {
return defaultInjectionStrategy;
return options.get( MappingOption.DEFAULT_INJECTION_STRATEGY.getOptionName() );
}

public boolean isAlwaysGenerateSpi() {
return alwaysGenerateSpi;
return parseBoolean( MappingOption.ALWAYS_GENERATE_SERVICE_FILE );
}

public boolean isDisableBuilders() {
return disableBuilders;
return parseBoolean( MappingOption.DISABLE_BUILDERS );
}

public boolean isVerbose() {
return verbose;
return parseBoolean( MappingOption.VERBOSE );
}

public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() {
return nullValueIterableMappingStrategy;
return parseEnum( MappingOption.NULL_VALUE_ITERABLE_MAPPING_STRATEGY, NullValueMappingStrategyGem.class );
}

public NullValueMappingStrategyGem getNullValueMapMappingStrategy() {
return nullValueMapMappingStrategy;
return parseEnum( MappingOption.NULL_VALUE_MAP_MAPPING_STRATEGY, NullValueMappingStrategyGem.class );
}

public boolean isDisableLifecycleOverloadDeduplicateSelector() {
return disableLifecycleOverloadDeduplicateSelector;
return parseBoolean( MappingOption.DISABLE_LIFECYCLE_OVERLOAD_DEDUPLICATE_SELECTOR );
}

private boolean parseBoolean(MappingOption option) {
if ( options.isEmpty() ) {
return false;
}
return Boolean.parseBoolean( options.get( option.getOptionName() ) );
}

private <E extends Enum<E>> E parseEnum(MappingOption option, Class<E> enumType) {
if ( options.isEmpty() ) {
return null;
}
String value = options.get( option.getOptionName() );
if ( value == null ) {
return null;
}
return Enum.valueOf( enumType, value.toUpperCase( Locale.ROOT ) );
}
}