Java
Deserialization
Date Parsing
JSON
Error Handling

Cannot deserialize value of type java.util.Date from String

Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms

Introduction

This Jackson error appears when the JSON payload contains a date string that does not match the format expected for a java.util.Date field. The fix is usually straightforward once you decide what date shape your API accepts and configure deserialization to match that contract in one place.

Why Jackson Rejects the String

Jackson can deserialize dates in several ways, but it still needs an unambiguous rule. If your payload sends an ISO 8601 string such as 2026-03-07T14:30:00Z while your mapper expects a numeric timestamp or a different pattern, Jackson has no safe conversion path and throws the exception.

Here is a minimal example that fails when the mapper is not configured for the incoming string format:

java
1import com.fasterxml.jackson.databind.ObjectMapper;
2import java.util.Date;
3
4public class Demo {
5    public static class EventDto {
6        public Date eventTime;
7    }
8
9    public static void main(String[] args) throws Exception {
10        String json = "{\"eventTime\":\"2026-03-07T14:30:00Z\"}";
11        ObjectMapper mapper = new ObjectMapper();
12        EventDto dto = mapper.readValue(json, EventDto.class);
13        System.out.println(dto.eventTime);
14    }
15}

The problem is not that java.util.Date cannot represent the timestamp. The problem is that Jackson needs to know exactly how to parse the text before it can create the Date object.

Fix One Field with @JsonFormat

If only one field uses a specific format, annotate that field directly. This keeps the parsing rule close to the DTO and makes the payload contract visible to anyone reading the class.

java
1import com.fasterxml.jackson.annotation.JsonFormat;
2import java.util.Date;
3
4public class EventDto {
5    @JsonFormat(
6        shape = JsonFormat.Shape.STRING,
7        pattern = "yyyy-MM-dd'T'HH:mm:ssX",
8        timezone = "UTC"
9    )
10    public Date eventTime;
11}

Now the same JSON string can be deserialized reliably:

java
1import com.fasterxml.jackson.databind.ObjectMapper;
2
3public class Demo {
4    public static void main(String[] args) throws Exception {
5        String json = "{\"eventTime\":\"2026-03-07T14:30:00Z\"}";
6        ObjectMapper mapper = new ObjectMapper();
7        EventDto dto = mapper.readValue(json, EventDto.class);
8        System.out.println(dto.eventTime);
9    }
10}

This option is a good fit when the field has a stable format and you do not want global mapper settings to affect unrelated DTOs.

Configure One Global Date Contract

If your entire API uses one date format, configure the ObjectMapper once and reuse it everywhere. That prevents drift between controllers, tests, and background jobs.

java
1import com.fasterxml.jackson.databind.ObjectMapper;
2import com.fasterxml.jackson.databind.SerializationFeature;
3import java.text.SimpleDateFormat;
4import java.util.TimeZone;
5
6public class MapperFactory {
7    public static ObjectMapper buildMapper() {
8        ObjectMapper mapper = new ObjectMapper();
9        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX"));
10        mapper.setTimeZone(TimeZone.getTimeZone("UTC"));
11        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
12        return mapper;
13    }
14}

Global configuration is powerful, but it only works well when your service truly has one date contract. If one endpoint accepts MM/dd/yyyy and another accepts ISO 8601, field-level annotations or custom deserializers are usually clearer.

Prefer java.time in New Code

java.util.Date can work, but it does not express timezone intent clearly. For new code, Instant, OffsetDateTime, or LocalDate usually communicate the API contract more precisely. Jackson handles these types well when you register JavaTimeModule.

java
1import com.fasterxml.jackson.databind.ObjectMapper;
2import com.fasterxml.jackson.databind.SerializationFeature;
3import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
4import java.time.OffsetDateTime;
5
6public class ModernDemo {
7    public static class EventDto {
8        public OffsetDateTime eventTime;
9    }
10
11    public static void main(String[] args) throws Exception {
12        String json = "{\"eventTime\":\"2026-03-07T14:30:00Z\"}";
13
14        ObjectMapper mapper = new ObjectMapper();
15        mapper.registerModule(new JavaTimeModule());
16        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
17
18        EventDto dto = mapper.readValue(json, EventDto.class);
19        System.out.println(dto.eventTime);
20    }
21}

This version is usually easier to reason about because the type itself tells you whether an offset is expected.

Handle Legacy Formats with a Custom Deserializer

Sometimes the upstream system sends dates in a format you cannot change. In that case, write a custom deserializer instead of scattering ad hoc parsing logic through service code.

java
1import com.fasterxml.jackson.core.JsonParser;
2import com.fasterxml.jackson.databind.DeserializationContext;
3import com.fasterxml.jackson.databind.JsonDeserializer;
4import java.io.IOException;
5import java.text.ParseException;
6import java.text.SimpleDateFormat;
7import java.util.Date;
8
9public class LegacyDateDeserializer extends JsonDeserializer<Date> {
10    private final SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
11
12    @Override
13    public Date deserialize(JsonParser parser, DeserializationContext context) throws IOException {
14        try {
15            return format.parse(parser.getText());
16        } catch (ParseException ex) {
17            throw new IOException("Invalid legacy date: " + parser.getText(), ex);
18        }
19    }
20}

Attach it to the field like this:

java
1import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
2import java.util.Date;
3
4public class LegacyEventDto {
5    @JsonDeserialize(using = LegacyDateDeserializer.class)
6    public Date eventTime;
7}

That keeps the weird format isolated and makes future cleanup easier.

Common Pitfalls

Using java.util.Date with no explicit format and assuming Jackson will guess correctly is the most common mistake. Another frequent problem is mixing local times and UTC timestamps in the same API, which makes debugging much harder than the original exception. Teams also forget to register JavaTimeModule after moving to OffsetDateTime, which creates a different deserialization failure that looks unrelated at first glance. Finally, tests often cover only a happy-path date string and miss null values, invalid inputs, or timestamps with different offsets.

Summary

  • This error means the incoming date string does not match Jackson's parsing rules for the target field.
  • Use @JsonFormat when one field has a specific string format.
  • Configure the ObjectMapper globally only when your whole API shares one date contract.
  • Prefer java.time types for new code because they express time semantics more clearly.
  • Use a custom deserializer when you must accept a legacy format you cannot change.

Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms