Skip to content

Commit 82400d7

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

6 files changed

Lines changed: 99 additions & 14 deletions

File tree

‎release-notes/CREDITS‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,3 +672,7 @@ Sergey Lappo (@sergeylappo)
672672
* Reported #6227: `BeanDescription` is not thread-safe when called concurrently on the
673673
same instance (`findProperties()`, `findDefaultViews()`)
674674
[3.2.4]
675+
676+
Sanha (@kimsanhaa)
677+
* Fixed #6240: `@JsonValue` ignored on getter also annotated with `@JsonKey`
678+
[3.2.4]

‎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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ No changes since 3.2
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.2.3 (21-Sep-2026)
2931

@@ -363,6 +365,8 @@ No changes since 3.2
363365
#6236: Retain `JsonFormat.Shape` in `withFormat()` of `Month`, `MonthDay`, `Year`
364366
and `YearMonth` serializers
365367
(fix by @cowtowncoder, w/ Claude code)
368+
#6240: `@JsonValue` ignored on getter also annotated with `@JsonKey`
369+
(fix by @kimsanhaa)
366370

367371
3.1.7 (21-Sep-2026)
368372

‎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
@@ -1258,21 +1258,27 @@ protected void _addGetterMethod(Map<String, POJOPropertyBuilder> props,
12581258
// 07-Feb-2025: [databind#4775] Do not stop processing here
12591259
// (used to return)
12601260
}
1261-
// @JsonKey?
1262-
else if (Boolean.TRUE.equals(_annotationIntrospector.hasAsKey(_config, m))) {
1263-
if (_jsonKeyAccessors == null) {
1264-
_jsonKeyAccessors = new LinkedList<>();
1261+
else {
1262+
// [databind#6240]: may have both (as with fields); neither is a regular property
1263+
boolean asKey = Boolean.TRUE.equals(_annotationIntrospector.hasAsKey(_config, m));
1264+
boolean asValue = Boolean.TRUE.equals(_annotationIntrospector.hasAsValue(_config, m));
1265+
// @JsonKey?
1266+
if (asKey) {
1267+
if (_jsonKeyAccessors == null) {
1268+
_jsonKeyAccessors = new LinkedList<>();
1269+
}
1270+
_jsonKeyAccessors.add(m);
12651271
}
1266-
_jsonKeyAccessors.add(m);
1267-
return;
1268-
}
1269-
// @JsonValue?
1270-
else if (Boolean.TRUE.equals(_annotationIntrospector.hasAsValue(_config, m))) {
1271-
if (_jsonValueAccessors == null) {
1272-
_jsonValueAccessors = new LinkedList<>();
1272+
// @JsonValue?
1273+
if (asValue) {
1274+
if (_jsonValueAccessors == null) {
1275+
_jsonValueAccessors = new LinkedList<>();
1276+
}
1277+
_jsonValueAccessors.add(m);
1278+
}
1279+
if (asKey || asValue) {
1280+
return;
12731281
}
1274-
_jsonValueAccessors.add(m);
1275-
return;
12761282
}
12771283
String implName; // from naming convention
12781284
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 @@ public 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)