1818import static org .assertj .core .api .Assertions .assertThat ;
1919import static org .assertj .core .api .Assertions .assertThatExceptionOfType ;
2020
21- import java .lang .reflect .Field ;
2221import java .text .SimpleDateFormat ;
2322import java .time .ZoneId ;
2423import java .time .ZonedDateTime ;
4140import org .junit .jupiter .api .DynamicTest ;
4241import org .junit .jupiter .api .Test ;
4342import org .junit .jupiter .api .TestFactory ;
44- import org .junit .platform .commons .util .AnnotationUtils ;
4543import org .neo4j .driver .Driver ;
4644import org .neo4j .driver .Session ;
4745import org .neo4j .driver .Value ;
5452import org .springframework .data .mapping .MappingException ;
5553import org .springframework .data .neo4j .config .AbstractNeo4jConfig ;
5654import org .springframework .data .neo4j .core .DatabaseSelectionProvider ;
57- import org .springframework .data .neo4j .core .convert . ConvertWith ;
55+ import org .springframework .data .neo4j .core .Neo4jTemplate ;
5856import org .springframework .data .neo4j .core .convert .Neo4jConversions ;
5957import org .springframework .data .neo4j .core .transaction .Neo4jBookmarkManager ;
6058import org .springframework .data .neo4j .core .transaction .Neo4jTransactionManager ;
59+ import org .springframework .data .neo4j .integration .shared .common .ThingWithAllCypherTypes2 ;
6160import org .springframework .data .neo4j .integration .shared .conversion .Neo4jConversionsITBase ;
6261import org .springframework .data .neo4j .integration .shared .conversion .ThingWithAllAdditionalTypes ;
6362import org .springframework .data .neo4j .integration .shared .common .ThingWithAllCypherTypes ;
6463import org .springframework .data .neo4j .integration .shared .common .ThingWithAllSpatialTypes ;
65- import org .springframework .data .neo4j .integration .shared .conversion .ThingWithCompositeProperties ;
6664import org .springframework .data .neo4j .integration .shared .conversion .ThingWithCustomTypes ;
67- import org .springframework .data .neo4j .integration .shared .common .ThingWithNonExistingPrimitives ;
6865import org .springframework .data .neo4j .integration .shared .common .ThingWithUUIDID ;
6966import org .springframework .data .neo4j .repository .Neo4jRepository ;
7067import org .springframework .data .neo4j .repository .config .EnableNeo4jRepositories ;
7370import org .springframework .test .util .ReflectionTestUtils ;
7471import org .springframework .transaction .PlatformTransactionManager ;
7572import org .springframework .transaction .annotation .EnableTransactionManagement ;
76- import org .springframework .util .ReflectionUtils ;
7773
7874/**
7975 * @author Michael J. Simons
8379@ Neo4jIntegrationTest
8480class TypeConversionIT extends Neo4jConversionsITBase {
8581
86- @ Autowired CypherTypesRepository cypherTypesRepository ;
82+ private final CypherTypesRepository cypherTypesRepository ;
8783
8884 private final AdditionalTypesRepository additionalTypesRepository ;
8985
9086 private final SpatialTypesRepository spatialTypesRepository ;
9187
9288 private final CustomTypesRepository customTypesRepository ;
93- private final BookmarkCapture bookmarkCapture ;
9489
9590 private final DefaultConversionService defaultConversionService ;
9691
9792 @ Autowired TypeConversionIT (CypherTypesRepository cypherTypesRepository ,
9893 AdditionalTypesRepository additionalTypesRepository , SpatialTypesRepository spatialTypesRepository ,
9994 CustomTypesRepository customTypesRepository ,
100- Neo4jConversions neo4jConversions , BookmarkCapture bookmarkCapture ) {
95+ Neo4jConversions neo4jConversions ) {
10196 this .cypherTypesRepository = cypherTypesRepository ;
10297 this .additionalTypesRepository = additionalTypesRepository ;
10398 this .spatialTypesRepository = spatialTypesRepository ;
10499 this .customTypesRepository = customTypesRepository ;
105- this .bookmarkCapture = bookmarkCapture ;
106100 this .defaultConversionService = new DefaultConversionService ();
107101 neo4jConversions .registerConvertersIn (defaultConversionService );
108102 }
109103
110104 @ Test
111- void thereShallBeNoDefaultValuesForNonExistingAttributes (@ Autowired NonExistingPrimitivesRepository repository ) {
105+ void thereShallBeNoDefaultValuesForNonExistingAttributes () {
106+
107+ Long id ;
108+ try (Session session = neo4jConnectionSupport .getDriver ().session (bookmarkCapture .createSessionConfig ())) {
109+
110+ id = session .writeTransaction (tx -> tx .run ("CREATE (n:CypherTypes) RETURN id(n)" ).single ().get (0 ).asLong ());
111+ bookmarkCapture .seedWith (session .lastBookmark ());
112+ }
112113
113114 assertThatExceptionOfType (MappingException .class )
114- .isThrownBy (() -> repository .findById (ID_OF_NON_EXISTING_PRIMITIVES_NODE ))
115+ .isThrownBy (() -> cypherTypesRepository .findById (id ))
115116 .withMessageMatching (
116- "Error mapping Record<\\ {thingWithNonExistingPrimitives : \\ {__internalNeo4jId__: \\ d+, id : NULL, someBoolean : NULL, __nodeLabels__: \\ [\" NonExistingPrimitives \" \\ ] \\ } \\ }>" )
117- .withStackTraceContaining ("unboxBoolean " )
118- .withRootCauseInstanceOf (NullPointerException .class );
117+ "Error mapping Record<\\ {thingWithAllCypherTypes : \\ {__internalNeo4jId__: \\ d+, aBoolean : NULL, aString : NULL, aLong: NULL, anOffsetTime: NULL, aLocalDateTime: NULL, aDouble: NULL, aByteArray: NULL, aPoint: NULL, aZeroDuration: NULL, aZoneDateTime: NULL, __nodeLabels__: \\ [\" CypherTypes \" ], aLocalDate: NULL, aZeroPeriod: NULL, anIsoDuration: NULL, aLocalTime: NULL, id: NULL} }>" )
118+ .withStackTraceContaining ("Illegal arguments for constructor " )
119+ .withRootCauseInstanceOf (IllegalArgumentException .class );
119120 }
120121
121122 @ TestFactory
@@ -162,10 +163,10 @@ Stream<DynamicNode> conversionsShouldBeAppliedToEntities() {
162163 () -> assertThat (ReflectionTestUtils .getField (thing , a .getKey ()))
163164 .isEqualTo (a .getValue ()))));
164165
165- DynamicContainer writes = DynamicContainer .dynamicContainer ("write" , entry .getValue ().entrySet ().stream ()
166- .map (a -> DynamicTest
167- .dynamicTest (a . getKey () ,
168- () -> assertWrite (copyOfThing , a . getKey () , defaultConversionService ))));
166+ DynamicContainer writes = DynamicContainer .dynamicContainer ("write" , entry .getValue ().keySet ().stream ()
167+ .map (o -> DynamicTest
168+ .dynamicTest (o ,
169+ () -> assertWrite (copyOfThing , o , defaultConversionService ))));
169170
170171 return DynamicContainer .dynamicContainer (entry .getKey (), Arrays .asList (reads , writes ));
171172 });
@@ -176,8 +177,6 @@ void assertWrite(Object thing, String fieldName, ConversionService conversionSer
176177 long id = (long ) ReflectionTestUtils .getField (thing , "id" );
177178 Object domainValue = ReflectionTestUtils .getField (thing , fieldName );
178179
179- Field field = ReflectionUtils .findField (thing .getClass (), fieldName );
180- Optional <ConvertWith > annotation = AnnotationUtils .findAnnotation (field , ConvertWith .class );
181180 Function <Object , Value > conversion ;
182181 if (fieldName .equals ("dateAsLong" )) {
183182 conversion = o -> Values .value (((Date ) o ).getTime ());
@@ -189,8 +188,7 @@ void assertWrite(Object thing, String fieldName, ConversionService conversionSer
189188 Value driverValue ;
190189 if (domainValue != null && Collection .class .isAssignableFrom (domainValue .getClass ())) {
191190 Collection <?> sourceCollection = (Collection <?>) domainValue ;
192- Object [] targetCollection = (sourceCollection ).stream ()
193- .map (element -> conversion .apply (element )).toArray ();
191+ Object [] targetCollection = (sourceCollection ).stream ().map (conversion ).toArray ();
194192 driverValue = Values .value (targetCollection );
195193 } else {
196194 driverValue = conversion .apply (domainValue );
@@ -240,6 +238,35 @@ void parametersTargetingConvertedAttributesMustBeConverted(@Autowired CustomType
240238 .hasSizeGreaterThan (0 );
241239 }
242240
241+ @ Test // GH-2348
242+ void nonExistingPrimitivesShouldNotFailWithFieldAccess (@ Autowired Neo4jTemplate template ) {
243+ Long id ;
244+ try (Session session = neo4jConnectionSupport .getDriver ().session (bookmarkCapture .createSessionConfig ())) {
245+
246+ id = session .writeTransaction (tx -> tx .run ("CREATE (n:ThingWithAllCypherTypes2) RETURN id(n)" ).single ().get (0 ).asLong ());
247+ bookmarkCapture .seedWith (session .lastBookmark ());
248+ }
249+
250+ Optional <ThingWithAllCypherTypes2 > optionalResult = template .findById (id , ThingWithAllCypherTypes2 .class );
251+ assertThat (optionalResult ).hasValueSatisfying (result -> {
252+ assertThat (result .isABoolean ()).isFalse ();
253+ assertThat (result .getALong ()).isEqualTo (0L );
254+ assertThat (result .getAnInt ()).isEqualTo (0 );
255+ assertThat (result .getADouble ()).isEqualTo (0.0 );
256+ assertThat (result .getAString ()).isNull ();
257+ assertThat (result .getAByteArray ()).isNull ();
258+ assertThat (result .getALocalDate ()).isNull ();
259+ assertThat (result .getAnOffsetTime ()).isNull ();
260+ assertThat (result .getALocalTime ()).isNull ();
261+ assertThat (result .getAZoneDateTime ()).isNull ();
262+ assertThat (result .getALocalDateTime ()).isNull ();
263+ assertThat (result .getAnIsoDuration ()).isNull ();
264+ assertThat (result .getAPoint ()).isNull ();
265+ assertThat (result .getAZeroPeriod ()).isNull ();
266+ assertThat (result .getAZeroDuration ()).isNull ();
267+ });
268+ }
269+
243270 public interface ConvertedIDsRepository extends Neo4jRepository <ThingWithUUIDID , UUID > {
244271 }
245272
@@ -252,18 +279,11 @@ public interface AdditionalTypesRepository extends Neo4jRepository<ThingWithAllA
252279 public interface SpatialTypesRepository extends Neo4jRepository <ThingWithAllSpatialTypes , Long > {
253280 }
254281
255- public interface NonExistingPrimitivesRepository extends Neo4jRepository <ThingWithNonExistingPrimitives , Long > {
256- }
257-
258282 public interface CustomTypesRepository extends Neo4jRepository <ThingWithCustomTypes , Long > {
259283
260284 List <ThingWithCustomTypes > findAllByDateAsString (Date theDate );
261285 }
262286
263- public interface ThingWithCompositePropertiesRepository
264- extends Neo4jRepository <ThingWithCompositeProperties , Long > {
265- }
266-
267287 @ Configuration
268288 @ EnableNeo4jRepositories (considerNestedRepositories = true )
269289 @ EnableTransactionManagement
@@ -281,7 +301,7 @@ public Neo4jConversions neo4jConversions() {
281301
282302 @ Bean
283303 public BookmarkCapture bookmarkCapture () {
284- return new BookmarkCapture () ;
304+ return Neo4jConversionsITBase . bookmarkCapture ;
285305 }
286306
287307 @ Override
0 commit comments