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- private final Driver driver ;
87-
88- @ Autowired CypherTypesRepository cypherTypesRepository ;
82+ private final CypherTypesRepository cypherTypesRepository ;
8983
9084 private final AdditionalTypesRepository additionalTypesRepository ;
9185
9286 private final SpatialTypesRepository spatialTypesRepository ;
9387
9488 private final CustomTypesRepository customTypesRepository ;
95- private final BookmarkCapture bookmarkCapture ;
9689
9790 private final DefaultConversionService defaultConversionService ;
9891
99- @ Autowired TypeConversionIT (Driver driver , CypherTypesRepository cypherTypesRepository ,
92+ @ Autowired TypeConversionIT (CypherTypesRepository cypherTypesRepository ,
10093 AdditionalTypesRepository additionalTypesRepository , SpatialTypesRepository spatialTypesRepository ,
10194 CustomTypesRepository customTypesRepository ,
102- Neo4jConversions neo4jConversions , BookmarkCapture bookmarkCapture ) {
103- this .driver = driver ;
95+ Neo4jConversions neo4jConversions ) {
10496 this .cypherTypesRepository = cypherTypesRepository ;
10597 this .additionalTypesRepository = additionalTypesRepository ;
10698 this .spatialTypesRepository = spatialTypesRepository ;
10799 this .customTypesRepository = customTypesRepository ;
108- this .bookmarkCapture = bookmarkCapture ;
109100 this .defaultConversionService = new DefaultConversionService ();
110101 neo4jConversions .registerConvertersIn (defaultConversionService );
111102 }
112103
113104 @ Test
114- 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+ }
115113
116114 assertThatExceptionOfType (MappingException .class )
117- .isThrownBy (() -> repository .findById (ID_OF_NON_EXISTING_PRIMITIVES_NODE ))
115+ .isThrownBy (() -> cypherTypesRepository .findById (id ))
118116 .withMessageMatching (
119- "Error mapping Record<\\ {n: \\ {__internalNeo4jId__: \\ d+, id : NULL, someBoolean : NULL, __nodeLabels__: \\ [\" NonExistingPrimitives \" \\ ] \\ } \\ }>" )
120- .withStackTraceContaining ("unboxBoolean " )
121- .withRootCauseInstanceOf (NullPointerException .class );
117+ "Error mapping Record<\\ {n: \\ {__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 );
122120 }
123121
124122 @ TestFactory
@@ -165,10 +163,10 @@ Stream<DynamicNode> conversionsShouldBeAppliedToEntities() {
165163 () -> assertThat (ReflectionTestUtils .getField (thing , a .getKey ()))
166164 .isEqualTo (a .getValue ()))));
167165
168- DynamicContainer writes = DynamicContainer .dynamicContainer ("write" , entry .getValue ().entrySet ().stream ()
169- .map (a -> DynamicTest
170- .dynamicTest (a . getKey () ,
171- () -> 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 ))));
172170
173171 return DynamicContainer .dynamicContainer (entry .getKey (), Arrays .asList (reads , writes ));
174172 });
@@ -179,8 +177,6 @@ void assertWrite(Object thing, String fieldName, ConversionService conversionSer
179177 long id = (long ) ReflectionTestUtils .getField (thing , "id" );
180178 Object domainValue = ReflectionTestUtils .getField (thing , fieldName );
181179
182- Field field = ReflectionUtils .findField (thing .getClass (), fieldName );
183- Optional <ConvertWith > annotation = AnnotationUtils .findAnnotation (field , ConvertWith .class );
184180 Function <Object , Value > conversion ;
185181 if (fieldName .equals ("dateAsLong" )) {
186182 conversion = o -> Values .value (((Date ) o ).getTime ());
@@ -192,8 +188,7 @@ void assertWrite(Object thing, String fieldName, ConversionService conversionSer
192188 Value driverValue ;
193189 if (domainValue != null && Collection .class .isAssignableFrom (domainValue .getClass ())) {
194190 Collection <?> sourceCollection = (Collection <?>) domainValue ;
195- Object [] targetCollection = (sourceCollection ).stream ()
196- .map (element -> conversion .apply (element )).toArray ();
191+ Object [] targetCollection = (sourceCollection ).stream ().map (conversion ).toArray ();
197192 driverValue = Values .value (targetCollection );
198193 } else {
199194 driverValue = conversion .apply (domainValue );
@@ -243,6 +238,35 @@ void parametersTargetingConvertedAttributesMustBeConverted(@Autowired CustomType
243238 .hasSizeGreaterThan (0 );
244239 }
245240
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+
246270 public interface ConvertedIDsRepository extends Neo4jRepository <ThingWithUUIDID , UUID > {
247271 }
248272
@@ -255,18 +279,11 @@ public interface AdditionalTypesRepository extends Neo4jRepository<ThingWithAllA
255279 public interface SpatialTypesRepository extends Neo4jRepository <ThingWithAllSpatialTypes , Long > {
256280 }
257281
258- public interface NonExistingPrimitivesRepository extends Neo4jRepository <ThingWithNonExistingPrimitives , Long > {
259- }
260-
261282 public interface CustomTypesRepository extends Neo4jRepository <ThingWithCustomTypes , Long > {
262283
263284 List <ThingWithCustomTypes > findAllByDateAsString (Date theDate );
264285 }
265286
266- public interface ThingWithCompositePropertiesRepository
267- extends Neo4jRepository <ThingWithCompositeProperties , Long > {
268- }
269-
270287 @ Configuration
271288 @ EnableNeo4jRepositories (considerNestedRepositories = true )
272289 @ EnableTransactionManagement
@@ -284,7 +301,7 @@ public Neo4jConversions neo4jConversions() {
284301
285302 @ Bean
286303 public BookmarkCapture bookmarkCapture () {
287- return new BookmarkCapture () ;
304+ return Neo4jConversionsITBase . bookmarkCapture ;
288305 }
289306
290307 @ Override
0 commit comments