The Jackson Java Time module provides seamless integration between Jackson JSON processing and Java 8 Date/Time API (java.time package). It enables proper serialization and deserialization of temporal objects like LocalDate, LocalDateTime, ZonedDateTime, etc.
Setup and Configuration
Dependencies
<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.15.0</version> </dependency>
Basic Configuration
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.databind.SerializationFeature;
public class JacksonTimeConfig {
public static ObjectMapper createObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
// Register JavaTimeModule
mapper.registerModule(new JavaTimeModule());
// Configure serialization options
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.disable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS);
return mapper;
}
// Alternative configuration with custom settings
public static ObjectMapper createCustomObjectMapper() {
return new ObjectMapper()
.registerModule(new JavaTimeModule())
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
.configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false)
.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
}
}
Basic Serialization and Deserialization
Example 1: Basic Java Time Object Handling
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.time.*;
import java.util.Map;
public class BasicTimeSerialization {
private static final ObjectMapper mapper = JacksonTimeConfig.createObjectMapper();
static class Event {
public String name;
public LocalDate date;
public LocalDateTime dateTime;
public ZonedDateTime zonedDateTime;
public Instant instant;
public Event() {}
public Event(String name, LocalDate date, LocalDateTime dateTime,
ZonedDateTime zonedDateTime, Instant instant) {
this.name = name;
this.date = date;
this.dateTime = dateTime;
this.zonedDateTime = zonedDateTime;
this.instant = instant;
}
}
public static void main(String[] args) throws Exception {
// Create sample data
Event event = new Event(
"Conference",
LocalDate.of(2024, 6, 15),
LocalDateTime.of(2024, 6, 15, 9, 30, 0),
ZonedDateTime.of(2024, 6, 15, 9, 30, 0, 0, ZoneId.of("America/New_York")),
Instant.now()
);
// Serialize to JSON
String json = mapper.writeValueAsString(event);
System.out.println("Serialized JSON:");
System.out.println(json);
// Deserialize back to object
Event deserializedEvent = mapper.readValue(json, Event.class);
System.out.println("\nDeserialized Event:");
System.out.println("Name: " + deserializedEvent.name);
System.out.println("Date: " + deserializedEvent.date);
System.out.println("DateTime: " + deserializedEvent.dateTime);
System.out.println("ZonedDateTime: " + deserializedEvent.zonedDateTime);
System.out.println("Instant: " + deserializedEvent.instant);
// Working with maps containing time objects
Map<String, Object> timeMap = Map.of(
"localDate", LocalDate.now(),
"localDateTime", LocalDateTime.now(),
"zonedDateTime", ZonedDateTime.now(),
"instant", Instant.now(),
"duration", Duration.ofHours(2).plusMinutes(30)
);
String mapJson = mapper.writeValueAsString(timeMap);
System.out.println("\nMap with time objects:");
System.out.println(mapJson);
}
}
Example 2: Custom Date/Time Formats
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
public class CustomFormatSerialization {
static class FormattedEvent {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
public LocalDate eventDate;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
public LocalDateTime eventDateTime;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")
public ZonedDateTime eventZonedDateTime;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss")
public LocalTime eventTime;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "MMM dd, yyyy")
public LocalDate formattedDate;
public FormattedEvent() {}
public FormattedEvent(LocalDate eventDate, LocalDateTime eventDateTime,
ZonedDateTime eventZonedDateTime, LocalTime eventTime) {
this.eventDate = eventDate;
this.eventDateTime = eventDateTime;
this.eventZonedDateTime = eventZonedDateTime;
this.eventTime = eventTime;
this.formattedDate = eventDate;
}
}
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
FormattedEvent event = new FormattedEvent(
LocalDate.of(2024, 12, 25),
LocalDateTime.of(2024, 12, 25, 18, 30, 0),
ZonedDateTime.of(2024, 12, 25, 18, 30, 0, 0, ZoneId.of("Europe/Paris")),
LocalTime.of(18, 30, 0)
);
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(event);
System.out.println("Formatted JSON:");
System.out.println(json);
// Custom mapper with global format
ObjectMapper customMapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.setDateFormat(new java.text.SimpleDateFormat("yyyy/MM/dd HH:mm:ss"))
.disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// Using DateTimeFormatter for parsing
String dateStr = "{\"eventDate\": \"2024-07-04\"}";
FormattedEvent parsedEvent = mapper.readValue(dateStr, FormattedEvent.class);
System.out.println("\nParsed date: " + parsedEvent.eventDate);
}
}
Advanced Configuration and Customization
Example 3: Custom Serializers and Deserializers
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.io.IOException;
import java.time.*;
import java.time.format.DateTimeFormatter;
public class CustomTimeSerializers {
// Custom LocalDate serializer
static class CustomLocalDateSerializer extends JsonSerializer<LocalDate> {
private static final DateTimeFormatter FORMATTER =
DateTimeFormatter.ofPattern("dd.MM.yyyy");
@Override
public void serialize(LocalDate value, JsonGenerator gen,
SerializerProvider provider) throws IOException {
gen.writeString(value.format(FORMATTER));
}
}
// Custom LocalDate deserializer
static class CustomLocalDateDeserializer extends JsonDeserializer<LocalDate> {
private static final DateTimeFormatter FORMATTER =
DateTimeFormatter.ofPattern("dd.MM.yyyy");
@Override
public LocalDate deserialize(JsonParser p, DeserializationContext ctx)
throws IOException {
return LocalDate.parse(p.getValueAsString(), FORMATTER);
}
}
// Custom Duration serializer (human readable)
static class HumanReadableDurationSerializer extends JsonSerializer<Duration> {
@Override
public void serialize(Duration value, JsonGenerator gen,
SerializerProvider provider) throws IOException {
long hours = value.toHours();
long minutes = value.toMinutesPart();
long seconds = value.toSecondsPart();
if (hours > 0) {
gen.writeString(String.format("%dh %dm %ds", hours, minutes, seconds));
} else if (minutes > 0) {
gen.writeString(String.format("%dm %ds", minutes, seconds));
} else {
gen.writeString(String.format("%ds", seconds));
}
}
}
static class CustomTimeEntity {
@JsonSerialize(using = CustomLocalDateSerializer.class)
@JsonDeserialize(using = CustomLocalDateDeserializer.class)
public LocalDate customDate;
@JsonSerialize(using = HumanReadableDurationSerializer.class)
public Duration duration;
public CustomTimeEntity() {}
public CustomTimeEntity(LocalDate customDate, Duration duration) {
this.customDate = customDate;
this.duration = duration;
}
}
public static ObjectMapper createCustomMapper() {
SimpleModule customModule = new SimpleModule();
customModule.addSerializer(LocalDate.class, new CustomLocalDateSerializer());
customModule.addDeserializer(LocalDate.class, new CustomLocalDateDeserializer());
customModule.addSerializer(Duration.class, new HumanReadableDurationSerializer());
return new ObjectMapper()
.registerModule(new JavaTimeModule())
.registerModule(customModule)
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
public static void main(String[] args) throws Exception {
ObjectMapper mapper = createCustomMapper();
CustomTimeEntity entity = new CustomTimeEntity(
LocalDate.of(2024, 3, 15),
Duration.ofHours(2).plusMinutes(45).plusSeconds(30)
);
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(entity);
System.out.println("Custom formatted JSON:");
System.out.println(json);
// Test deserialization
String inputJson = "{\"customDate\":\"15.03.2024\",\"duration\":\"2h 45m 30s\"}";
CustomTimeEntity deserialized = mapper.readValue(inputJson, CustomTimeEntity.class);
System.out.println("\nDeserialized entity:");
System.out.println("Date: " + deserialized.customDate);
System.out.println("Duration: " + deserialized.duration);
}
}
Working with Different Time Types
Example 4: Comprehensive Time Type Handling
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.*;
import java.util.*;
public class ComprehensiveTimeTypes {
static class TimeContainer {
// Basic types
public LocalDate localDate;
public LocalTime localTime;
public LocalDateTime localDateTime;
public ZonedDateTime zonedDateTime;
public OffsetDateTime offsetDateTime;
public Instant instant;
// Duration and Period
public Duration duration;
public Period period;
// Year-based types
public Year year;
public YearMonth yearMonth;
public MonthDay monthDay;
// Zone information
public ZoneId zoneId;
public ZoneOffset zoneOffset;
// Collections of time objects
public List<LocalDate> dates;
public Set<LocalDateTime> dateTimes;
public Map<String, Instant> instantMap;
public TimeContainer() {}
}
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.enable(SerializationFeature.INDENT_OUTPUT);
TimeContainer container = new TimeContainer();
// Set basic types
container.localDate = LocalDate.of(2024, 6, 15);
container.localTime = LocalTime.of(14, 30, 45);
container.localDateTime = LocalDateTime.of(2024, 6, 15, 14, 30, 45);
container.zonedDateTime = ZonedDateTime.of(
LocalDateTime.of(2024, 6, 15, 14, 30, 45),
ZoneId.of("America/New_York")
);
container.offsetDateTime = OffsetDateTime.of(
LocalDateTime.of(2024, 6, 15, 14, 30, 45),
ZoneOffset.ofHours(-5)
);
container.instant = Instant.now();
// Set duration and period
container.duration = Duration.ofHours(2).plusMinutes(30);
container.period = Period.of(1, 6, 15); // 1 year, 6 months, 15 days
// Set year-based types
container.year = Year.of(2024);
container.yearMonth = YearMonth.of(2024, 6);
container.monthDay = MonthDay.of(6, 15);
// Set zone information
container.zoneId = ZoneId.of("Europe/Paris");
container.zoneOffset = ZoneOffset.ofHours(2);
// Set collections
container.dates = Arrays.asList(
LocalDate.of(2024, 1, 1),
LocalDate.of(2024, 6, 15),
LocalDate.of(2024, 12, 31)
);
container.dateTimes = new HashSet<>(Arrays.asList(
LocalDateTime.of(2024, 1, 1, 0, 0),
LocalDateTime.of(2024, 6, 15, 12, 0),
LocalDateTime.of(2024, 12, 31, 23, 59)
));
container.instantMap = Map.of(
"start", Instant.parse("2024-01-01T00:00:00Z"),
"end", Instant.parse("2024-12-31T23:59:59Z")
);
// Serialize
String json = mapper.writeValueAsString(container);
System.out.println("Comprehensive time container JSON:");
System.out.println(json);
// Deserialize
TimeContainer deserialized = mapper.readValue(json, TimeContainer.class);
System.out.println("\nDeserialization successful:");
System.out.println("LocalDate: " + deserialized.localDate);
System.out.println("Duration: " + deserialized.duration);
System.out.println("Year: " + deserialized.year);
System.out.println("Dates list size: " + deserialized.dates.size());
}
}
Real-World Application Examples
Example 5: REST API with Java Time Objects
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.*;
import java.util.*;
// Simulated REST API models
class ApiModels {
static class User {
public String id;
public String username;
public LocalDateTime createdAt;
public LocalDateTime lastLogin;
public ZonedDateTime accountExpires;
public List<LoginSession> sessions;
public User() {}
public User(String id, String username) {
this.id = id;
this.username = username;
this.createdAt = LocalDateTime.now();
this.sessions = new ArrayList<>();
}
}
static class LoginSession {
public String sessionId;
public Instant loginTime;
public Instant logoutTime;
public Duration duration;
public String ipAddress;
public LoginSession() {}
public LoginSession(String sessionId, String ipAddress) {
this.sessionId = sessionId;
this.ipAddress = ipAddress;
this.loginTime = Instant.now();
}
public void endSession() {
this.logoutTime = Instant.now();
this.duration = Duration.between(loginTime, logoutTime);
}
}
static class ApiResponse<T> {
public boolean success;
public String message;
public T data;
public Instant timestamp;
public ApiResponse(boolean success, String message, T data) {
this.success = success;
this.message = message;
this.data = data;
this.timestamp = Instant.now();
}
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(true, "Operation successful", data);
}
public static <T> ApiResponse<T> error(String message) {
return new ApiResponse<>(false, message, null);
}
}
}
public class RestApiExample {
private static final ObjectMapper mapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.enable(SerializationFeature.INDENT_OUTPUT);
public static void main(String[] args) throws Exception {
// Simulate API responses
// Create user with sessions
ApiModels.User user = new ApiModels.User("user123", "john_doe");
user.lastLogin = LocalDateTime.now().minusHours(2);
user.accountExpires = ZonedDateTime.now().plusMonths(6);
ApiModels.LoginSession session1 = new ApiModels.LoginSession("sess1", "192.168.1.100");
session1.endSession();
ApiModels.LoginSession session2 = new ApiModels.LoginSession("sess2", "192.168.1.101");
session2.logoutTime = Instant.now().minusMinutes(30);
session2.duration = Duration.ofMinutes(45);
user.sessions = Arrays.asList(session1, session2);
// Create API response
ApiModels.ApiResponse<ApiModels.User> response =
ApiModels.ApiResponse.success(user);
// Serialize to JSON (as would happen in REST controller)
String jsonResponse = mapper.writeValueAsString(response);
System.out.println("API Response JSON:");
System.out.println(jsonResponse);
// Simulate receiving JSON request
String userUpdateJson = """
{
"username": "john_doe_updated",
"accountExpires": "2024-12-31T23:59:59-05:00[America/New_York]"
}
""";
// Deserialize partial update
Map<String, Object> updateData = mapper.readValue(userUpdateJson, Map.class);
System.out.println("\nReceived update data:");
updateData.forEach((key, value) ->
System.out.println(key + ": " + value + " (" + value.getClass().getSimpleName() + ")"));
}
// Utility method for Spring Boot REST controller
public static String toJson(Object object) {
try {
return mapper.writeValueAsString(object);
} catch (Exception e) {
throw new RuntimeException("Serialization error", e);
}
}
public static <T> T fromJson(String json, Class<T> type) {
try {
return mapper.readValue(json, type);
} catch (Exception e) {
throw new RuntimeException("Deserialization error", e);
}
}
}
Example 6: Configuration and Settings with Time Objects
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.*;
import java.util.concurrent.TimeUnit;
public class ConfigurationExample {
static class AppConfig {
public String appName;
public LocalDate startDate;
public LocalTime maintenanceWindowStart;
public Duration sessionTimeout;
public Period reportRetentionPeriod;
public ZonedDateTime nextMaintenance;
public List<BackupSchedule> backupSchedules;
public Map<DayOfWeek, WorkingHours> workingHours;
public AppConfig() {}
}
static class BackupSchedule {
public String name;
public LocalTime time;
public Duration interval;
public DayOfWeek[] days;
public BackupSchedule() {}
public BackupSchedule(String name, LocalTime time, Duration interval, DayOfWeek[] days) {
this.name = name;
this.time = time;
this.interval = interval;
this.days = days;
}
}
static class WorkingHours {
public LocalTime start;
public LocalTime end;
public ZoneId timezone;
public WorkingHours() {}
public WorkingHours(LocalTime start, LocalTime end, ZoneId timezone) {
this.start = start;
this.end = end;
this.timezone = timezone;
}
}
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.enable(SerializationFeature.INDENT_OUTPUT);
AppConfig config = new AppConfig();
config.appName = "MyApplication";
config.startDate = LocalDate.of(2024, 1, 1);
config.maintenanceWindowStart = LocalTime.of(2, 0); // 2 AM
config.sessionTimeout = Duration.ofMinutes(30);
config.reportRetentionPeriod = Period.ofYears(2);
config.nextMaintenance = ZonedDateTime.of(
LocalDate.now().plusMonths(1).withDayOfMonth(1),
LocalTime.of(2, 0),
ZoneId.systemDefault()
);
// Backup schedules
config.backupSchedules = Arrays.asList(
new BackupSchedule(
"Daily Backup",
LocalTime.of(1, 0),
Duration.ofDays(1),
new DayOfWeek[]{DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY,
DayOfWeek.THURSDAY, DayOfWeek.FRIDAY}
),
new BackupSchedule(
"Weekly Archive",
LocalTime.of(2, 0),
Duration.ofDays(7),
new DayOfWeek[]{DayOfWeek.SUNDAY}
)
);
// Working hours
config.workingHours = Map.of(
DayOfWeek.MONDAY, new WorkingHours(LocalTime.of(9, 0), LocalTime.of(17, 0), ZoneId.of("America/New_York")),
DayOfWeek.TUESDAY, new WorkingHours(LocalTime.of(9, 0), LocalTime.of(17, 0), ZoneId.of("America/New_York")),
DayOfWeek.WEDNESDAY, new WorkingHours(LocalTime.of(9, 0), LocalTime.of(17, 0), ZoneId.of("America/New_York")),
DayOfWeek.THURSDAY, new WorkingHours(LocalTime.of(9, 0), LocalTime.of(17, 0), ZoneId.of("America/New_York")),
DayOfWeek.FRIDAY, new WorkingHours(LocalTime.of(9, 0), LocalTime.of(17, 0), ZoneId.of("America/New_York"))
);
// Serialize configuration
String configJson = mapper.writeValueAsString(config);
System.out.println("Application Configuration:");
System.out.println(configJson);
// Save to file (simulated)
// mapper.writeValue(new File("app-config.json"), config);
// Read from file (simulated)
// AppConfig loadedConfig = mapper.readValue(new File("app-config.json"), AppConfig.class);
// Test with different serialization formats
System.out.println("\n=== Testing different formats ===");
// Timestamp format
ObjectMapper timestampMapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
String timestampJson = timestampMapper.writeValueAsString(config.sessionTimeout);
System.out.println("Duration as timestamp: " + timestampJson);
// ISO format (default)
String isoJson = mapper.writeValueAsString(config.sessionTimeout);
System.out.println("Duration as ISO: " + isoJson);
}
}
Best Practices and Troubleshooting
Example 7: Best Practices and Common Issues
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import java.time.*;
import java.util.*;
public class BestPractices {
private static final ObjectMapper mapper = new ObjectMapper()
.registerModule(new JavaTimeModule());
static class CommonMistakes {
// Missing JavaTimeModule registration
public static void missingModule() {
ObjectMapper badMapper = new ObjectMapper(); // No JavaTimeModule!
try {
String json = badMapper.writeValueAsString(LocalDate.now());
System.out.println("This won't work properly: " + json);
} catch (Exception e) {
System.out.println("Expected error: " + e.getMessage());
}
}
// Timezone issues
public static void timezoneAwareness() {
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
String json = serialize(zdt);
System.out.println("Tokyo time: " + json);
// Deserialization preserves timezone
ZonedDateTime deserialized = deserialize(json, ZonedDateTime.class);
System.out.println("Deserialized zone: " + deserialized.getZone());
}
// Duration precision
public static void durationPrecision() {
Duration preciseDuration = Duration.ofNanos(123456789);
String json = serialize(preciseDuration);
System.out.println("Precise duration: " + json);
Duration deserialized = deserialize(json, Duration.class);
System.out.println("Deserialized: " + deserialized);
System.out.println("Nanos: " + deserialized.toNanos());
}
}
static class ValidationUtils {
public static void validateTimeRange(LocalDateTime start, LocalDateTime end) {
if (start.isAfter(end)) {
throw new IllegalArgumentException("Start time must be before end time");
}
}
public static boolean isInFuture(Instant instant) {
return instant.isAfter(Instant.now());
}
public static boolean isValidDuration(String durationStr) {
try {
Duration.parse(durationStr);
return true;
} catch (Exception e) {
return false;
}
}
}
static class PerformanceTips {
// Reuse ObjectMapper instance
private static final ObjectMapper SHARED_MAPPER = new ObjectMapper()
.registerModule(new JavaTimeModule());
// Cache frequently used patterns
private static final Map<String, ObjectMapper> FORMATTER_CACHE = new HashMap<>();
public static ObjectMapper getMapperForFormat(String dateFormat) {
return FORMATTER_CACHE.computeIfAbsent(dateFormat, fmt -> {
ObjectMapper m = new ObjectMapper();
m.registerModule(new JavaTimeModule());
// Configure with specific format...
return m;
});
}
}
// Utility methods
public static <T> String serialize(T object) {
try {
return mapper.writeValueAsString(object);
} catch (Exception e) {
throw new RuntimeException("Serialization failed", e);
}
}
public static <T> T deserialize(String json, Class<T> type) {
try {
return mapper.readValue(json, type);
} catch (Exception e) {
throw new RuntimeException("Deserialization failed", e);
}
}
public static void main(String[] args) {
System.out.println("=== Common Mistakes ===");
CommonMistakes.missingModule();
CommonMistakes.timezoneAwareness();
CommonMistakes.durationPrecision();
System.out.println("\n=== Validation Examples ===");
try {
ValidationUtils.validateTimeRange(
LocalDateTime.now(),
LocalDateTime.now().minusHours(1)
);
} catch (IllegalArgumentException e) {
System.out.println("Validation caught: " + e.getMessage());
}
System.out.println("\n=== Performance Tips ===");
String json = PerformanceTips.SHARED_MAPPER.writeValueAsString(
Map.of("time", Instant.now())
);
System.out.println("Using shared mapper: " + json);
}
}
Key Features and Benefits
- ISO-8601 Compliance: Default serialization uses standard formats
- Time Zone Awareness: Proper handling of zoned date/time objects
- Precision Preservation: Nanosecond precision for Instants and durations
- Flexible Configuration: Custom formats and serializers
- Collection Support: Works with lists, sets, and maps of time objects
Common Serialization Formats
- LocalDate:
"2024-12-25" - LocalDateTime:
"2024-12-25T14:30:45" - ZonedDateTime:
"2024-12-25T14:30:45-05:00[America/New_York]" - Instant:
"2024-12-25T19:30:45Z" - Duration:
"PT2H30M" - Period:
"P1Y6M15D"
Conclusion
The Jackson Java Time Module is essential for modern Java applications using the Java 8 Date/Time API. Key takeaways:
- Always register
JavaTimeModulewith yourObjectMapper - Configure serialization based on your needs (timestamps vs ISO format)
- Use annotations for custom formatting when needed
- Be timezone-aware when working with zoned types
- Reuse ObjectMapper instances for better performance
By following these patterns and best practices, you can efficiently serialize and deserialize Java time objects in your JSON-based applications.