#1065 @InheritReverseConfiguration from MappingConfig

This commit is contained in:
sjaakd 2017-02-05 23:08:47 +01:00 committed by Gunnar Morling
parent 13c3d878d8
commit fa20d03051
7 changed files with 103 additions and 10 deletions

View File

@ -76,6 +76,7 @@ public class SourceMethod implements Method {
private List<String> parameterNames;
private List<SourceMethod> applicablePrototypeMethods;
private List<SourceMethod> applicableReversePrototypeMethods;
private Boolean isBeanMapping;
private Boolean isEnumMapping;
@ -312,11 +313,11 @@ public class SourceMethod implements Method {
}
public boolean reverses(SourceMethod method) {
return getDeclaringMapper() == null
&& isAbstract()
return method.getDeclaringMapper() == null
&& method.isAbstract()
&& getSourceParameters().size() == 1 && method.getSourceParameters().size() == 1
&& equals( first( getSourceParameters() ).getType(), method.getResultType() )
&& equals( getResultType(), first( method.getSourceParameters() ).getType() );
&& first( getSourceParameters() ).getType().isAssignableTo( method.getResultType() )
&& getResultType().isAssignableTo( first( method.getSourceParameters() ).getType() );
}
public boolean isSame(SourceMethod method) {
@ -486,6 +487,20 @@ public class SourceMethod implements Method {
return applicablePrototypeMethods;
}
public List<SourceMethod> getApplicableReversePrototypeMethods() {
if ( applicableReversePrototypeMethods == null ) {
applicableReversePrototypeMethods = new ArrayList<SourceMethod>();
for ( SourceMethod prototype : prototypeMethods ) {
if ( reverses( prototype ) ) {
applicableReversePrototypeMethods.add( prototype );
}
}
}
return applicableReversePrototypeMethods;
}
private static boolean allParametersAreAssignable(List<Parameter> fromParams, List<Parameter> toParams) {
if ( fromParams.size() == toParams.size() ) {
Set<Parameter> unaccountedToParams = new HashSet<Parameter>( toParams );

View File

@ -424,10 +424,15 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
initializingMethods.add( method );
MappingOptions mappingOptions = method.getMappingOptions();
List<SourceMethod> applicablePrototypeMethods = method.getApplicablePrototypeMethods();
List<SourceMethod> applicableReversePrototypeMethods = method.getApplicableReversePrototypeMethods();
MappingOptions inverseMappingOptions =
getInverseMappingOptions( availableMethods, method, initializingMethods, mapperConfig );
getInverseMappingOptions( join( availableMethods, applicableReversePrototypeMethods ),
method,
initializingMethods,
mapperConfig );
List<SourceMethod> applicablePrototypeMethods = method.getApplicablePrototypeMethods();
MappingOptions templateMappingOptions =
getTemplateMappingOptions(
@ -457,6 +462,21 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
Message.INHERITCONFIGURATION_MULTIPLE_PROTOTYPE_METHODS_MATCH,
Strings.join( applicablePrototypeMethods, ", " ) );
}
if ( applicableReversePrototypeMethods.size() == 1 ) {
mappingOptions.applyInheritedOptions(
first( applicableReversePrototypeMethods ).getMappingOptions(),
true,
method,
messager,
typeFactory );
}
else if ( applicableReversePrototypeMethods.size() > 1 ) {
messager.printMessage(
method.getExecutable(),
Message.INHERITINVERSECONFIGURATION_MULTIPLE_PROTOTYPE_METHODS_MATCH,
Strings.join( applicablePrototypeMethods, ", " ) );
}
}
mappingOptions.markAsFullyInitialized();
@ -497,7 +517,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
// method is configured as being reverse method, collect candidates
List<SourceMethod> candidates = new ArrayList<SourceMethod>();
for ( SourceMethod oneMethod : rawMethods ) {
if ( oneMethod.reverses( method ) ) {
if ( method.reverses( oneMethod ) ) {
candidates.add( oneMethod );
}
}
@ -559,7 +579,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
* Returns the configuring forward method's options in case the given method is annotated with
* {@code @InheritConfiguration} and exactly one such configuring method can unambiguously be selected (as per the
* source/target type and optionally the name given via {@code @InheritConfiguration}). The method cannot be marked
* forward mapping itself (hence 'ohter'). And neither can it contain an {@code @InheritReverseConfiguration}
* forward mapping itself (hence 'other'). And neither can it contain an {@code @InheritReverseConfiguration}
*/
private MappingOptions getTemplateMappingOptions(List<SourceMethod> rawMethods, SourceMethod method,
List<SourceMethod> initializingMethods,

View File

@ -113,6 +113,7 @@ public enum Message {
INHERITCONFIGURATION_DUPLICATE_MATCHES( "Given name \"%s\" matches several candidate methods: %s." ),
INHERITCONFIGURATION_NO_NAME_MATCH( "Given name \"%s\" does not match the only candidate. Did you mean: \"%s\"." ),
INHERITCONFIGURATION_MULTIPLE_PROTOTYPE_METHODS_MATCH( "More than one configuration prototype method is applicable. Use @InheritConfiguration to select one of them explicitly: %s." ),
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_DUPLICATE_SOURCE( "Source value mapping: \"%s\" cannot be mapped more than once." ),

View File

@ -0,0 +1,42 @@
/**
* Copyright 2012-2017 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.inheritfromconfig;
import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingInheritanceStrategy;
import org.mapstruct.factory.Mappers;
/**
* @author Andreas Gudian
*/
@Mapper(
config = AutoInheritedConfig.class,
mappingInheritanceStrategy = MappingInheritanceStrategy.EXPLICIT
)
public abstract class CarMapperReverseWithExplicitInheritance {
public static final CarMapperReverseWithExplicitInheritance INSTANCE =
Mappers.getMapper( CarMapperReverseWithExplicitInheritance.class );
@InheritInverseConfiguration(name = "baseDtoToEntity")
@Mapping( target = "colour", source = "color" )
public abstract CarDto toCarDto(CarEntity entity);
}

View File

@ -125,6 +125,21 @@ public class InheritFromConfigTest {
assertThat( carDto.getId() ).isEqualTo( 42L );
}
@Test
@IssueKey( "1065" )
@WithClasses({ CarMapperReverseWithExplicitInheritance.class } )
public void explicitInheritedMappingIsAppliedInReverseDirectlyFromConfig() {
CarEntity carEntity = new CarEntity();
carEntity.setColor( "red" );
carEntity.setPrimaryKey( 42L );
CarDto carDto = CarMapperReverseWithExplicitInheritance.INSTANCE.toCarDto( carEntity );
assertThat( carDto.getColour() ).isEqualTo( "red" );
assertThat( carDto.getId() ).isEqualTo( 42L );
}
@Test
public void explicitInheritedMappingWithTwoLevelsIsOverriddenAtMethodLevel() {
CarDto carDto = newTestDto();

View File

@ -37,5 +37,5 @@ public interface ArtistToChartEntryConfig {
@Mapping(target = "artistName", source = "artist.name"),
@Mapping(target = "chartName", ignore = true )
})
BaseChartEntry mapForward( Song song );
BaseChartEntry mapForwardConfig( Song song );
}

View File

@ -44,7 +44,7 @@ public abstract class ArtistToChartEntryWithConfigReverse {
})
abstract ChartEntryWithBase mapForward(Song song);
@InheritInverseConfiguration
@InheritInverseConfiguration( name = "mapForward" )
@Mapping(target = "positions", ignore = true)
abstract Song mapReverse(ChartEntryWithBase ce);
}