Refactor options and add an enum (#3877)

This commit is contained in:
Filip Hrisafov 2025-06-01 07:52:18 +02:00 committed by GitHub
parent 9847eaf195
commit 46ce011e4b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 127 additions and 124 deletions

View File

@ -13,17 +13,16 @@ import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor; import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.lang.model.SourceVersion; import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element; import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind; import javax.lang.model.element.ElementKind;
@ -35,9 +34,8 @@ import javax.lang.model.util.ElementKindVisitor6;
import javax.tools.Diagnostic.Kind; import javax.tools.Diagnostic.Kind;
import org.mapstruct.ap.internal.gem.MapperGem; 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.model.Mapper;
import org.mapstruct.ap.internal.option.MappingOption;
import org.mapstruct.ap.internal.option.Options; import org.mapstruct.ap.internal.option.Options;
import org.mapstruct.ap.internal.processor.DefaultModelElementProcessorContext; import org.mapstruct.ap.internal.processor.DefaultModelElementProcessorContext;
import org.mapstruct.ap.internal.processor.ModelElementProcessor; import org.mapstruct.ap.internal.processor.ModelElementProcessor;
@ -84,19 +82,6 @@ import static javax.lang.model.element.ElementKind.CLASS;
* @author Gunnar Morling * @author Gunnar Morling
*/ */
@SupportedAnnotationTypes("org.mapstruct.Mapper") @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 { public class MappingProcessor extends AbstractProcessor {
/** /**
@ -104,20 +89,32 @@ public class MappingProcessor extends AbstractProcessor {
*/ */
private static final boolean ANNOTATIONS_CLAIMED_EXCLUSIVELY = false; private static final boolean ANNOTATIONS_CLAIMED_EXCLUSIVELY = false;
protected static final String SUPPRESS_GENERATOR_TIMESTAMP = "mapstruct.suppressGeneratorTimestamp"; // CHECKSTYLE:OFF
protected static final String SUPPRESS_GENERATOR_VERSION_INFO_COMMENT = // Deprecated options, kept for backwards compatibility.
"mapstruct.suppressGeneratorVersionInfoComment"; // They will be removed in a future release.
protected static final String UNMAPPED_TARGET_POLICY = "mapstruct.unmappedTargetPolicy"; @Deprecated
protected static final String UNMAPPED_SOURCE_POLICY = "mapstruct.unmappedSourcePolicy"; protected static final String SUPPRESS_GENERATOR_TIMESTAMP = MappingOption.SUPPRESS_GENERATOR_TIMESTAMP.getOptionName();
protected static final String DEFAULT_COMPONENT_MODEL = "mapstruct.defaultComponentModel"; @Deprecated
protected static final String DEFAULT_INJECTION_STRATEGY = "mapstruct.defaultInjectionStrategy"; protected static final String SUPPRESS_GENERATOR_VERSION_INFO_COMMENT = MappingOption.SUPPRESS_GENERATOR_VERSION_INFO_COMMENT.getOptionName();
protected static final String ALWAYS_GENERATE_SERVICE_FILE = "mapstruct.alwaysGenerateServicesFile"; @Deprecated
protected static final String DISABLE_BUILDERS = "mapstruct.disableBuilders"; protected static final String UNMAPPED_TARGET_POLICY = MappingOption.UNMAPPED_TARGET_POLICY.getOptionName();
protected static final String VERBOSE = "mapstruct.verbose"; @Deprecated
protected static final String NULL_VALUE_ITERABLE_MAPPING_STRATEGY = "mapstruct.nullValueIterableMappingStrategy"; protected static final String UNMAPPED_SOURCE_POLICY = MappingOption.UNMAPPED_SOURCE_POLICY.getOptionName();
protected static final String NULL_VALUE_MAP_MAPPING_STRATEGY = "mapstruct.nullValueMapMappingStrategy"; @Deprecated
protected static final String DISABLE_LIFECYCLE_OVERLOAD_DEDUPLICATE_SELECTOR = protected static final String DEFAULT_COMPONENT_MODEL = MappingOption.DEFAULT_COMPONENT_MODEL.getOptionName();
"mapstruct.disableLifecycleOverloadDeduplicateSelector"; @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 Set<String> additionalSupportedOptions;
private final String additionalSupportedOptionsError; private final String additionalSupportedOptionsError;
@ -156,7 +153,7 @@ public class MappingProcessor extends AbstractProcessor {
public synchronized void init(ProcessingEnvironment processingEnv) { public synchronized void init(ProcessingEnvironment processingEnv) {
super.init( processingEnv ); super.init( processingEnv );
options = createOptions(); options = new Options( processingEnv.getOptions() );
annotationProcessorContext = new AnnotationProcessorContext( annotationProcessorContext = new AnnotationProcessorContext(
processingEnv.getElementUtils(), processingEnv.getElementUtils(),
processingEnv.getTypeUtils(), processingEnv.getTypeUtils(),
@ -171,34 +168,6 @@ public class MappingProcessor extends AbstractProcessor {
} }
} }
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 @Override
public SourceVersion getSupportedSourceVersion() { public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported(); return SourceVersion.latestSupported();
@ -259,13 +228,11 @@ public class MappingProcessor extends AbstractProcessor {
@Override @Override
public Set<String> getSupportedOptions() { public Set<String> getSupportedOptions() {
Set<String> supportedOptions = super.getSupportedOptions(); return Stream.concat(
if ( additionalSupportedOptions.isEmpty() ) { Stream.of( MappingOption.values() ).map( MappingOption::getOptionName ),
return supportedOptions; additionalSupportedOptions.stream()
} )
Set<String> allSupportedOptions = new HashSet<>( supportedOptions ); .collect( Collectors.toSet() );
allSupportedOptions.addAll( additionalSupportedOptions );
return allSupportedOptions;
} }
/** /**

View File

@ -56,16 +56,18 @@ public class DefaultOptions extends DelegatingOptions {
@Override @Override
public ReportingPolicyGem unmappedTargetPolicy() { public ReportingPolicyGem unmappedTargetPolicy() {
if ( options.getUnmappedTargetPolicy() != null ) { ReportingPolicyGem unmappedTargetPolicy = options.getUnmappedTargetPolicy();
return options.getUnmappedTargetPolicy(); if ( unmappedTargetPolicy != null ) {
return unmappedTargetPolicy;
} }
return ReportingPolicyGem.valueOf( mapper.unmappedTargetPolicy().getDefaultValue() ); return ReportingPolicyGem.valueOf( mapper.unmappedTargetPolicy().getDefaultValue() );
} }
@Override @Override
public ReportingPolicyGem unmappedSourcePolicy() { public ReportingPolicyGem unmappedSourcePolicy() {
if ( options.getUnmappedSourcePolicy() != null ) { ReportingPolicyGem unmappedSourcePolicy = options.getUnmappedSourcePolicy();
return options.getUnmappedSourcePolicy(); if ( unmappedSourcePolicy != null ) {
return unmappedSourcePolicy;
} }
return ReportingPolicyGem.valueOf( mapper.unmappedSourcePolicy().getDefaultValue() ); return ReportingPolicyGem.valueOf( mapper.unmappedSourcePolicy().getDefaultValue() );
} }
@ -77,8 +79,9 @@ public class DefaultOptions extends DelegatingOptions {
@Override @Override
public String componentModel() { public String componentModel() {
if ( options.getDefaultComponentModel() != null ) { String defaultComponentModel = options.getDefaultComponentModel();
return options.getDefaultComponentModel(); if ( defaultComponentModel != null ) {
return defaultComponentModel;
} }
return mapper.componentModel().getDefaultValue(); return mapper.componentModel().getDefaultValue();
} }
@ -97,8 +100,9 @@ public class DefaultOptions extends DelegatingOptions {
@Override @Override
public InjectionStrategyGem getInjectionStrategy() { public InjectionStrategyGem getInjectionStrategy() {
if ( options.getDefaultInjectionStrategy() != null ) { String defaultInjectionStrategy = options.getDefaultInjectionStrategy();
return InjectionStrategyGem.valueOf( options.getDefaultInjectionStrategy().toUpperCase() ); if ( defaultInjectionStrategy != null ) {
return InjectionStrategyGem.valueOf( defaultInjectionStrategy.toUpperCase() );
} }
return InjectionStrategyGem.valueOf( mapper.injectionStrategy().getDefaultValue() ); return InjectionStrategyGem.valueOf( mapper.injectionStrategy().getDefaultValue() );
} }

View File

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

View File

@ -5,6 +5,9 @@
*/ */
package org.mapstruct.ap.internal.option; 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.NullValueMappingStrategyGem;
import org.mapstruct.ap.internal.gem.ReportingPolicyGem; import org.mapstruct.ap.internal.gem.ReportingPolicyGem;
@ -13,93 +16,79 @@ import org.mapstruct.ap.internal.gem.ReportingPolicyGem;
* *
* @author Andreas Gudian * @author Andreas Gudian
* @author Gunnar Morling * @author Gunnar Morling
* @author Filip Hrisafov
*/ */
public class Options { 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 private final Map<String, String> options;
public Options(boolean suppressGeneratorTimestamp, boolean suppressGeneratorVersionComment,
ReportingPolicyGem unmappedTargetPolicy, public Options(Map<String, String> options) {
ReportingPolicyGem unmappedSourcePolicy, this.options = options;
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;
} }
public boolean isSuppressGeneratorTimestamp() { public boolean isSuppressGeneratorTimestamp() {
return suppressGeneratorTimestamp; return parseBoolean( MappingOption.SUPPRESS_GENERATOR_TIMESTAMP );
} }
public boolean isSuppressGeneratorVersionComment() { public boolean isSuppressGeneratorVersionComment() {
return suppressGeneratorVersionComment; return parseBoolean( MappingOption.SUPPRESS_GENERATOR_VERSION_INFO_COMMENT );
} }
public ReportingPolicyGem getUnmappedTargetPolicy() { public ReportingPolicyGem getUnmappedTargetPolicy() {
return unmappedTargetPolicy; return parseEnum( MappingOption.UNMAPPED_TARGET_POLICY, ReportingPolicyGem.class );
} }
public ReportingPolicyGem getUnmappedSourcePolicy() { public ReportingPolicyGem getUnmappedSourcePolicy() {
return unmappedSourcePolicy; return parseEnum( MappingOption.UNMAPPED_SOURCE_POLICY, ReportingPolicyGem.class );
} }
public String getDefaultComponentModel() { public String getDefaultComponentModel() {
return defaultComponentModel; return options.get( MappingOption.DEFAULT_COMPONENT_MODEL.getOptionName() );
} }
public String getDefaultInjectionStrategy() { public String getDefaultInjectionStrategy() {
return defaultInjectionStrategy; return options.get( MappingOption.DEFAULT_INJECTION_STRATEGY.getOptionName() );
} }
public boolean isAlwaysGenerateSpi() { public boolean isAlwaysGenerateSpi() {
return alwaysGenerateSpi; return parseBoolean( MappingOption.ALWAYS_GENERATE_SERVICE_FILE );
} }
public boolean isDisableBuilders() { public boolean isDisableBuilders() {
return disableBuilders; return parseBoolean( MappingOption.DISABLE_BUILDERS );
} }
public boolean isVerbose() { public boolean isVerbose() {
return verbose; return parseBoolean( MappingOption.VERBOSE );
} }
public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() { public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() {
return nullValueIterableMappingStrategy; return parseEnum( MappingOption.NULL_VALUE_ITERABLE_MAPPING_STRATEGY, NullValueMappingStrategyGem.class );
} }
public NullValueMappingStrategyGem getNullValueMapMappingStrategy() { public NullValueMappingStrategyGem getNullValueMapMappingStrategy() {
return nullValueMapMappingStrategy; return parseEnum( MappingOption.NULL_VALUE_MAP_MAPPING_STRATEGY, NullValueMappingStrategyGem.class );
} }
public boolean isDisableLifecycleOverloadDeduplicateSelector() { 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 ) );
} }
} }