6666import org .springframework .data .neo4j .core .schema .IdGenerator ;
6767import org .springframework .data .neo4j .core .schema .Node ;
6868import org .springframework .data .neo4j .core .schema .PostLoad ;
69+ import org .springframework .data .util .Lazy ;
6970import org .springframework .data .util .TypeInformation ;
7071import org .springframework .lang .Nullable ;
7172import org .springframework .util .ReflectionUtils ;
@@ -117,26 +118,67 @@ public final class Neo4jMappingContext extends AbstractMappingContext<Neo4jPersi
117118
118119 private boolean strict = false ;
119120
120- public Neo4jMappingContext () {
121+ private final Lazy <PersistentPropertyCharacteristicsProvider > propertyCharacteristicsProvider ;
122+
123+ /**
124+ * A builder for creating custom instances of a {@link Neo4jMappingContext}.
125+ * @since 6.3.7
126+ */
127+ public static class Builder {
128+
129+ private Neo4jConversions neo4jConversions ;
130+
131+ @ Nullable
132+ private TypeSystem typeSystem ;
121133
122- this (new Neo4jConversions ());
134+ @ Nullable
135+ private PersistentPropertyCharacteristicsProvider persistentPropertyCharacteristicsProvider ;
136+
137+ private Builder () {
138+ this (new Neo4jConversions (), null , null );
139+ }
140+
141+ private Builder (Neo4jConversions neo4jConversions , @ Nullable TypeSystem typeSystem , @ Nullable PersistentPropertyCharacteristicsProvider persistentPropertyCharacteristicsProvider ) {
142+ this .neo4jConversions = neo4jConversions ;
143+ this .typeSystem = typeSystem ;
144+ this .persistentPropertyCharacteristicsProvider = persistentPropertyCharacteristicsProvider ;
145+ }
146+
147+ @ SuppressWarnings ("HiddenField" )
148+ public Builder withNeo4jConversions (@ Nullable Neo4jConversions neo4jConversions ) {
149+ this .neo4jConversions = neo4jConversions ;
150+ return this ;
151+ }
152+
153+ @ SuppressWarnings ("HiddenField" )
154+ public Builder withPersistentPropertyCharacteristicsProvider (@ Nullable PersistentPropertyCharacteristicsProvider persistentPropertyCharacteristicsProvider ) {
155+ this .persistentPropertyCharacteristicsProvider = persistentPropertyCharacteristicsProvider ;
156+ return this ;
157+ }
158+
159+ @ SuppressWarnings ("HiddenField" )
160+ public Builder withTypeSystem (@ Nullable TypeSystem typeSystem ) {
161+ this .typeSystem = typeSystem ;
162+ return this ;
163+ }
164+
165+ public Neo4jMappingContext build () {
166+ return new Neo4jMappingContext (this );
167+ }
123168 }
124169
125- public Neo4jMappingContext (Neo4jConversions neo4jConversions ) {
170+ public static Builder builder () {
171+ return new Builder ();
172+ }
173+
174+ public Neo4jMappingContext () {
126175
127- this (neo4jConversions , null );
176+ this (new Builder () );
128177 }
129178
130- /**
131- * We need to set the context to non-strict in case we must dynamically add parent classes. As there is no
132- * way to access the original value without reflection, we track its change.
133- *
134- * @param strict The new value for the strict setting.
135- */
136- @ Override
137- public void setStrict (boolean strict ) {
138- super .setStrict (strict );
139- this .strict = strict ;
179+ public Neo4jMappingContext (Neo4jConversions neo4jConversions ) {
180+
181+ this (new Builder (neo4jConversions , null , null ));
140182 }
141183
142184 /**
@@ -145,17 +187,40 @@ public void setStrict(boolean strict) {
145187 *
146188 * @param neo4jConversions The conversions to be used
147189 * @param typeSystem The current drivers type system. If this is null, we use the default one without accessing the driver.
190+ * @deprecated Use {@link Neo4jMappingContext#builder()}
148191 */
149192 @ API (status = API .Status .INTERNAL , since = "6.0" )
193+ @ Deprecated
150194 public Neo4jMappingContext (Neo4jConversions neo4jConversions , @ Nullable TypeSystem typeSystem ) {
195+ this (new Builder (neo4jConversions , typeSystem , null ));
196+ }
197+
198+ private Neo4jMappingContext (Builder builder ) {
151199
152- this .conversionService = new DefaultNeo4jConversionService (neo4jConversions );
153- this .typeSystem = typeSystem == null ? InternalTypeSystem .TYPE_SYSTEM : typeSystem ;
200+ this .conversionService = new DefaultNeo4jConversionService (builder . neo4jConversions );
201+ this .typeSystem = builder . typeSystem == null ? InternalTypeSystem .TYPE_SYSTEM : builder . typeSystem ;
154202 this .eventSupport = EventSupport .useExistingCallbacks (this , EntityCallbacks .create ());
155203
156- super .setSimpleTypeHolder (neo4jConversions .getSimpleTypeHolder ());
204+ super .setSimpleTypeHolder (builder .neo4jConversions .getSimpleTypeHolder ());
205+
206+ PersistentPropertyCharacteristicsProvider characteristicsProvider = builder .persistentPropertyCharacteristicsProvider ;
207+ this .propertyCharacteristicsProvider = Lazy .of (() -> characteristicsProvider != null || this .beanFactory == null ?
208+ characteristicsProvider : this .beanFactory .getBeanProvider (PersistentPropertyCharacteristicsProvider .class ).getIfUnique ());
157209 }
158210
211+ /**
212+ * We need to set the context to non-strict in case we must dynamically add parent classes. As there is no
213+ * way to access the original value without reflection, we track its change.
214+ *
215+ * @param strict The new value for the strict setting.
216+ */
217+ @ Override
218+ public void setStrict (boolean strict ) {
219+ super .setStrict (strict );
220+ this .strict = strict ;
221+ }
222+
223+
159224 public Neo4jEntityConverter getEntityConverter () {
160225 return new DefaultNeo4jEntityConverter (INSTANTIATORS , nodeDescriptionStore , conversionService , eventSupport ,
161226 typeSystem );
@@ -260,7 +325,12 @@ private static boolean isValidParentNode(@Nullable Class<?> parentClass) {
260325 protected Neo4jPersistentProperty createPersistentProperty (Property property , Neo4jPersistentEntity <?> owner ,
261326 SimpleTypeHolder simpleTypeHolder ) {
262327
263- return new DefaultNeo4jPersistentProperty (property , owner , this , simpleTypeHolder );
328+ PersistentPropertyCharacteristics optionalCharacteristics = this .propertyCharacteristicsProvider
329+ .getOptional ()
330+ .flatMap (provider -> Optional .ofNullable (provider .apply (property , owner )))
331+ .orElse (null );
332+
333+ return new DefaultNeo4jPersistentProperty (property , owner , this , simpleTypeHolder , optionalCharacteristics );
264334 }
265335
266336 @ Override
@@ -278,9 +348,9 @@ public NodeDescription<?> getNodeDescription(Class<?> underlyingClass) {
278348 @ Nullable
279349 public Neo4jPersistentEntity <?> getPersistentEntity (TypeInformation <?> typeInformation ) {
280350
281- NodeDescription <?> existingDescription = this .doGetPersistentEntity (typeInformation );
351+ Neo4jPersistentEntity <?> existingDescription = this .doGetPersistentEntity (typeInformation );
282352 if (existingDescription != null ) {
283- return ( Neo4jPersistentEntity <?>) existingDescription ;
353+ return existingDescription ;
284354 }
285355 return super .getPersistentEntity (typeInformation );
286356 }
0 commit comments