15
15
*/
16
16
package org .springframework .data .neo4j .core .mapping ;
17
17
18
+ import java .util .Collection ;
19
+ import java .util .Map ;
20
+ import java .util .concurrent .ConcurrentHashMap ;
21
+
18
22
import org .apiguardian .api .API ;
23
+ import org .springframework .core .CollectionFactory ;
19
24
import org .springframework .core .convert .converter .Converter ;
20
25
import org .springframework .data .mapping .MappingException ;
21
26
import org .springframework .data .mapping .PersistentEntity ;
22
27
import org .springframework .data .mapping .PersistentProperty ;
23
28
import org .springframework .data .mapping .PersistentPropertyAccessor ;
24
29
import org .springframework .data .mapping .PreferredConstructor ;
25
30
import org .springframework .data .mapping .PreferredConstructor .Parameter ;
26
- import org .springframework .data .mapping .SimplePropertyHandler ;
27
31
import org .springframework .data .mapping .model .ParameterValueProvider ;
28
32
import org .springframework .data .util .ClassTypeInformation ;
29
33
import org .springframework .data .util .ReflectionUtils ;
@@ -41,11 +45,13 @@ public final class EntityFromDtoInstantiatingConverter<T> implements Converter<O
41
45
private final Class <?> targetEntityType ;
42
46
private final Neo4jMappingContext context ;
43
47
48
+ private final Map <Class <?>, EntityFromDtoInstantiatingConverter <?>> converterCache = new ConcurrentHashMap <>();
49
+
44
50
/**
45
51
* Creates a new {@link Converter} to instantiate Entities from DTOs.
46
52
*
47
53
* @param entityType must not be {@literal null}.
48
- * @param context must not be {@literal null}.
54
+ * @param context must not be {@literal null}.
49
55
*/
50
56
public EntityFromDtoInstantiatingConverter (Class <T > entityType , Neo4jMappingContext context ) {
51
57
@@ -63,7 +69,8 @@ public T convert(Object dtoInstance) {
63
69
return null ;
64
70
}
65
71
66
- PersistentEntity <?, ?> sourceEntity = context .addPersistentEntity (ClassTypeInformation .from (dtoInstance .getClass ())).get ();
72
+ PersistentEntity <?, ?> sourceEntity = context .addPersistentEntity (
73
+ ClassTypeInformation .from (dtoInstance .getClass ())).get ();
67
74
PersistentPropertyAccessor <Object > sourceAccessor = sourceEntity .getPropertyAccessor (dtoInstance );
68
75
69
76
PersistentEntity <?, ?> targetEntity = context .getPersistentEntity (targetEntityType );
@@ -78,23 +85,21 @@ public Object getParameterValue(Parameter parameter) {
78
85
PersistentProperty <?> targetProperty = targetEntity .getPersistentProperty (parameter .getName ());
79
86
if (targetProperty == null ) {
80
87
throw new MappingException ("Cannot map constructor parameter " + parameter .getName ()
81
- + " to a property of class " + targetEntityType );
88
+ + " to a property of class " + targetEntityType );
82
89
}
83
90
return getPropertyValueFor (targetProperty , sourceEntity , sourceAccessor );
84
91
}
85
92
});
86
93
87
94
PersistentPropertyAccessor <Object > dtoAccessor = targetEntity .getPropertyAccessor (entity );
88
- targetEntity .doWithProperties ((SimplePropertyHandler ) property -> {
89
-
95
+ targetEntity .doWithAll (property -> {
90
96
if (constructor .isConstructorParameter (property )) {
91
97
return ;
92
98
}
93
99
94
100
Object propertyValue = getPropertyValueFor (property , sourceEntity , sourceAccessor );
95
101
dtoAccessor .setProperty (property , propertyValue );
96
102
});
97
-
98
103
return entity ;
99
104
}
100
105
@@ -114,6 +119,23 @@ Object getPropertyValueFor(PersistentProperty<?> targetProperty, PersistentEntit
114
119
return ReflectionUtils .getPrimitiveDefault (targetPropertyType );
115
120
}
116
121
122
+ if (targetProperty .isAssociation () && targetProperty .isCollectionLike ()) {
123
+ EntityFromDtoInstantiatingConverter <?> nestedConverter = converterCache .computeIfAbsent (targetProperty .getComponentType (), t -> new EntityFromDtoInstantiatingConverter <>(t , context ));
124
+ Collection <?> source = (Collection <?>) propertyValue ;
125
+ if (source == null ) {
126
+ return CollectionFactory .createCollection (targetPropertyType , 0 );
127
+ }
128
+ Collection <Object > target = CollectionFactory .createApproximateCollection (source , source .size ());
129
+ source .stream ().map (nestedConverter ::convert ).forEach (target ::add );
130
+ return target ;
131
+ }
132
+
133
+ if (propertyValue != null && !targetPropertyType .isInstance (propertyValue )) {
134
+ EntityFromDtoInstantiatingConverter <?> nestedConverter = converterCache .computeIfAbsent (targetProperty .getType (),
135
+ t -> new EntityFromDtoInstantiatingConverter <>(t , context ));
136
+ return nestedConverter .convert (propertyValue );
137
+ }
138
+
117
139
return propertyValue ;
118
140
}
119
141
}
0 commit comments