mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#1065 @InheritReverseConfiguration from MappingConfig
This commit is contained in:
parent
13c3d878d8
commit
fa20d03051
@ -76,6 +76,7 @@ public class SourceMethod implements Method {
|
|||||||
private List<String> parameterNames;
|
private List<String> parameterNames;
|
||||||
|
|
||||||
private List<SourceMethod> applicablePrototypeMethods;
|
private List<SourceMethod> applicablePrototypeMethods;
|
||||||
|
private List<SourceMethod> applicableReversePrototypeMethods;
|
||||||
|
|
||||||
private Boolean isBeanMapping;
|
private Boolean isBeanMapping;
|
||||||
private Boolean isEnumMapping;
|
private Boolean isEnumMapping;
|
||||||
@ -312,11 +313,11 @@ public class SourceMethod implements Method {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean reverses(SourceMethod method) {
|
public boolean reverses(SourceMethod method) {
|
||||||
return getDeclaringMapper() == null
|
return method.getDeclaringMapper() == null
|
||||||
&& isAbstract()
|
&& method.isAbstract()
|
||||||
&& getSourceParameters().size() == 1 && method.getSourceParameters().size() == 1
|
&& getSourceParameters().size() == 1 && method.getSourceParameters().size() == 1
|
||||||
&& equals( first( getSourceParameters() ).getType(), method.getResultType() )
|
&& first( getSourceParameters() ).getType().isAssignableTo( method.getResultType() )
|
||||||
&& equals( getResultType(), first( method.getSourceParameters() ).getType() );
|
&& getResultType().isAssignableTo( first( method.getSourceParameters() ).getType() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSame(SourceMethod method) {
|
public boolean isSame(SourceMethod method) {
|
||||||
@ -486,6 +487,20 @@ public class SourceMethod implements Method {
|
|||||||
return applicablePrototypeMethods;
|
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) {
|
private static boolean allParametersAreAssignable(List<Parameter> fromParams, List<Parameter> toParams) {
|
||||||
if ( fromParams.size() == toParams.size() ) {
|
if ( fromParams.size() == toParams.size() ) {
|
||||||
Set<Parameter> unaccountedToParams = new HashSet<Parameter>( toParams );
|
Set<Parameter> unaccountedToParams = new HashSet<Parameter>( toParams );
|
||||||
|
@ -424,10 +424,15 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
initializingMethods.add( method );
|
initializingMethods.add( method );
|
||||||
|
|
||||||
MappingOptions mappingOptions = method.getMappingOptions();
|
MappingOptions mappingOptions = method.getMappingOptions();
|
||||||
List<SourceMethod> applicablePrototypeMethods = method.getApplicablePrototypeMethods();
|
List<SourceMethod> applicableReversePrototypeMethods = method.getApplicableReversePrototypeMethods();
|
||||||
|
|
||||||
MappingOptions inverseMappingOptions =
|
MappingOptions inverseMappingOptions =
|
||||||
getInverseMappingOptions( availableMethods, method, initializingMethods, mapperConfig );
|
getInverseMappingOptions( join( availableMethods, applicableReversePrototypeMethods ),
|
||||||
|
method,
|
||||||
|
initializingMethods,
|
||||||
|
mapperConfig );
|
||||||
|
|
||||||
|
List<SourceMethod> applicablePrototypeMethods = method.getApplicablePrototypeMethods();
|
||||||
|
|
||||||
MappingOptions templateMappingOptions =
|
MappingOptions templateMappingOptions =
|
||||||
getTemplateMappingOptions(
|
getTemplateMappingOptions(
|
||||||
@ -457,6 +462,21 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
Message.INHERITCONFIGURATION_MULTIPLE_PROTOTYPE_METHODS_MATCH,
|
Message.INHERITCONFIGURATION_MULTIPLE_PROTOTYPE_METHODS_MATCH,
|
||||||
Strings.join( applicablePrototypeMethods, ", " ) );
|
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();
|
mappingOptions.markAsFullyInitialized();
|
||||||
@ -497,7 +517,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
// method is configured as being reverse method, collect candidates
|
// method is configured as being reverse method, collect candidates
|
||||||
List<SourceMethod> candidates = new ArrayList<SourceMethod>();
|
List<SourceMethod> candidates = new ArrayList<SourceMethod>();
|
||||||
for ( SourceMethod oneMethod : rawMethods ) {
|
for ( SourceMethod oneMethod : rawMethods ) {
|
||||||
if ( oneMethod.reverses( method ) ) {
|
if ( method.reverses( oneMethod ) ) {
|
||||||
candidates.add( 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
|
* 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
|
* {@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
|
* 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,
|
private MappingOptions getTemplateMappingOptions(List<SourceMethod> rawMethods, SourceMethod method,
|
||||||
List<SourceMethod> initializingMethods,
|
List<SourceMethod> initializingMethods,
|
||||||
|
@ -113,6 +113,7 @@ public enum Message {
|
|||||||
INHERITCONFIGURATION_DUPLICATE_MATCHES( "Given name \"%s\" matches several candidate methods: %s." ),
|
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_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." ),
|
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" ),
|
INHERITCONFIGURATION_CYCLE( "Cycle detected while evaluating inherited configurations. Inheritance path: %s" ),
|
||||||
|
|
||||||
VALUEMAPPING_DUPLICATE_SOURCE( "Source value mapping: \"%s\" cannot be mapped more than once." ),
|
VALUEMAPPING_DUPLICATE_SOURCE( "Source value mapping: \"%s\" cannot be mapped more than once." ),
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
}
|
@ -125,6 +125,21 @@ public class InheritFromConfigTest {
|
|||||||
assertThat( carDto.getId() ).isEqualTo( 42L );
|
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
|
@Test
|
||||||
public void explicitInheritedMappingWithTwoLevelsIsOverriddenAtMethodLevel() {
|
public void explicitInheritedMappingWithTwoLevelsIsOverriddenAtMethodLevel() {
|
||||||
CarDto carDto = newTestDto();
|
CarDto carDto = newTestDto();
|
||||||
|
@ -37,5 +37,5 @@ public interface ArtistToChartEntryConfig {
|
|||||||
@Mapping(target = "artistName", source = "artist.name"),
|
@Mapping(target = "artistName", source = "artist.name"),
|
||||||
@Mapping(target = "chartName", ignore = true )
|
@Mapping(target = "chartName", ignore = true )
|
||||||
})
|
})
|
||||||
BaseChartEntry mapForward( Song song );
|
BaseChartEntry mapForwardConfig( Song song );
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ public abstract class ArtistToChartEntryWithConfigReverse {
|
|||||||
})
|
})
|
||||||
abstract ChartEntryWithBase mapForward(Song song);
|
abstract ChartEntryWithBase mapForward(Song song);
|
||||||
|
|
||||||
@InheritInverseConfiguration
|
@InheritInverseConfiguration( name = "mapForward" )
|
||||||
@Mapping(target = "positions", ignore = true)
|
@Mapping(target = "positions", ignore = true)
|
||||||
abstract Song mapReverse(ChartEntryWithBase ce);
|
abstract Song mapReverse(ChartEntryWithBase ce);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user