#880 Fix override behaviour for componentModel and unmappedTargetPolicy.

This commit is contained in:
Andreas Gudian 2016-09-01 22:31:21 +02:00
parent c73d007fc8
commit 8071723bae
10 changed files with 200 additions and 70 deletions

View File

@ -127,13 +127,12 @@ 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.toUpperCase() ) : null,
defaultComponentModel == null ? "default" : defaultComponentModel, processingEnv.getOptions().get( DEFAULT_COMPONENT_MODEL ),
Boolean.valueOf( processingEnv.getOptions().get( ALWAYS_GENERATE_SERVICE_FILE ) ) Boolean.valueOf( processingEnv.getOptions().get( ALWAYS_GENERATE_SERVICE_FILE ) )
); );
} }

View File

@ -508,32 +508,16 @@ public class BeanMappingMethod extends MappingMethod {
return method.getResultType().getPropertyReadAccessors().get( propertyName ); return method.getResultType().getPropertyReadAccessors().get( propertyName );
} }
/** private ReportingPolicy getUnmappedTargetPolicy() {
* Returns the effective policy for reporting unmapped getReturnType properties. If explicitly set via
* {@code Mapper}, this value will be returned. Otherwise the value from the corresponding processor option will
* be returned. If that is not set either, the default value from {@code Mapper#unmappedTargetPolicy()} will be
* returned.
*
* @return The effective policy for reporting unmapped target properties.
*/
private ReportingPolicy getEffectiveUnmappedTargetPolicy() {
MapperConfiguration mapperSettings = MapperConfiguration.getInstanceOn( ctx.getMapperTypeElement() ); MapperConfiguration mapperSettings = MapperConfiguration.getInstanceOn( ctx.getMapperTypeElement() );
boolean setViaAnnotation = mapperSettings.isSetUnmappedTargetPolicy();
ReportingPolicy annotationValue = ReportingPolicy.valueOf( mapperSettings.unmappedTargetPolicy() );
if ( setViaAnnotation return mapperSettings.unmappedTargetPolicy( ctx.getOptions() );
|| ctx.getOptions().getUnmappedTargetPolicy() == null ) {
return annotationValue;
}
else {
return ctx.getOptions().getUnmappedTargetPolicy();
}
} }
private void reportErrorForUnmappedTargetPropertiesIfRequired() { private void reportErrorForUnmappedTargetPropertiesIfRequired() {
// fetch settings from element to implement // fetch settings from element to implement
ReportingPolicy unmappedTargetPolicy = getEffectiveUnmappedTargetPolicy(); ReportingPolicy unmappedTargetPolicy = getUnmappedTargetPolicy();
if ( !unprocessedTargetProperties.isEmpty() && unmappedTargetPolicy.requiresReport() ) { if ( !unprocessedTargetProperties.isEmpty() && unmappedTargetPolicy.requiresReport() ) {

View File

@ -32,7 +32,6 @@ import org.mapstruct.ap.internal.model.Field;
import org.mapstruct.ap.internal.model.Mapper; import org.mapstruct.ap.internal.model.Mapper;
import org.mapstruct.ap.internal.model.MapperReference; import org.mapstruct.ap.internal.model.MapperReference;
import org.mapstruct.ap.internal.model.common.TypeFactory; import org.mapstruct.ap.internal.model.common.TypeFactory;
import org.mapstruct.ap.internal.option.OptionsHelper;
import org.mapstruct.ap.internal.util.MapperConfiguration; import org.mapstruct.ap.internal.util.MapperConfiguration;
/** /**
@ -51,13 +50,10 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle
public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, Mapper mapper) { public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, Mapper mapper) {
this.typeFactory = context.getTypeFactory(); this.typeFactory = context.getTypeFactory();
String componentModel = MapperConfiguration.getInstanceOn( mapperTypeElement ).componentModel(); String componentModel = MapperConfiguration.getInstanceOn( mapperTypeElement )
String effectiveComponentModel = OptionsHelper.getEffectiveComponentModel( .componentModel( context.getOptions() );
context.getOptions(),
componentModel
);
if ( !getComponentModelIdentifier().equalsIgnoreCase( effectiveComponentModel ) ) { if ( !getComponentModelIdentifier().equalsIgnoreCase( componentModel ) ) {
return mapper; return mapper;
} }

View File

@ -28,7 +28,6 @@ import javax.tools.StandardLocation;
import org.mapstruct.ap.internal.model.GeneratedType; import org.mapstruct.ap.internal.model.GeneratedType;
import org.mapstruct.ap.internal.model.Mapper; import org.mapstruct.ap.internal.model.Mapper;
import org.mapstruct.ap.internal.model.ServicesEntry; 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.util.MapperConfiguration;
import org.mapstruct.ap.internal.writer.ModelWriter; import org.mapstruct.ap.internal.writer.ModelWriter;
@ -50,13 +49,10 @@ public class MapperServiceProcessor implements ModelElementProcessor<Mapper, Vo
spiGenerationNeeded = true; spiGenerationNeeded = true;
} }
else { else {
String componentModel = MapperConfiguration.getInstanceOn( mapperTypeElement ).componentModel(); String componentModel =
String effectiveComponentModel = OptionsHelper.getEffectiveComponentModel( MapperConfiguration.getInstanceOn( mapperTypeElement ).componentModel( context.getOptions() );
context.getOptions(),
componentModel
);
spiGenerationNeeded = "default".equals( effectiveComponentModel ); spiGenerationNeeded = "default".equals( componentModel );
} }
if ( !context.isErroneous() && spiGenerationNeeded && mapper.hasCustomImplementation() ) { if ( !context.isErroneous() && spiGenerationNeeded && mapper.hasCustomImplementation() ) {

View File

@ -27,12 +27,14 @@ import javax.lang.model.element.Element;
import javax.lang.model.type.DeclaredType; import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import org.mapstruct.ap.internal.option.Options;
import org.mapstruct.ap.internal.option.ReportingPolicy;
import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism; import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism;
import org.mapstruct.ap.internal.prism.MapperConfigPrism; import org.mapstruct.ap.internal.prism.MapperConfigPrism;
import org.mapstruct.ap.internal.prism.MapperPrism; import org.mapstruct.ap.internal.prism.MapperPrism;
import org.mapstruct.ap.internal.prism.MappingInheritanceStrategyPrism; import org.mapstruct.ap.internal.prism.MappingInheritanceStrategyPrism;
import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism;
import org.mapstruct.ap.internal.prism.NullValueCheckStrategyPrism; import org.mapstruct.ap.internal.prism.NullValueCheckStrategyPrism;
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
@ -109,13 +111,21 @@ public class MapperConfiguration {
return mapperPrism.imports(); return mapperPrism.imports();
} }
public String unmappedTargetPolicy() { public ReportingPolicy unmappedTargetPolicy(Options options) {
if ( mapperConfigPrism != null && mapperPrism.values.unmappedTargetPolicy() == null ) { if ( mapperPrism.values.unmappedTargetPolicy() != null ) {
return mapperConfigPrism.unmappedTargetPolicy(); return ReportingPolicy.valueOf( mapperPrism.unmappedTargetPolicy() );
} }
else {
return mapperPrism.unmappedTargetPolicy(); if ( mapperConfigPrism != null && mapperConfigPrism.values.unmappedTargetPolicy() != null ) {
return ReportingPolicy.valueOf( mapperConfigPrism.unmappedTargetPolicy() );
} }
if ( options.getUnmappedTargetPolicy() != null ) {
return options.getUnmappedTargetPolicy();
}
// fall back to default defined in the annotation
return ReportingPolicy.valueOf( mapperPrism.unmappedTargetPolicy() );
} }
public CollectionMappingStrategyPrism getCollectionMappingStrategy() { public CollectionMappingStrategyPrism getCollectionMappingStrategy() {
@ -169,13 +179,20 @@ public class MapperConfiguration {
} }
public String componentModel() { public String componentModel(Options options) {
if ( mapperConfigPrism != null && mapperPrism.values.componentModel() == null ) { if ( mapperPrism.values.componentModel() != null ) {
return mapperConfigPrism.componentModel();
}
else {
return mapperPrism.componentModel(); return mapperPrism.componentModel();
} }
if ( mapperConfigPrism != null && mapperConfigPrism.values.componentModel() != null ) {
return mapperConfigPrism.componentModel();
}
if ( options.getDefaultComponentModel() != null ) {
return options.getDefaultComponentModel();
}
return mapperPrism.componentModel(); // fall back to default defined in the annotation
} }
public DeclaredType config() { public DeclaredType config() {
@ -186,12 +203,7 @@ public class MapperConfiguration {
return mapperPrism.isValid; return mapperPrism.isValid;
} }
public boolean isSetUnmappedTargetPolicy() {
return mapperPrism.values.unmappedTargetPolicy() != null;
}
public AnnotationMirror getAnnotationMirror() { public AnnotationMirror getAnnotationMirror() {
return mapperPrism.mirror; return mapperPrism.mirror;
} }
} }

View File

@ -0,0 +1,30 @@
/**
* Copyright 2012-2016 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.bugs._880;
import org.mapstruct.MapperConfig;
import org.mapstruct.ReportingPolicy;
/**
* @author Andreas Gudian
*/
@MapperConfig(unmappedTargetPolicy = ReportingPolicy.WARN)
public interface Config {
}

View File

@ -0,0 +1,30 @@
/**
* Copyright 2012-2016 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.bugs._880;
import org.mapstruct.Mapper;
/**
* @author Andreas Gudian
*
*/
@Mapper
public interface DefaultsToProcessorOptionsMapper {
Poodle metamorph(Object essence);
}

View File

@ -0,0 +1,63 @@
/**
* Copyright 2012-2016 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.bugs._880;
import javax.tools.Diagnostic.Kind;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic;
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOptions;
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
import org.mapstruct.ap.testutil.runner.GeneratedSource;
import org.springframework.stereotype.Component;
/**
* @author Andreas Gudian
*/
@RunWith(AnnotationProcessorTestRunner.class)
@WithClasses({
UsesConfigFromAnnotationMapper.class,
DefaultsToProcessorOptionsMapper.class,
Poodle.class,
Config.class })
@ProcessorOptions({
@ProcessorOption(name = "mapstruct.defaultComponentModel", value = "spring"),
@ProcessorOption(name = "mapstruct.unmappedTargetPolicy", value = "ignore") })
public class Issue880Test {
@Rule
public GeneratedSource generatedSource = new GeneratedSource();
@Test
@ExpectedCompilationOutcome(
value = CompilationResult.SUCCEEDED,
diagnostics = @Diagnostic(kind = Kind.WARNING,
type = UsesConfigFromAnnotationMapper.class, line = 29,
messageRegExp = "Unmapped target property: \"core\"\\."))
public void compilationSucceedsAndAppliesCorrectComponentModel() {
generatedSource.forMapper( UsesConfigFromAnnotationMapper.class ).containsNoImportFor( Component.class );
generatedSource.forMapper( DefaultsToProcessorOptionsMapper.class ).containsImportFor( Component.class );
}
}

View File

@ -16,30 +16,20 @@
* 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.ap.internal.option; package org.mapstruct.ap.test.bugs._880;
/** /**
* Helper class for dealing with {@link Options}.
*
* @author Andreas Gudian * @author Andreas Gudian
*
*/ */
public class OptionsHelper { public class Poodle {
private String core;
private OptionsHelper() { public String getCore() {
return core;
} }
/** public void setCore(String core) {
* @param options the options this.core = core;
* @param locallyDeclaredComponentModel the locally declared component model
*
* @return the effective component model to be used
*/
public static String getEffectiveComponentModel(Options options, String locallyDeclaredComponentModel) {
if ( "default".equals( locallyDeclaredComponentModel ) ) {
return options.getDefaultComponentModel();
}
return locallyDeclaredComponentModel;
} }
} }

View File

@ -0,0 +1,30 @@
/**
* Copyright 2012-2016 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.bugs._880;
import org.mapstruct.Mapper;
/**
* @author Andreas Gudian
*
*/
@Mapper(componentModel = "default", config = Config.class)
public interface UsesConfigFromAnnotationMapper {
Poodle metamorph(Object essence);
}