mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#1011 extract the grouping of the nested target properties out of the MappingOptions into its own class
This commit is contained in:
parent
106214cb9f
commit
c751100272
@ -19,17 +19,21 @@
|
||||
package org.mapstruct.ap.internal.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mapstruct.ap.internal.model.common.Parameter;
|
||||
import org.mapstruct.ap.internal.model.source.Mapping;
|
||||
import org.mapstruct.ap.internal.model.source.MappingOptions;
|
||||
import org.mapstruct.ap.internal.model.source.Method;
|
||||
import org.mapstruct.ap.internal.model.source.PropertyEntry;
|
||||
import org.mapstruct.ap.internal.model.source.SourceReference;
|
||||
|
||||
import static org.mapstruct.ap.internal.util.Collections.first;
|
||||
|
||||
/**
|
||||
* This is a helper class that holds the generated {@link PropertyMapping}(s) and all the information associated with
|
||||
* it for nested target properties.
|
||||
@ -50,14 +54,25 @@ public class NestedTargetPropertyMappingHolder {
|
||||
this.propertyMappings = propertyMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The source parameters that were processed during the generation of the property mappings
|
||||
*/
|
||||
public List<Parameter> getProcessedSourceParameters() {
|
||||
return processedSourceParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return all the targets that were hanled
|
||||
*/
|
||||
public Set<String> getHandledTargets() {
|
||||
return handledTargets;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the generated property mappings
|
||||
*/
|
||||
public List<PropertyMapping> getPropertyMappings() {
|
||||
return propertyMappings;
|
||||
}
|
||||
@ -88,18 +103,20 @@ public class NestedTargetPropertyMappingHolder {
|
||||
Set<String> handledTargets = new HashSet<String>();
|
||||
List<PropertyMapping> propertyMappings = new ArrayList<PropertyMapping>();
|
||||
|
||||
Map<PropertyEntry, MappingOptions> optionsByNestedTarget =
|
||||
method.getMappingOptions().groupByPoppedTargetReferences();
|
||||
for ( Map.Entry<PropertyEntry, MappingOptions> entryByTP : optionsByNestedTarget.entrySet() ) {
|
||||
Map<PropertyEntry, List<Mapping>> groupedByTP = groupByPoppedTargetReferences( method.getMappingOptions() );
|
||||
|
||||
Map<Parameter, MappingOptions> optionsBySourceParam = entryByTP.getValue().groupBySourceParameter();
|
||||
boolean forceUpdateMethod = optionsBySourceParam.keySet().size() > 1;
|
||||
for ( Map.Entry<Parameter, MappingOptions> entryByParam : optionsBySourceParam.entrySet() ) {
|
||||
for ( Map.Entry<PropertyEntry, List<Mapping>> entryByTP : groupedByTP.entrySet() ) {
|
||||
Map<Parameter, List<Mapping>> groupedBySourceParam = groupBySourceParameter( entryByTP.getValue() );
|
||||
boolean forceUpdateMethod = groupedBySourceParam.keySet().size() > 1;
|
||||
for ( Map.Entry<Parameter, List<Mapping>> entryByParam : groupedBySourceParam.entrySet() ) {
|
||||
|
||||
SourceReference sourceRef = new SourceReference.BuilderFromProperty()
|
||||
.sourceParameter( entryByParam.getKey() )
|
||||
.name( entryByTP.getKey().getName() )
|
||||
.build();
|
||||
MappingOptions mappingOptions = MappingOptions.forMappingsOnly(
|
||||
groupByTargetName( entryByParam.getValue() )
|
||||
);
|
||||
|
||||
PropertyMapping propertyMapping = new PropertyMapping.PropertyMappingBuilder()
|
||||
.mappingContext( mappingContext )
|
||||
@ -108,8 +125,8 @@ public class NestedTargetPropertyMappingHolder {
|
||||
.targetPropertyName( entryByTP.getKey().getName() )
|
||||
.sourceReference( sourceRef )
|
||||
.existingVariableNames( existingVariableNames )
|
||||
.dependsOn( entryByParam.getValue().collectNestedDependsOn() )
|
||||
.forgeMethodWithMappingOptions( entryByParam.getValue() )
|
||||
.dependsOn( mappingOptions.collectNestedDependsOn() )
|
||||
.forgeMethodWithMappingOptions( mappingOptions )
|
||||
.forceUpdateMethod( forceUpdateMethod )
|
||||
.build();
|
||||
processedSourceParameters.add( sourceRef.getParameter() );
|
||||
@ -120,7 +137,86 @@ public class NestedTargetPropertyMappingHolder {
|
||||
}
|
||||
handledTargets.add( entryByTP.getKey().getName() );
|
||||
}
|
||||
|
||||
return new NestedTargetPropertyMappingHolder( processedSourceParameters, handledTargets, propertyMappings );
|
||||
}
|
||||
|
||||
/**
|
||||
* The target references are popped. The {@code List<}{@link Mapping}{@code >} are keyed on the unique first
|
||||
* entries of the target references.
|
||||
*
|
||||
* So, take
|
||||
*
|
||||
* targetReference 1: propertyEntryX.propertyEntryX1.propertyEntryX1a
|
||||
* targetReference 2: propertyEntryX.propertyEntryX2
|
||||
* targetReference 3: propertyEntryY.propertyY1
|
||||
* targetReference 4: propertyEntryZ
|
||||
*
|
||||
* will be popped and grouped into entries:
|
||||
*
|
||||
* propertyEntryX - List ( targetReference1: propertyEntryX1.propertyEntryX1a,
|
||||
* targetReference2: propertyEntryX2 )
|
||||
* propertyEntryY - List ( targetReference1: propertyEntryY1 )
|
||||
*
|
||||
* The key will be the former top level property, the MappingOptions will contain the remainders.
|
||||
*
|
||||
* So, 2 cloned new MappingOptions with popped targetReferences. Also Note that the not nested targetReference4
|
||||
* disappeared.
|
||||
*
|
||||
* @return See above
|
||||
*/
|
||||
public Map<PropertyEntry, List<Mapping>> groupByPoppedTargetReferences(MappingOptions mappingOptions) {
|
||||
Map<String, List<Mapping>> mappings = mappingOptions.getMappings();
|
||||
// group all mappings based on the top level name before popping
|
||||
Map<PropertyEntry, List<Mapping>> mappingsKeyedByProperty = new HashMap<PropertyEntry, List<Mapping>>();
|
||||
for ( List<Mapping> mapping : mappings.values() ) {
|
||||
Mapping newMapping = first( mapping ).popTargetReference();
|
||||
if ( newMapping != null ) {
|
||||
// group properties on current name.
|
||||
PropertyEntry property = first( first( mapping ).getTargetReference().getPropertyEntries() );
|
||||
if ( !mappingsKeyedByProperty.containsKey( property ) ) {
|
||||
mappingsKeyedByProperty.put( property, new ArrayList<Mapping>() );
|
||||
}
|
||||
mappingsKeyedByProperty.get( property ).add( newMapping );
|
||||
}
|
||||
}
|
||||
|
||||
return mappingsKeyedByProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the List of Mappings into possibly more Mappings based on each source method parameter type.
|
||||
*
|
||||
* Note: this method is used for forging nested update methods. For that purpose, the same method with all
|
||||
* joined mappings should be generated. See also: NestedTargetPropertiesTest#shouldMapNestedComposedTarget
|
||||
*
|
||||
* @return the split mapping options.
|
||||
*/
|
||||
public Map<Parameter, List<Mapping>> groupBySourceParameter(List<Mapping> mappings) {
|
||||
|
||||
Map<Parameter, List<Mapping>> mappingsKeyedByParameter = new HashMap<Parameter, List<Mapping>>();
|
||||
for ( Mapping mapping : mappings ) {
|
||||
if ( mapping.getSourceReference() != null && mapping.getSourceReference().isValid() ) {
|
||||
Parameter parameter = mapping.getSourceReference().getParameter();
|
||||
if ( !mappingsKeyedByParameter.containsKey( parameter ) ) {
|
||||
mappingsKeyedByParameter.put( parameter, new ArrayList<Mapping>() );
|
||||
}
|
||||
mappingsKeyedByParameter.get( parameter ).add( mapping );
|
||||
}
|
||||
}
|
||||
|
||||
return mappingsKeyedByParameter;
|
||||
}
|
||||
|
||||
private Map<String, List<Mapping>> groupByTargetName(List<Mapping> mappingList) {
|
||||
Map<String, List<Mapping>> result = new HashMap<String, List<Mapping>>();
|
||||
for ( Mapping mapping : mappingList ) {
|
||||
if ( !result.containsKey( mapping.getTargetName() ) ) {
|
||||
result.put( mapping.getTargetName(), new ArrayList<Mapping>() );
|
||||
}
|
||||
result.get( mapping.getTargetName() ).add( mapping );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ package org.mapstruct.ap.internal.model.source;
|
||||
import static org.mapstruct.ap.internal.util.Collections.first;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@ -86,58 +85,6 @@ public class MappingOptions {
|
||||
return mappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* The target references are popped. The MappingOptions are keyed on the unique first entries of the
|
||||
* target references.
|
||||
*
|
||||
* So, take
|
||||
*
|
||||
* targetReference 1: propertyEntryX.propertyEntryX1.propertyEntryX1a
|
||||
* targetReference 2: propertyEntryX.propertyEntryX2
|
||||
* targetReference 3: propertyEntryY.propertyY1
|
||||
* targetReference 4: propertyEntryZ
|
||||
*
|
||||
* will be popped and grouped into entries:
|
||||
*
|
||||
* propertyEntryX - MappingOptions ( targetReference1: propertyEntryX1.propertyEntryX1a,
|
||||
* targetReference2: propertyEntryX2 )
|
||||
* propertyEntryY - MappingOptions ( targetReference1: propertyEntryY1 )
|
||||
*
|
||||
* The key will be the former top level property, the MappingOptions will contain the remainders.
|
||||
*
|
||||
* So, 2 cloned new MappingOptions with popped targetReferences. Also Note that the not nested targetReference4
|
||||
* disappeared.
|
||||
*
|
||||
* @return See above
|
||||
*/
|
||||
public Map<PropertyEntry, MappingOptions> groupByPoppedTargetReferences() {
|
||||
|
||||
// group all mappings based on the top level name before popping
|
||||
Map<PropertyEntry, List<Mapping>> mappingsKeyedByProperty = new HashMap<PropertyEntry, List<Mapping>>();
|
||||
for ( List<Mapping> mapping : mappings.values() ) {
|
||||
Mapping newMapping = first( mapping ).popTargetReference();
|
||||
if ( newMapping != null ) {
|
||||
// group properties on current name.
|
||||
PropertyEntry property = first( first( mapping ).getTargetReference().getPropertyEntries() );
|
||||
if ( !mappingsKeyedByProperty.containsKey( property ) ) {
|
||||
mappingsKeyedByProperty.put( property, new ArrayList<Mapping>() );
|
||||
}
|
||||
mappingsKeyedByProperty.get( property ).add( newMapping );
|
||||
}
|
||||
}
|
||||
|
||||
// now group them into mapping options
|
||||
Map<PropertyEntry, MappingOptions> result = new HashMap<PropertyEntry, MappingOptions>();
|
||||
for ( Map.Entry<PropertyEntry, List<Mapping>> mappingKeyedByProperty : mappingsKeyedByProperty.entrySet() ) {
|
||||
Map<String, List<Mapping>> newEntries = new HashMap<String, List<Mapping>>();
|
||||
for ( Mapping newEntry : mappingKeyedByProperty.getValue() ) {
|
||||
newEntries.put( newEntry.getTargetName(), Arrays.asList( newEntry ) );
|
||||
}
|
||||
result.put( mappingKeyedByProperty.getKey(), forMappingsOnly( newEntries ) );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check there are nested target references for this mapping options.
|
||||
*
|
||||
@ -170,48 +117,6 @@ public class MappingOptions {
|
||||
return nestedDependsOn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the MappingOptions into possibly more MappingOptions based on each source method parameter type.
|
||||
*
|
||||
* Note: this method is used for forging nested update methods. For that purpose, the same method with all
|
||||
* joined mappings should be generated. See also: NestedTargetPropertiesTest#shouldMapNestedComposedTarget
|
||||
*
|
||||
* @return the split mapping options.
|
||||
*
|
||||
*/
|
||||
public Map<Parameter, MappingOptions> groupBySourceParameter() {
|
||||
|
||||
Map<Parameter, List<Mapping>> mappingsKeyedByParameterType = new HashMap<Parameter, List<Mapping>>();
|
||||
for ( List<Mapping> mappingList : mappings.values() ) {
|
||||
for ( Mapping mapping : mappingList ) {
|
||||
if ( mapping.getSourceReference() != null && mapping.getSourceReference().isValid() ) {
|
||||
Parameter parameter = mapping.getSourceReference().getParameter();
|
||||
if ( !mappingsKeyedByParameterType.containsKey( parameter ) ) {
|
||||
mappingsKeyedByParameterType.put( parameter, new ArrayList<Mapping>() );
|
||||
}
|
||||
mappingsKeyedByParameterType.get( parameter ).add( mapping );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<Parameter, MappingOptions> result = new HashMap<Parameter, MappingOptions>();
|
||||
for ( Map.Entry<Parameter, List<Mapping>> entry : mappingsKeyedByParameterType.entrySet() ) {
|
||||
result.put( entry.getKey(), MappingOptions.forMappingsOnly( groupByTargetName( entry.getValue() ) ) );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, List<Mapping>> groupByTargetName( List<Mapping> mappingList ) {
|
||||
Map<String, List<Mapping>> result = new HashMap<String, List<Mapping>>();
|
||||
for ( Mapping mapping : mappingList ) {
|
||||
if ( !result.containsKey( mapping.getTargetName() ) ) {
|
||||
result.put( mapping.getTargetName(), new ArrayList<Mapping>() );
|
||||
}
|
||||
result.get( mapping.getTargetName() ).add( mapping );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the underlying mappings with a new property. Specifically used in in combination with forged methods
|
||||
* where the new parameter name needs to be established at a later moment.
|
||||
|
Loading…
x
Reference in New Issue
Block a user