Skip to content

Commit 30e7bec

Browse files
committed
Merge branch '2.14' into 2.15
2 parents 3466a73 + 075ec92 commit 30e7bec

File tree

4 files changed

+93
-8
lines changed

4 files changed

+93
-8
lines changed

release-notes/CREDITS-2.x

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1535,6 +1535,10 @@ Philippe Marschall (marschall@github)
15351535
* Contributed #3699: Allow custom `JsonNode` implementations
15361536
(2.14.2)
15371537
1538+
Gili Tzabari (cowwoc@github)
1539+
* Reported #3063: `@JsonValue` fails for Java Record
1540+
(2.14.2)
1541+
15381542
Hervé Boutemy (hboutemy@github)
15391543
* Contributed fix for #3680: Timestamp in classes inside jar showing 02/01/1980
15401544
(2.15.0)
@@ -1550,4 +1554,3 @@ Sim Yih Tsern (yihtsern@github)
15501554
(2.15.0)
15511555
* Contributed fix for #3342: `JsonTypeInfo.As.EXTERNAL_PROPERTY` does not work with record wrappers
15521556
(2.15.0)
1553-

release-notes/VERSION-2.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ Project: jackson-databind
3131

3232
#1751: `@JsonTypeInfo` does not work if the Type Id is an Integer value
3333
(reported by @marvin-we)
34+
#3063: `@JsonValue` fails for Java Record
35+
(reported by Gili T)
3436
#3699: Allow custom `JsonNode` implementations
3537
(contributed by Philippe M)
3638
#3711: Enum polymorphism not working correctly with DEDUCTION

src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,11 @@ public AnnotatedMember getJsonKeyAccessor() {
259259
// If @JsonKey defined, must have a single one
260260
if (_jsonKeyAccessors != null) {
261261
if (_jsonKeyAccessors.size() > 1) {
262-
reportProblem("Multiple 'as-key' properties defined (%s vs %s)",
263-
_jsonKeyAccessors.get(0),
264-
_jsonKeyAccessors.get(1));
262+
if (!_resolveFieldVsGetter(_jsonKeyAccessors)) {
263+
reportProblem("Multiple 'as-key' properties defined (%s vs %s)",
264+
_jsonKeyAccessors.get(0),
265+
_jsonKeyAccessors.get(1));
266+
}
265267
}
266268
// otherwise we won't greatly care
267269
return _jsonKeyAccessors.get(0);
@@ -278,11 +280,14 @@ public AnnotatedMember getJsonValueAccessor()
278280
collectAll();
279281
}
280282
// If @JsonValue defined, must have a single one
283+
// 15-Jan-2023, tatu: Except let's try resolving "getter-over-field" case at least
281284
if (_jsonValueAccessors != null) {
282285
if (_jsonValueAccessors.size() > 1) {
283-
reportProblem("Multiple 'as-value' properties defined (%s vs %s)",
284-
_jsonValueAccessors.get(0),
285-
_jsonValueAccessors.get(1));
286+
if (!_resolveFieldVsGetter(_jsonValueAccessors)) {
287+
reportProblem("Multiple 'as-value' properties defined (%s vs %s)",
288+
_jsonValueAccessors.get(0),
289+
_jsonValueAccessors.get(1));
290+
}
286291
}
287292
// otherwise we won't greatly care
288293
return _jsonValueAccessors.get(0);
@@ -1189,7 +1194,7 @@ protected void _renameWithWrappers(Map<String, POJOPropertyBuilder> props)
11891194

11901195
/*
11911196
/**********************************************************
1192-
/* Overridable internal methods, sorting, other stuff
1197+
/* Internal methods, sorting
11931198
/**********************************************************
11941199
*/
11951200

@@ -1310,6 +1315,48 @@ private boolean _anyIndexed(Collection<POJOPropertyBuilder> props) {
13101315
return false;
13111316
}
13121317

1318+
/*
1319+
/**********************************************************
1320+
/* Internal methods, conflict resolution
1321+
/**********************************************************
1322+
*/
1323+
1324+
/**
1325+
* Method that will be given a {@link List} with 2 or more accessors
1326+
* that may be in conflict: it will need to remove lower-priority accessors
1327+
* to leave just a single highest-priority accessor to use.
1328+
* If this succeeds method returns {@code true}, otherwise {@code false}.
1329+
*<p>
1330+
* NOTE: method will directly modify given {@code List} directly, regardless
1331+
* of whether it ultimately succeeds or not.
1332+
*
1333+
* @return True if seeming conflict was resolved and there only remains
1334+
* single accessor
1335+
*/
1336+
protected boolean _resolveFieldVsGetter(List<AnnotatedMember> accessors) {
1337+
do {
1338+
AnnotatedMember acc1 = accessors.get(0);
1339+
AnnotatedMember acc2 = accessors.get(1);
1340+
1341+
if (acc1 instanceof AnnotatedField) {
1342+
if (acc2 instanceof AnnotatedMethod) {
1343+
// Method has precedence, remove first entry
1344+
accessors.remove(0);
1345+
continue;
1346+
}
1347+
} else if (acc1 instanceof AnnotatedMethod) {
1348+
// Method has precedence, remove second entry
1349+
if (acc2 instanceof AnnotatedField) {
1350+
accessors.remove(1);
1351+
continue;
1352+
}
1353+
}
1354+
// Not a field/method pair; fail
1355+
return false;
1356+
} while (accessors.size() > 1);
1357+
return true;
1358+
}
1359+
13131360
/*
13141361
/**********************************************************
13151362
/* Internal methods; helpers
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.fasterxml.jackson.databind.records;
2+
3+
import java.util.Collections;
4+
import java.util.Map;
5+
6+
import com.fasterxml.jackson.annotation.*;
7+
8+
import com.fasterxml.jackson.databind.BaseMapTest;
9+
import com.fasterxml.jackson.databind.ObjectMapper;
10+
11+
public class RecordJsonValue3063Test extends BaseMapTest
12+
{
13+
// [databind#3063]
14+
record GetLocations3063(@JsonValue Map<String, String> nameToLocation)
15+
{
16+
@JsonCreator
17+
public GetLocations3063(Map<String, String> nameToLocation)
18+
{
19+
this.nameToLocation = nameToLocation;
20+
}
21+
}
22+
23+
private final ObjectMapper MAPPER = newJsonMapper();
24+
25+
// [databind#3063]
26+
public void testRecordWithJsonValue3063() throws Exception
27+
{
28+
Map<String, String> locations = Collections.singletonMap("a", "locationA");
29+
String json = MAPPER.writeValueAsString(new GetLocations3063(locations));
30+
31+
assertNotNull(json);
32+
}
33+
}

0 commit comments

Comments
 (0)