Skip to content

Commit 8f58434

Browse files
cowtowncoderclaude
andcommitted
Merge branch '2.x' into 3.1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 parents 6246748 + a95ad4f commit 8f58434

6 files changed

Lines changed: 97 additions & 14 deletions

File tree

‎release-notes/CREDITS‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,3 +447,7 @@ Sergey Lappo (@sergeylappo)
447447
* Reported #6227: `BeanDescription` is not thread-safe when called concurrently on the
448448
same instance (`findProperties()`, `findDefaultViews()`)
449449
[3.1.8]
450+
451+
Sanha (@kimsanhaa)
452+
* Fixed #6240: `@JsonValue` ignored on getter also annotated with `@JsonKey`
453+
[3.1.8]

‎release-notes/CREDITS-2.x‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2117,3 +2117,7 @@ Sergey Lappo (@sergeylappo)
21172117
* Reported #6227: `BeanDescription` is not thread-safe when called concurrently on the
21182118
same instance (`findProperties()`, `findDefaultViews()`)
21192119
[2.21.8]
2120+
2121+
Sanha (@kimsanhaa)
2122+
* Fixed #6240: `@JsonValue` ignored on getter also annotated with `@JsonKey`
2123+
[2.23.0]

‎release-notes/VERSION‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ No changes since 3.1
2424
#6236: Retain `JsonFormat.Shape` in `withFormat()` of `Month`, `MonthDay`, `Year`
2525
and `YearMonth` serializers
2626
(fix by @cowtowncoder, w/ Claude code)
27+
#6240: `@JsonValue` ignored on getter also annotated with `@JsonKey`
28+
(fix by @kimsanhaa)
2729

2830
3.1.7 (21-Sep-2026)
2931

‎release-notes/VERSION-2.x‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ Project: jackson-databind
66

77
2.23.0 (not yet released)
88

9-
No changes since 2.22
9+
#6240: `@JsonValue` ignored on getter also annotated with `@JsonKey`
10+
(fix by @kimsanhaa)
1011

1112
2.22.4 (not yet released)
1213

‎src/main/java/tools/jackson/databind/introspect/POJOPropertiesCollector.java‎

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,21 +1179,27 @@ protected void _addGetterMethod(Map<String, POJOPropertyBuilder> props,
11791179
// 07-Feb-2025: [databind#4775] Do not stop processing here
11801180
// (used to return)
11811181
}
1182-
// @JsonKey?
1183-
else if (Boolean.TRUE.equals(_annotationIntrospector.hasAsKey(_config, m))) {
1184-
if (_jsonKeyAccessors == null) {
1185-
_jsonKeyAccessors = new LinkedList<>();
1182+
else {
1183+
// [databind#6240]: may have both (as with fields); neither is a regular property
1184+
boolean asKey = Boolean.TRUE.equals(_annotationIntrospector.hasAsKey(_config, m));
1185+
boolean asValue = Boolean.TRUE.equals(_annotationIntrospector.hasAsValue(_config, m));
1186+
// @JsonKey?
1187+
if (asKey) {
1188+
if (_jsonKeyAccessors == null) {
1189+
_jsonKeyAccessors = new LinkedList<>();
1190+
}
1191+
_jsonKeyAccessors.add(m);
11861192
}
1187-
_jsonKeyAccessors.add(m);
1188-
return;
1189-
}
1190-
// @JsonValue?
1191-
else if (Boolean.TRUE.equals(_annotationIntrospector.hasAsValue(_config, m))) {
1192-
if (_jsonValueAccessors == null) {
1193-
_jsonValueAccessors = new LinkedList<>();
1193+
// @JsonValue?
1194+
if (asValue) {
1195+
if (_jsonValueAccessors == null) {
1196+
_jsonValueAccessors = new LinkedList<>();
1197+
}
1198+
_jsonValueAccessors.add(m);
1199+
}
1200+
if (asKey || asValue) {
1201+
return;
11941202
}
1195-
_jsonValueAccessors.add(m);
1196-
return;
11971203
}
11981204
String implName; // from naming convention
11991205
boolean visible;

‎src/test/java/tools/jackson/databind/ser/jdk/MapSerializationTest.java‎

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,41 @@ static class NoKeyOuter {
168168
}
169169
}
170170

171+
// [databind#6240]: same as `Outer2871`, but annotations on getter
172+
static class OuterWithGetter6240 {
173+
private final Inner2871 inner;
174+
175+
OuterWithGetter6240(Inner2871 inner) {
176+
this.inner = inner;
177+
}
178+
179+
@JsonKey
180+
@JsonValue
181+
public Inner2871 getInner() {
182+
return inner;
183+
}
184+
}
185+
186+
// [databind#6240]
187+
static class KeyOnlyGetter6240 {
188+
public String name = "value";
189+
190+
@JsonKey
191+
@JsonValue(false)
192+
public String getId() {
193+
return "a";
194+
}
195+
}
196+
197+
// [databind#6240]
198+
static class ValueOnlyGetter6240 {
199+
@JsonKey(false)
200+
@JsonValue
201+
public String getId() {
202+
return "a";
203+
}
204+
}
205+
171206
// // // Inner types from MapKeySerializationTest
172207

173208
static class KarlSerializer extends ValueSerializer<String>
@@ -487,6 +522,37 @@ public void testNoKeyOuter() throws Exception {
487522
assertEquals("{\"key\":\"innerValue\"}", actual);
488523
}
489524

525+
// [databind#6240]
526+
@Test
527+
public void testClassAsKeyWithGetter() throws Exception {
528+
OuterWithGetter6240 outer = new OuterWithGetter6240(new Inner2871("innerKey", "innerValue"));
529+
assertEquals("{\"innerKey\":\"value\"}",
530+
MAPPER.writeValueAsString(Collections.singletonMap(outer, "value")));
531+
}
532+
533+
// [databind#6240]
534+
@Test
535+
public void testClassAsValueWithGetter() throws Exception {
536+
OuterWithGetter6240 outer = new OuterWithGetter6240(new Inner2871("innerKey", "innerValue"));
537+
assertEquals("\"innerValue\"", MAPPER.writeValueAsString(outer));
538+
assertEquals("{\"key\":\"innerValue\"}",
539+
MAPPER.writeValueAsString(Collections.singletonMap("key", outer)));
540+
}
541+
542+
// [databind#6240]: disabled `@JsonValue` must not expose key getter as property
543+
@Test
544+
public void testKeyOnlyGetter() throws Exception {
545+
assertEquals("{\"name\":\"value\"}", MAPPER.writeValueAsString(new KeyOnlyGetter6240()));
546+
assertEquals("{\"a\":1}",
547+
MAPPER.writeValueAsString(Collections.singletonMap(new KeyOnlyGetter6240(), 1)));
548+
}
549+
550+
// [databind#6240]: disabled `@JsonKey` must not disable `@JsonValue`
551+
@Test
552+
public void testValueOnlyGetter() throws Exception {
553+
assertEquals("\"a\"", MAPPER.writeValueAsString(new ValueOnlyGetter6240()));
554+
}
555+
490556
// // // Tests from MapKeySerializationTest
491557

492558
@Test

0 commit comments

Comments
 (0)