Skip to content

Commit a50c7e1

Browse files
authored
fix(object-mapping): try making record components accessible (#1681)
In some cases reading components of `record` may fail as their accessors may not be accessible. This update makes sure the driver tries to make them accessible. For instance, this is useful when using local `record` in a stricter runtime. The `ObjectMappingTests` actually had a test for this, but it did not fail when it was run as a unit test. The tests have been moved to integration tests without any other update.
1 parent 8bf8858 commit a50c7e1

File tree

2 files changed

+64
-16
lines changed

2 files changed

+64
-16
lines changed

driver/src/main/java/org/neo4j/driver/Values.java

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static org.neo4j.driver.internal.util.Extract.assertParameter;
2020
import static org.neo4j.driver.internal.util.Iterables.newHashMapWithSize;
2121

22+
import java.lang.reflect.AccessibleObject;
2223
import java.time.Duration;
2324
import java.time.LocalDate;
2425
import java.time.LocalDateTime;
@@ -247,6 +248,7 @@ public static Value value(Object value) {
247248

248249
/**
249250
* Returns an array of values from object vararg.
251+
*
250252
* @param input the object value(s)
251253
* @return the array of values
252254
*/
@@ -256,6 +258,7 @@ public static Value[] values(final Object... input) {
256258

257259
/**
258260
* Returns a value from value vararg.
261+
*
259262
* @param input the value(s)
260263
* @return the value
261264
*/
@@ -265,6 +268,7 @@ public static Value value(Value... input) {
265268

266269
/**
267270
* Returns a value from byte vararg.
271+
*
268272
* @param input the byte value(s)
269273
* @return the value
270274
*/
@@ -274,6 +278,7 @@ public static Value value(byte... input) {
274278

275279
/**
276280
* Returns a value from string vararg.
281+
*
277282
* @param input the string value(s)
278283
* @return the value
279284
*/
@@ -286,6 +291,7 @@ public static Value value(String... input) {
286291

287292
/**
288293
* Returns a value from boolean vararg.
294+
*
289295
* @param input the boolean value(s)
290296
* @return the value
291297
*/
@@ -298,6 +304,7 @@ public static Value value(boolean... input) {
298304

299305
/**
300306
* Returns a value from char vararg.
307+
*
301308
* @param input the char value(s)
302309
* @return the value
303310
*/
@@ -310,6 +317,7 @@ public static Value value(char... input) {
310317

311318
/**
312319
* Returns a value from long vararg.
320+
*
313321
* @param input the long value(s)
314322
* @return the value
315323
*/
@@ -322,6 +330,7 @@ public static Value value(long... input) {
322330

323331
/**
324332
* Returns a value from short vararg.
333+
*
325334
* @param input the short value(s)
326335
* @return the value
327336
*/
@@ -331,8 +340,10 @@ public static Value value(short... input) {
331340
.collect(Collectors.toCollection(() -> new ArrayList<>(input.length)));
332341
return new ListValue(values);
333342
}
343+
334344
/**
335345
* Returns a value from int vararg.
346+
*
336347
* @param input the int value(s)
337348
* @return the value
338349
*/
@@ -342,8 +353,10 @@ public static Value value(int... input) {
342353
.collect(Collectors.toCollection(() -> new ArrayList<>(input.length)));
343354
return new ListValue(values);
344355
}
356+
345357
/**
346358
* Returns a value from double vararg.
359+
*
347360
* @param input the double value(s)
348361
* @return the value
349362
*/
@@ -356,6 +369,7 @@ public static Value value(double... input) {
356369

357370
/**
358371
* Returns a value from float vararg.
372+
*
359373
* @param input the float value(s)
360374
* @return the value
361375
*/
@@ -368,6 +382,7 @@ public static Value value(float... input) {
368382

369383
/**
370384
* Returns a value from list of objects.
385+
*
371386
* @param vals the list of objects
372387
* @return the value
373388
*/
@@ -379,6 +394,7 @@ public static Value value(List<Object> vals) {
379394

380395
/**
381396
* Returns a value from iterable of objects.
397+
*
382398
* @param val the iterable of objects
383399
* @return the value
384400
*/
@@ -388,6 +404,7 @@ public static Value value(Iterable<Object> val) {
388404

389405
/**
390406
* Returns a value from iterator of objects.
407+
*
391408
* @param val the iterator of objects
392409
* @return the value
393410
*/
@@ -401,6 +418,7 @@ public static Value value(Iterator<Object> val) {
401418

402419
/**
403420
* Returns a value from stream of objects.
421+
*
404422
* @param stream the stream of objects
405423
* @return the value
406424
*/
@@ -463,14 +481,17 @@ public static Value value(Stream<Object> stream) {
463481
* limitations on how those are supported by the database. Please read the Neo4j Cypher Manual for more up-to-date
464482
* details. For example, at the time of writing, it is not possible to store maps as properties
465483
* (see the following <a href="https://neo4j.com/docs/cypher-manual/current/values-and-types/property-structural-constructed/#constructed-types">page</a>).
484+
* <p>
485+
* If accessors for record components are not accessible, the driver will try to make them accessible using
486+
* {@link AccessibleObject#trySetAccessible()} and will emit an error if this does not succeed.
466487
*
467488
* @param record the record to map
468489
* @return the map value
490+
* @throws ClientException when mapping fails
469491
* @see TypeSystem#MAP()
470492
* @see java.lang.Record
471493
* @see java.lang.reflect.RecordComponent
472494
* @see Property
473-
* @throws ClientException when mapping fails
474495
* @since 5.28.5
475496
*/
476497
@Preview(name = "Object mapping")
@@ -483,11 +504,16 @@ public static Value value(java.lang.Record record) {
483504
var isVector = recordComponent.getAnnotation(org.neo4j.driver.mapping.Vector.class) != null;
484505
Value value;
485506
try {
486-
var objectValue = recordComponent.getAccessor().invoke(record);
507+
var accessor = recordComponent.getAccessor();
508+
if (!accessor.canAccess(record) && !accessor.trySetAccessible()) {
509+
throw new IllegalStateException(
510+
"Failed to make record component '%s' accessible".formatted(recordComponent.getName()));
511+
}
512+
var objectValue = accessor.invoke(record);
487513
value = (objectValue != null) ? isVector ? vector(objectValue) : value(objectValue) : null;
488514
} catch (Throwable throwable) {
489515
var message = "Failed to map '%s' property to value during mapping '%s' to map value"
490-
.formatted(property, record.getClass().getCanonicalName());
516+
.formatted(property, record.getClass().getName());
491517
throw new ClientException(
492518
GqlStatusError.UNKNOWN.getStatus(),
493519
GqlStatusError.UNKNOWN.getStatusDescription(message),
@@ -505,6 +531,7 @@ public static Value value(java.lang.Record record) {
505531

506532
/**
507533
* Returns a value from char.
534+
*
508535
* @param val the char value
509536
* @return the value
510537
*/
@@ -514,6 +541,7 @@ public static Value value(final char val) {
514541

515542
/**
516543
* Returns a value from string.
544+
*
517545
* @param val the string value
518546
* @return the value
519547
*/
@@ -523,6 +551,7 @@ public static Value value(final String val) {
523551

524552
/**
525553
* Returns a value from long.
554+
*
526555
* @param val the long value
527556
* @return the value
528557
*/
@@ -532,6 +561,7 @@ public static Value value(final long val) {
532561

533562
/**
534563
* Returns a value from int.
564+
*
535565
* @param val the int value
536566
* @return the value
537567
*/
@@ -541,6 +571,7 @@ public static Value value(final int val) {
541571

542572
/**
543573
* Returns a value from double.
574+
*
544575
* @param val the double value
545576
* @return the value
546577
*/
@@ -550,6 +581,7 @@ public static Value value(final double val) {
550581

551582
/**
552583
* Returns a value from boolean.
584+
*
553585
* @param val the boolean value
554586
* @return the value
555587
*/
@@ -559,6 +591,7 @@ public static Value value(final boolean val) {
559591

560592
/**
561593
* Returns a value from string to object map.
594+
*
562595
* @param val the string to object map
563596
* @return the value
564597
*/
@@ -572,6 +605,7 @@ public static Value value(final Map<String, Object> val) {
572605

573606
/**
574607
* Returns a value from local date.
608+
*
575609
* @param localDate the local date value
576610
* @return the value
577611
*/
@@ -581,6 +615,7 @@ public static Value value(LocalDate localDate) {
581615

582616
/**
583617
* Returns a value from offset time.
618+
*
584619
* @param offsetTime the offset time value
585620
* @return the value
586621
*/
@@ -590,6 +625,7 @@ public static Value value(OffsetTime offsetTime) {
590625

591626
/**
592627
* Returns a value from local time.
628+
*
593629
* @param localTime the local time value
594630
* @return the value
595631
*/
@@ -599,6 +635,7 @@ public static Value value(LocalTime localTime) {
599635

600636
/**
601637
* Returns a value from local date time.
638+
*
602639
* @param localDateTime the local date time value
603640
* @return the value
604641
*/
@@ -608,6 +645,7 @@ public static Value value(LocalDateTime localDateTime) {
608645

609646
/**
610647
* Returns a value from offset date time.
648+
*
611649
* @param offsetDateTime the offset date time value
612650
* @return the value
613651
*/
@@ -617,6 +655,7 @@ public static Value value(OffsetDateTime offsetDateTime) {
617655

618656
/**
619657
* Returns a value from zoned date time.
658+
*
620659
* @param zonedDateTime the zoned date time value
621660
* @return the value
622661
*/
@@ -626,6 +665,7 @@ public static Value value(ZonedDateTime zonedDateTime) {
626665

627666
/**
628667
* Returns a value from period.
668+
*
629669
* @param period the period value
630670
* @return the value
631671
*/
@@ -635,6 +675,7 @@ public static Value value(Period period) {
635675

636676
/**
637677
* Returns a value from duration.
678+
*
638679
* @param duration the duration value
639680
* @return the value
640681
*/
@@ -644,9 +685,10 @@ public static Value value(Duration duration) {
644685

645686
/**
646687
* Returns a value from month, day, seconds and nanoseconds values.
647-
* @param months the month value
648-
* @param days the day value
649-
* @param seconds the seconds value
688+
*
689+
* @param months the month value
690+
* @param days the day value
691+
* @param seconds the seconds value
650692
* @param nanoseconds the nanoseconds value
651693
* @return the value
652694
*/
@@ -656,6 +698,7 @@ public static Value isoDuration(long months, long days, long seconds, int nanose
656698

657699
/**
658700
* Returns a value from ISO duration.
701+
*
659702
* @param duration the ISO duration value
660703
* @return the value
661704
*/
@@ -665,9 +708,10 @@ private static Value value(IsoDuration duration) {
665708

666709
/**
667710
* Returns a value from SRID, x and y values.
711+
*
668712
* @param srid the SRID value
669-
* @param x the x value
670-
* @param y the y value
713+
* @param x the x value
714+
* @param y the y value
671715
* @return the value
672716
*/
673717
public static Value point(int srid, double x, double y) {
@@ -676,6 +720,7 @@ public static Value point(int srid, double x, double y) {
676720

677721
/**
678722
* Returns a value from point.
723+
*
679724
* @param point the point value
680725
* @return the value
681726
*/
@@ -685,10 +730,11 @@ private static Value value(Point point) {
685730

686731
/**
687732
* Returns a value from SRID, x ,y and z values.
733+
*
688734
* @param srid the SRID value
689-
* @param x the x value
690-
* @param y the y value
691-
* @param z the z value
735+
* @param x the x value
736+
* @param y the y value
737+
* @param z the z value
692738
* @return the value
693739
*/
694740
public static Value point(int srid, double x, double y, double z) {
@@ -854,7 +900,7 @@ public static Function<Value, Map<String, Object>> ofMap() {
854900
* the provided converter.
855901
*
856902
* @param valueConverter converter to use for the values of the map
857-
* @param <T> the type of values in the returned map
903+
* @param <T> the type of values in the returned map
858904
* @return a function that returns {@link Value#asMap(Function)} of a {@link Value}
859905
*/
860906
public static <T> Function<Value, Map<String, T>> ofMap(final Function<Value, T> valueConverter) {
@@ -873,8 +919,8 @@ public static Function<Value, Entity> ofEntity() {
873919
/**
874920
* Converts values to {@link Long entity id}.
875921
*
876-
* @deprecated superseded by {@link #ofEntityElementId()}.
877922
* @return a function that returns the id an entity {@link Value}
923+
* @deprecated superseded by {@link #ofEntityElementId()}.
878924
*/
879925
@Deprecated
880926
public static Function<Value, Long> ofEntityId() {
@@ -1002,7 +1048,7 @@ public static Function<Value, List<Object>> ofList() {
10021048
* Converts values to {@link List} of {@code T}.
10031049
*
10041050
* @param innerMap converter for the values inside the list
1005-
* @param <T> the type of values inside the list
1051+
* @param <T> the type of values inside the list
10061052
* @return a function that returns {@link Value#asList(Function)} of a {@link Value}
10071053
*/
10081054
public static <T> Function<Value, List<T>> ofList(final Function<Value, T> innerMap) {

0 commit comments

Comments
 (0)