Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2a15b6c
Fix #5405, @JsonFormat(shape = Shape.POJO) does not work for java.uti…
JacksonJang Dec 1, 2025
58e8c48
Merge branch '3.x' into 5405-map-format-shape-bug
cowtowncoder Dec 3, 2025
18520e9
Merge branch '3.x' into 5405-map-format-shape-bug
cowtowncoder Dec 4, 2025
046dedd
Fix #5405: Apply property-level JsonFormat overrides for cached seria…
JacksonJang Dec 6, 2025
82d0af2
Merge branch '3.x' into 5405-map-format-shape-bug
cowtowncoder Dec 9, 2025
cdc0e61
Merge branch '3.x' into 5405-map-format-shape-bug
cowtowncoder Dec 10, 2025
c544871
Merge branch '3.x' into 5405-map-format-shape-bug
cowtowncoder Dec 10, 2025
c887f1c
Merge branch '3.x' into 5405-map-format-shape-bug
cowtowncoder Dec 10, 2025
bedf466
Merge branch '3.x' into 5405-map-format-shape-bug
cowtowncoder Dec 10, 2025
d21ba45
Merge branch '3.x' into 5405-map-format-shape-bug
cowtowncoder Dec 11, 2025
53463e6
Merge branch '3.x' into 5405-map-format-shape-bug
cowtowncoder Dec 11, 2025
fb8c0e3
Merge branch '3.x' into 5405-map-format-shape-bug
cowtowncoder Dec 11, 2025
784a76e
Merge branch '3.x' into 5405-map-format-shape-bug
cowtowncoder Dec 11, 2025
5909290
Merge branch '3.x' into 5405-map-format-shape-bug
cowtowncoder Dec 12, 2025
02d2b96
Merge branch '3.x' into 5405-map-format-shape-bug
cowtowncoder Dec 13, 2025
662d050
Move test to optimal package
cowtowncoder Dec 13, 2025
4f59606
Add release notes
cowtowncoder Dec 13, 2025
b40b522
tiny comment re-formatting
cowtowncoder Dec 13, 2025
eafd1c7
...
cowtowncoder Dec 13, 2025
dfc0978
Add shape-shifting-check to the other code path.
cowtowncoder Dec 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions release-notes/CREDITS
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,13 @@ Oliver Drotbohm (@odrotbohm)

@JacksonJang
* Contributed fix for #4629: `@JsonIncludeProperties` and `@JsonIgnoreProperties`
ignored when deserializing Records
ignored when deserializing Records
[3.1.0]
* Contributed fix for #5115: `@JsonUnwrapped` Record deserialization can't handle
name collision
name collision
[3.1.0]
* Contributed fix for #5405: `@JsonFormat(shape = Shape.POJO)` does not work for
`java.util.Map` serialization via property annotation
[3.1.0]

Viktor Szathmáry (@phraktle)
Expand Down
5 changes: 4 additions & 1 deletion release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@ Versions: 3.x (for earlier see VERSION-2.x)
#5361: Fix Maven SBOM publishing (worked in 3.0.0-rc4 but not in rc5 or later)
(date-time)#359: `InstantDeserializer` deserializes the nanosecond portion of
fractional negative timestamps incorrectly
#5405: `@JsonFormat(shape = Shape.POJO)` does not work for `java.util.Map`
serialization via property annotation
(fix contributed by @JacksonJang)
#5413: Add/support forward reference resolution for array values
(contributed by Hélios G)
5442: Make `JsonMapper/ObjectMapper` fully proxyable by CGLIB
#5442: Make `JsonMapper/ObjectMapper` fully proxyable by CGLIB
(fix contributed by Fouad A)
#5456: Additional configuration (`JsonNodeFeature.STRIP_TRAILING_BIGDECIMAL_ZEROES`: true)
to MapperBuilder#configureForJackson2 to closer match Jackson 2 behavior
Expand Down
20 changes: 18 additions & 2 deletions src/main/java/tools/jackson/databind/SerializationContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,10 @@ public ValueSerializer<Object> findPrimaryPropertySerializer(JavaType valueType,
ValueSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
if (ser == null) {
ser = _createAndCachePropertySerializer(valueType, property);
} else if (property != null) {
BeanDescription.Supplier beanDescRef = lazyIntrospectBeanDescription(valueType);
// [databind#5405]: property-level @JsonFormat must be honored even with cached serializers
ser = _checkShapeShifting(valueType, beanDescRef, property, ser);
}
return handlePrimaryContextualization(ser, property);
}
Expand All @@ -705,14 +709,26 @@ public ValueSerializer<Object> findPrimaryPropertySerializer(JavaType valueType,
public ValueSerializer<Object> findPrimaryPropertySerializer(Class<?> rawType,
BeanProperty property)
{
boolean checkShape = (property != null);
JavaType fullType = null;

ValueSerializer<Object> ser = _knownSerializers.untypedValueSerializer(rawType);
if (ser == null) {
JavaType fullType = _config.constructType(rawType);
fullType = _config.constructType(rawType);
ser = _serializerCache.untypedValueSerializer(fullType);
if (ser == null) {
checkShape = false; // because next call does it
ser = _createAndCachePropertySerializer(rawType, fullType, property);
}
}
if (checkShape) {
if (fullType == null) {
fullType = _config.constructType(rawType);
}
BeanDescription.Supplier beanDescRef = lazyIntrospectBeanDescription(fullType);
// [databind#5405]: property-level @JsonFormat must be honored even with cached serializers
ser = _checkShapeShifting(fullType, beanDescRef, property, ser);
}
return handlePrimaryContextualization(ser, property);
}

Expand Down Expand Up @@ -1041,7 +1057,7 @@ private ValueSerializer<Object> _checkShapeShifting(JavaType type,
BeanDescription.Supplier beanDescRef, BeanProperty prop, ValueSerializer<?> ser)
{
JsonFormat.Value overrides = prop.findFormatOverrides(_config);
if (overrides != null) {
if (overrides != null && overrides != JsonFormat.Value.empty()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a slight optimization to avoid call when there are no overrides.

// First: it may be completely fine to use serializer, despite some overrides
ValueSerializer<?> ser2 = ser.withFormatOverrides(_config, overrides);
if (ser2 != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package tools.jackson.databind.tofix;
package tools.jackson.databind.format;

import java.util.*;

Expand All @@ -8,9 +8,8 @@
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

import tools.jackson.databind.*;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.testutil.DatabindTestUtil;
import tools.jackson.databind.testutil.failure.JacksonTestFailureExpected;

import static org.junit.jupiter.api.Assertions.assertEquals;

Expand Down Expand Up @@ -72,9 +71,20 @@ public Bean5405Override(int value) {
// [databind#5045]: property overrides for @JsonFormat.shape won't work for Maps
// 30-Nov-2025, tatu: Something about caching is the issue: if "b" commented out,
// override appears to work; with "b" not
@JacksonTestFailureExpected
@Test
public void serializeAsPOJOViaProperty() throws Exception
{
String result = MAPPER.writeValueAsString(new Bean5405Container(1,0,3));
assertEquals(a2q(
"{'a':{'extra':13,'empty':false},'c':{'extra':13,'empty':false}}"),
result);
}

// [databind#5405]:
// 01-Dec-2025, JacksonJang: In this case, the @JsonFormat(shape = POJO) override
// behaves correctly even with b included.
@Test
public void serializeAsPOJOViaFullProperty() throws Exception
{
String result = MAPPER.writeValueAsString(new Bean5405Container(1,2,3));
assertEquals(a2q(
Expand Down