diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310StringParsableDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310StringParsableDeserializer.java index 96596a34..31d25f25 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310StringParsableDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310StringParsableDeserializer.java @@ -131,7 +131,15 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx } else if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { // 20-Apr-2016, tatu: Related to [databind#1208], can try supporting embedded // values quite easily - return p.getEmbeddedObject(); + // [modules-java8#389]: only accept a value of this type. A byte[] must + // not be stored as a ZoneId, Period, or ZoneOffset. + Object embedded = p.getEmbeddedObject(); + if (embedded == null || handledType().isInstance(embedded)) { + return embedded; + } + return _handleUnexpectedToken(ctxt, p, + "Unexpected embedded value of type %s", + embedded.getClass().getName()); } else if (p.isExpectedStartArrayToken()) { return _deserializeFromArray(p, ctxt); } diff --git a/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310EmbeddedObjectDeserTest.java b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310EmbeddedObjectDeserTest.java new file mode 100644 index 00000000..7e1beea6 --- /dev/null +++ b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310EmbeddedObjectDeserTest.java @@ -0,0 +1,64 @@ +package com.fasterxml.jackson.datatype.jsr310.deser; + +import java.time.Period; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.datatype.jsr310.ModuleTestBase; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; + +// [modules-java8#389] +public class JSR310EmbeddedObjectDeserTest extends ModuleTestBase +{ + private final ObjectMapper MAPPER = newMapper(); + + @Test + public void testZoneIdRejectsEmbeddedBytes() { + ObjectNode node = MAPPER.createObjectNode(); + node.putPOJO("zone", new byte[] { (byte) 0xDE, (byte) 0xAD }); + + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> + MAPPER.convertValue(node, new TypeReference>() { })); + assertInstanceOf(MismatchedInputException.class, e.getCause()); + } + + @Test + public void testZoneIdAcceptsEmbeddedZoneId() { + ObjectNode node = MAPPER.createObjectNode(); + node.putPOJO("zone", ZoneId.of("UTC")); + + Map result = MAPPER.convertValue(node, + new TypeReference>() { }); + assertEquals(ZoneId.of("UTC"), result.get("zone")); + } + + @Test + public void testPeriodRejectsEmbeddedBytes() { + ObjectNode node = MAPPER.createObjectNode(); + node.putPOJO("period", new byte[] { 1, 2 }); + + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> + MAPPER.convertValue(node, new TypeReference>() { })); + assertInstanceOf(MismatchedInputException.class, e.getCause()); + } + + @Test + public void testZoneOffsetRejectsEmbeddedBytes() { + ObjectNode node = MAPPER.createObjectNode(); + node.putPOJO("offset", new byte[] { 1, 2 }); + + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> + MAPPER.convertValue(node, new TypeReference>() { })); + assertInstanceOf(MismatchedInputException.class, e.getCause()); + } +} diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index c8693d31..c6d1fbe7 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -243,3 +243,13 @@ Seonwoo Jung (@seonwooj0810) * Contributed fix for #76: Missing milliseconds, when serializing Java 8 date-time, if they are zeros (2.23.0) + +Manqing Zhou (@manqingzhou) + * Reported #389: Validate embedded objects (`JsonToken.VALUE_EMBEDDED_OBJECT`) + against expected `java.time` type, instead of returning them as-is + (2.23.0) + +Aditya Bagla (@adityabagla7) + * Contributed fix for #389: Validate embedded objects (`JsonToken.VALUE_EMBEDDED_OBJECT`) + against expected `java.time` type, instead of returning them as-is + (2.23.0) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 559b4889..02ec9155 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -14,6 +14,10 @@ Modules: `JavaTimeFeature.ALWAYS_WRITE_SUBSECOND_DIGITS`) (reported by @rycler) (fix contributed by Seonwoo J) +#389: Validate embedded objects (`JsonToken.VALUE_EMBEDDED_OBJECT`) against + expected `java.time` type, instead of returning them as-is + (reported by @manqingzhou) + (fix contributed by Aditya B) 2.22.3 (21-Sep-2026) 2.22.2 (16-Aug-2026)