Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public Builder userDefinedReturnType(Type userDefinedReturnType) {
return this;
}

public Builder returnTypeBuilder( BuilderType returnTypeBuilder ) {
public Builder returnTypeBuilder(BuilderType returnTypeBuilder) {
this.returnTypeBuilder = returnTypeBuilder;
return this;
}
Expand All @@ -132,7 +132,7 @@ public Builder forgedMethod(ForgedMethod forgedMethod) {
this.method = forgedMethod;
mappingReferences = forgedMethod.getMappingReferences();
Parameter sourceParameter = first( Parameter.getSourceParameters( forgedMethod.getParameters() ) );
for ( MappingReference mappingReference: mappingReferences.getMappingReferences() ) {
for ( MappingReference mappingReference : mappingReferences.getMappingReferences() ) {
SourceReference sourceReference = mappingReference.getSourceReference();
if ( sourceReference != null ) {
mappingReference.setSourceReference( new SourceReference.BuilderFromSourceReference()
Expand Down Expand Up @@ -237,7 +237,8 @@ else if ( !method.isUpdateMethod() ) {
for ( Parameter sourceParameter : method.getSourceParameters() ) {
unprocessedSourceParameters.add( sourceParameter );

if ( sourceParameter.getType().isPrimitive() || sourceParameter.getType().isArrayType() ) {
if ( sourceParameter.getType().isPrimitive() || sourceParameter.getType().isArrayType() ||
sourceParameter.getType().isMapType() ) {
continue;
}
Map<String, Accessor> readAccessors = sourceParameter.getType().getPropertyReadAccessors();
Expand Down Expand Up @@ -272,6 +273,9 @@ else if ( !method.isUpdateMethod() ) {

// map parameters without a mapping
applyParameterNameBasedMapping();

// map properties without a mapping from map parameters
applyPropertyNameBasedMappingForMapSources();
}

// Process the unprocessed defined targets
Expand All @@ -295,18 +299,18 @@ else if ( !method.isUpdateMethod() ) {

// before / after mappings
List<LifecycleCallbackMethodReference> beforeMappingMethods = LifecycleMethodResolver.beforeMappingMethods(
method,
resultTypeToMap,
selectionParameters,
ctx,
existingVariableNames
method,
resultTypeToMap,
selectionParameters,
ctx,
existingVariableNames
);
List<LifecycleCallbackMethodReference> afterMappingMethods = LifecycleMethodResolver.afterMappingMethods(
method,
resultTypeToMap,
selectionParameters,
ctx,
existingVariableNames
method,
resultTypeToMap,
selectionParameters,
ctx,
existingVariableNames
);

if ( method instanceof ForgedMethod ) {
Expand Down Expand Up @@ -365,10 +369,10 @@ private void initializeMappingReferencesIfNeeded(Type resultTypeToMap) {
*/
private boolean isBuilderRequired() {
return returnTypeBuilder != null
&& ( !method.isUpdateMethod() || !method.isMappingTargetAssignableToReturnType() );
&& ( !method.isUpdateMethod() || !method.isMappingTargetAssignableToReturnType() );
}

private boolean shouldCallFinalizerMethod(Type returnTypeToConstruct ) {
private boolean shouldCallFinalizerMethod(Type returnTypeToConstruct) {
if ( returnTypeToConstruct == null ) {
return false;
}
Expand Down Expand Up @@ -553,7 +557,8 @@ else if ( !returnType.hasAccessibleConstructor() ) {

/**
* Find a factory method for a return type or for a builder.
* @param returnTypeImpl the return type implementation to construct
*
* @param returnTypeImpl the return type implementation to construct
* @param @selectionParameters
* @return
*/
Expand Down Expand Up @@ -634,7 +639,7 @@ private ConstructorAccessor getConstructorAccessor(Type type) {
ExecutableElement defaultAnnotatedConstructor = null;
ExecutableElement parameterLessConstructor = null;
List<ExecutableElement> accessibleConstructors = new ArrayList<>( constructors.size() );
List<ExecutableElement> publicConstructors = new ArrayList<>( );
List<ExecutableElement> publicConstructors = new ArrayList<>();

for ( ExecutableElement constructor : constructors ) {
if ( constructor.getModifiers().contains( Modifier.PRIVATE ) ) {
Expand Down Expand Up @@ -894,7 +899,7 @@ private boolean handleDefinedNestedTargetMapping(Set<String> handledTargets, Typ
handledTargets.addAll( holder.getHandledTargets() );
// Store all the unprocessed defined targets.
for ( Entry<String, Set<MappingReference>> entry : holder.getUnprocessedDefinedTarget()
.entrySet() ) {
.entrySet() ) {
if ( entry.getValue().isEmpty() ) {
continue;
}
Expand All @@ -904,7 +909,7 @@ private boolean handleDefinedNestedTargetMapping(Set<String> handledTargets, Typ
}

private boolean handleDefinedMapping(MappingReference mappingRef, Type resultTypeToMap,
Set<String> handledTargets) {
Set<String> handledTargets) {
boolean errorOccured = false;

PropertyMapping propertyMapping = null;
Expand Down Expand Up @@ -1069,7 +1074,7 @@ else if ( mapping.getJavaExpression() != null ) {
handledTargets.add( targetPropertyName );
}
// its a plain-old property mapping
else {
else {

SourceReference sourceRef = mappingRef.getSourceReference();
// sourceRef is not defined, check if a source property has the same name
Expand Down Expand Up @@ -1185,7 +1190,7 @@ else if ( mapping.getJavaExpression() != null ) {
* <p>
* When a target property matches its name with the (nested) source property, it is added to the list if and
* only if it is an unprocessed target property.
*
* <p>
* duplicates will be handled by {@link #applyPropertyNameBasedMapping(List)}
*/
private void applyTargetThisMapping() {
Expand Down Expand Up @@ -1231,6 +1236,54 @@ private void applyPropertyNameBasedMapping() {
applyPropertyNameBasedMapping( sourceReferences );
}

/**
* Iterates over all target properties and all source parameters.
* <p>
* When a property name match occurs, the remainder will be checked for duplicates. Matches will be removed from
* the set of remaining target properties.
*/
private void applyPropertyNameBasedMappingForMapSources() {
final Type stringType = ctx.getTypeFactory().getType( String.class );
for ( Parameter sourceParameter : method.getSourceParameters() ) {
if ( !sourceParameter.getType().isMapType() ) {
continue;
}
final List<Type> typeParameters = sourceParameter.getType().getTypeParameters();
if (!(typeParameters.size() == 2 && typeParameters.get( 0 ).equals( stringType ))) {
Message message = typeParameters.isEmpty() ? Message.MAPTOBEANMAPPING_UNTYPED
: Message.MAPTOBEANMAPPING_WRONG_GENERIC_TYPES;
ctx.getMessager()
.printMessage(
method.getExecutable(),
message,
sourceParameter.getName(),
String.format(
"Map<%s,%s>",
!typeParameters.isEmpty() ? typeParameters.get( 0 ).getName() : "",
typeParameters.size() > 1 ? typeParameters.get( 1 ).getName() : ""
)
);
}
}
List<SourceReference> sourceReferences = new ArrayList<>();
for ( String targetPropertyName : unprocessedTargetProperties.keySet() ) {
for ( Parameter sourceParameter : method.getSourceParameters() ) {
if ( !sourceParameter.getType().isMapType() ) {
continue;
}
final List<Type> typeParameters = sourceParameter.getType().getTypeParameters();
if (!(typeParameters.size() == 2 && typeParameters.get( 0 ).equals( stringType ))) {
continue;
}
SourceReference sourceRef = getMapSourceRefByTargetName( sourceParameter, targetPropertyName );
if ( sourceRef != null ) {
sourceReferences.add( sourceRef );
}
}
}
applyPropertyNameBasedMapping( sourceReferences );
}

/**
* Iterates over all target properties and all source parameters.
* <p>
Expand All @@ -1247,10 +1300,11 @@ private void applyPropertyNameBasedMapping(List<SourceReference> sourceReference
if ( targetPropertyWriteAccessor == null ) {
// TODO improve error message
ctx.getMessager()
.printMessage( method.getExecutable(),
Message.BEANMAPPING_SEVERAL_POSSIBLE_SOURCES,
targetPropertyName
);
.printMessage(
method.getExecutable(),
Message.BEANMAPPING_SEVERAL_POSSIBLE_SOURCES,
targetPropertyName
);
continue;
}

Expand Down Expand Up @@ -1349,15 +1403,27 @@ private SourceReference getSourceRefByTargetName(Parameter sourceParameter, Stri
DeclaredType declaredSourceType = (DeclaredType) sourceParameter.getType().getTypeMirror();
Type returnType = ctx.getTypeFactory().getReturnType( declaredSourceType, sourceReadAccessor );
sourceRef = new SourceReference.BuilderFromProperty().sourceParameter( sourceParameter )
.type( returnType )
.readAccessor( sourceReadAccessor )
.presenceChecker( sourcePresenceChecker )
.name( targetPropertyName )
.build();
.type( returnType )
.readAccessor( sourceReadAccessor )
.presenceChecker( sourcePresenceChecker )
.name( targetPropertyName )
.build();
}
return sourceRef;
}

private SourceReference getMapSourceRefByTargetName(Parameter sourceParameter, String targetPropertyName) {

SourceReference sourceRef = null;

if ( !sourceParameter.getType().isMapType() ) {
return sourceRef;
}

Type defaultType = ctx.getTypeFactory().getType( Object.class );
return SourceReference.fromMapSource( new String[] { targetPropertyName }, sourceParameter, defaultType );
}

private MappingReferences extractMappingReferences(String targetProperty, boolean restrictToDefinedMappings) {
if ( unprocessedDefinedTargets.containsKey( targetProperty ) ) {
Set<MappingReference> mappings = unprocessedDefinedTargets.get( targetProperty );
Expand Down Expand Up @@ -1603,7 +1669,7 @@ public Set<Type> getImportTypes() {
}
}

if ( returnTypeToConstruct != null ) {
if ( returnTypeToConstruct != null ) {
types.addAll( returnTypeToConstruct.getImportTypes() );
}
if ( returnTypeBuilder != null ) {
Expand All @@ -1615,20 +1681,20 @@ public Set<Type> getImportTypes() {

public List<Parameter> getSourceParametersExcludingPrimitives() {
return getSourceParameters().stream()
.filter( parameter -> !parameter.getType().isPrimitive() )
.collect( Collectors.toList() );
.filter( parameter -> !parameter.getType().isPrimitive() )
.collect( Collectors.toList() );
}

public List<Parameter> getSourceParametersNeedingNullCheck() {
return getSourceParameters().stream()
.filter( this::needsNullCheck )
.collect( Collectors.toList() );
.filter( this::needsNullCheck )
.collect( Collectors.toList() );
}

public List<Parameter> getSourceParametersNotNeedingNullCheck() {
return getSourceParameters().stream()
.filter( parameter -> !needsNullCheck( parameter ) )
.collect( Collectors.toList() );
.filter( parameter -> !needsNullCheck( parameter ) )
.collect( Collectors.toList() );
}

private boolean needsNullCheck(Parameter parameter) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,9 @@ private Assignment forge( ) {
else if ( sourceType.isMapType() && targetType.isMapType() ) {
assignment = forgeMapMapping( sourceType, targetType, rightHandSide );
}
else if ( sourceType.isMapType() && !targetType.isMapType()) {
assignment = forgeMapToBeanMapping( sourceType, targetType, rightHandSide );
}
else if ( ( sourceType.isIterableType() && targetType.isStreamType() )
|| ( sourceType.isStreamType() && targetType.isStreamType() )
|| ( sourceType.isStreamType() && targetType.isIterableType() ) ) {
Expand Down Expand Up @@ -612,6 +615,12 @@ private String getSourcePresenceCheckerRef( SourceReference sourceReference ) {
// in the forged method?
PropertyEntry propertyEntry = sourceReference.getShallowestProperty();
if ( propertyEntry.getPresenceChecker() != null ) {

if (propertyEntry.getPresenceChecker().getAccessorType() == AccessorType.MAP_CONTAINS ) {
return sourceParam.getName()
+ "." + "containsKey( \"" + propertyEntry.getPresenceChecker().getSimpleName() + "\" )";
}

sourcePresenceChecker = sourceParam.getName()
+ "." + propertyEntry.getPresenceChecker().getSimpleName() + "()";

Expand Down Expand Up @@ -684,6 +693,19 @@ private Assignment forgeMapMapping(Type sourceType, Type targetType, SourceRHS s
return createForgedAssignment( source, methodRef, mapMappingMethod );
}

private Assignment forgeMapToBeanMapping(Type sourceType, Type targetType, SourceRHS source) {

targetType = targetType.withoutBounds();
ForgedMethod methodRef = prepareForgedMethod( sourceType, targetType, source, "{}" );

BeanMappingMethod.Builder builder = new BeanMappingMethod.Builder();
final BeanMappingMethod mapToBeanMappingMethod = builder.mappingContext( ctx )
.forgedMethod( methodRef )
.build();

return createForgedAssignment( source, methodRef, mapToBeanMappingMethod );
}

private Assignment forgeMapping(SourceRHS sourceRHS) {
Type sourceType;
if ( targetWriteAccessorType == AccessorType.ADDER ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ private PropertyEntry(String[] fullName, Accessor readAccessor, Accessor presenc
/**
* Constructor used to create {@link SourceReference} property entries from a mapping
*
* @param name name of the property (dot separated)
* @param readAccessor its read accessor
* @param name name of the property (dot separated)
* @param readAccessor its read accessor
* @param presenceChecker its presence Checker
* @param type type of the property
* @param type type of the property
* @return the property entry for given parameters.
*/
public static PropertyEntry forSourceReference(String[] name, Accessor readAccessor,
Expand All @@ -67,7 +67,7 @@ public Type getType() {
}

public String getFullName() {
return Strings.join( Arrays.asList( fullName ), "." );
return Strings.join( Arrays.asList( fullName ), "." );
}

@Override
Expand Down
Loading