18
18
import static org .assertj .core .api .Assertions .assertThat ;
19
19
import static org .assertj .core .api .Assertions .assertThatExceptionOfType ;
20
20
21
- import java .lang .reflect .Field ;
22
21
import java .text .SimpleDateFormat ;
23
22
import java .time .ZoneId ;
24
23
import java .time .ZonedDateTime ;
41
40
import org .junit .jupiter .api .DynamicTest ;
42
41
import org .junit .jupiter .api .Test ;
43
42
import org .junit .jupiter .api .TestFactory ;
44
- import org .junit .platform .commons .util .AnnotationUtils ;
45
43
import org .neo4j .driver .Driver ;
46
44
import org .neo4j .driver .Session ;
47
45
import org .neo4j .driver .Value ;
54
52
import org .springframework .data .mapping .MappingException ;
55
53
import org .springframework .data .neo4j .config .AbstractNeo4jConfig ;
56
54
import org .springframework .data .neo4j .core .DatabaseSelectionProvider ;
57
- import org .springframework .data .neo4j .core .convert . ConvertWith ;
55
+ import org .springframework .data .neo4j .core .Neo4jTemplate ;
58
56
import org .springframework .data .neo4j .core .convert .Neo4jConversions ;
59
57
import org .springframework .data .neo4j .core .transaction .Neo4jBookmarkManager ;
60
58
import org .springframework .data .neo4j .core .transaction .Neo4jTransactionManager ;
59
+ import org .springframework .data .neo4j .integration .shared .common .ThingWithAllCypherTypes2 ;
61
60
import org .springframework .data .neo4j .integration .shared .conversion .Neo4jConversionsITBase ;
62
61
import org .springframework .data .neo4j .integration .shared .conversion .ThingWithAllAdditionalTypes ;
63
62
import org .springframework .data .neo4j .integration .shared .common .ThingWithAllCypherTypes ;
64
63
import org .springframework .data .neo4j .integration .shared .common .ThingWithAllSpatialTypes ;
65
- import org .springframework .data .neo4j .integration .shared .conversion .ThingWithCompositeProperties ;
66
64
import org .springframework .data .neo4j .integration .shared .conversion .ThingWithCustomTypes ;
67
- import org .springframework .data .neo4j .integration .shared .common .ThingWithNonExistingPrimitives ;
68
65
import org .springframework .data .neo4j .integration .shared .common .ThingWithUUIDID ;
69
66
import org .springframework .data .neo4j .repository .Neo4jRepository ;
70
67
import org .springframework .data .neo4j .repository .config .EnableNeo4jRepositories ;
73
70
import org .springframework .test .util .ReflectionTestUtils ;
74
71
import org .springframework .transaction .PlatformTransactionManager ;
75
72
import org .springframework .transaction .annotation .EnableTransactionManagement ;
76
- import org .springframework .util .ReflectionUtils ;
77
73
78
74
/**
79
75
* @author Michael J. Simons
83
79
@ Neo4jIntegrationTest
84
80
class TypeConversionIT extends Neo4jConversionsITBase {
85
81
86
- private final Driver driver ;
87
-
88
- @ Autowired CypherTypesRepository cypherTypesRepository ;
82
+ private final CypherTypesRepository cypherTypesRepository ;
89
83
90
84
private final AdditionalTypesRepository additionalTypesRepository ;
91
85
92
86
private final SpatialTypesRepository spatialTypesRepository ;
93
87
94
88
private final CustomTypesRepository customTypesRepository ;
95
- private final BookmarkCapture bookmarkCapture ;
96
89
97
90
private final DefaultConversionService defaultConversionService ;
98
91
99
- @ Autowired TypeConversionIT (Driver driver , CypherTypesRepository cypherTypesRepository ,
92
+ @ Autowired TypeConversionIT (CypherTypesRepository cypherTypesRepository ,
100
93
AdditionalTypesRepository additionalTypesRepository , SpatialTypesRepository spatialTypesRepository ,
101
94
CustomTypesRepository customTypesRepository ,
102
- Neo4jConversions neo4jConversions , BookmarkCapture bookmarkCapture ) {
103
- this .driver = driver ;
95
+ Neo4jConversions neo4jConversions ) {
104
96
this .cypherTypesRepository = cypherTypesRepository ;
105
97
this .additionalTypesRepository = additionalTypesRepository ;
106
98
this .spatialTypesRepository = spatialTypesRepository ;
107
99
this .customTypesRepository = customTypesRepository ;
108
- this .bookmarkCapture = bookmarkCapture ;
109
100
this .defaultConversionService = new DefaultConversionService ();
110
101
neo4jConversions .registerConvertersIn (defaultConversionService );
111
102
}
112
103
113
104
@ 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
+ }
115
113
116
114
assertThatExceptionOfType (MappingException .class )
117
- .isThrownBy (() -> repository .findById (ID_OF_NON_EXISTING_PRIMITIVES_NODE ))
115
+ .isThrownBy (() -> cypherTypesRepository .findById (id ))
118
116
.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 );
122
120
}
123
121
124
122
@ TestFactory
@@ -165,10 +163,10 @@ Stream<DynamicNode> conversionsShouldBeAppliedToEntities() {
165
163
() -> assertThat (ReflectionTestUtils .getField (thing , a .getKey ()))
166
164
.isEqualTo (a .getValue ()))));
167
165
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 ))));
172
170
173
171
return DynamicContainer .dynamicContainer (entry .getKey (), Arrays .asList (reads , writes ));
174
172
});
@@ -179,8 +177,6 @@ void assertWrite(Object thing, String fieldName, ConversionService conversionSer
179
177
long id = (long ) ReflectionTestUtils .getField (thing , "id" );
180
178
Object domainValue = ReflectionTestUtils .getField (thing , fieldName );
181
179
182
- Field field = ReflectionUtils .findField (thing .getClass (), fieldName );
183
- Optional <ConvertWith > annotation = AnnotationUtils .findAnnotation (field , ConvertWith .class );
184
180
Function <Object , Value > conversion ;
185
181
if (fieldName .equals ("dateAsLong" )) {
186
182
conversion = o -> Values .value (((Date ) o ).getTime ());
@@ -192,8 +188,7 @@ void assertWrite(Object thing, String fieldName, ConversionService conversionSer
192
188
Value driverValue ;
193
189
if (domainValue != null && Collection .class .isAssignableFrom (domainValue .getClass ())) {
194
190
Collection <?> sourceCollection = (Collection <?>) domainValue ;
195
- Object [] targetCollection = (sourceCollection ).stream ()
196
- .map (element -> conversion .apply (element )).toArray ();
191
+ Object [] targetCollection = (sourceCollection ).stream ().map (conversion ).toArray ();
197
192
driverValue = Values .value (targetCollection );
198
193
} else {
199
194
driverValue = conversion .apply (domainValue );
@@ -243,6 +238,35 @@ void parametersTargetingConvertedAttributesMustBeConverted(@Autowired CustomType
243
238
.hasSizeGreaterThan (0 );
244
239
}
245
240
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
+
246
270
public interface ConvertedIDsRepository extends Neo4jRepository <ThingWithUUIDID , UUID > {
247
271
}
248
272
@@ -255,18 +279,11 @@ public interface AdditionalTypesRepository extends Neo4jRepository<ThingWithAllA
255
279
public interface SpatialTypesRepository extends Neo4jRepository <ThingWithAllSpatialTypes , Long > {
256
280
}
257
281
258
- public interface NonExistingPrimitivesRepository extends Neo4jRepository <ThingWithNonExistingPrimitives , Long > {
259
- }
260
-
261
282
public interface CustomTypesRepository extends Neo4jRepository <ThingWithCustomTypes , Long > {
262
283
263
284
List <ThingWithCustomTypes > findAllByDateAsString (Date theDate );
264
285
}
265
286
266
- public interface ThingWithCompositePropertiesRepository
267
- extends Neo4jRepository <ThingWithCompositeProperties , Long > {
268
- }
269
-
270
287
@ Configuration
271
288
@ EnableNeo4jRepositories (considerNestedRepositories = true )
272
289
@ EnableTransactionManagement
@@ -284,7 +301,7 @@ public Neo4jConversions neo4jConversions() {
284
301
285
302
@ Bean
286
303
public BookmarkCapture bookmarkCapture () {
287
- return new BookmarkCapture () ;
304
+ return Neo4jConversionsITBase . bookmarkCapture ;
288
305
}
289
306
290
307
@ Override
0 commit comments