Wisdom
  • Welcome
  • core
    • Flyway
    • Bean Validation
    • Lombok
    • Webclient
      • Generic Webclient Api
      • SSL Certificate
    • Application Event Publisher
    • REST API's Design
      • Http Methods and Status Codes
      • Resource Naming and URL Structure
      • Request / Response Design
      • Versioning Strategies
      • Filtering and Searching In API
    • Spring Boot Mail Integration
      • Sendgrid
    • Template Engines
      • Java Template Engine [JTE]
  • security
    • Complete Guide to URL Matchers in Spring Security: Types, Examples, Pros, Cons, and Best Use Cases
    • Passwordless Login With Spring Security 6
      • Spring Security OneTimeToken
        • One Time Token with default configuration
        • One Time Token with custom configuration
        • One Time Token With Jwt
  • others
    • How to Integrate WhatsApp for Sending Messages in Your Application
  • java
    • Interview Questions
      • Constructor
      • Serialization
      • Abstract Class
    • GSON
      • Type Token
      • Joda Datetime Custom Serializer and Deserializer
  • Nginx
    • Core Concepts and Basics
    • Deep Dive on NGINX Configuration Blocks
    • Deep Dive on NGINX Directives
    • Deep Dive into Nginx Variables
    • Nginx as a Reverse Proxy and Load Balancer
    • Security Hardening in NGINX
    • Performance Optimization & Tuning in NGINX
    • Dynamic DNS Resolution in Nginx
    • Advanced Configuration & Use Cases in NGINX
    • Streaming & Media Delivery in NGINX
    • Final Configuration
  • Angular
    • How to Open a PDF or an Image in Angular Without Dependencies
    • Displaying Colored Logs with Search Highlighting in Angular 6
    • Implementing Auto-Suggestion in Input Field in Angular Template-Driven Forms
    • Creating an Angular Project Using npx Without Installing It Globally
    • Skip SCSS and Test Files in Angular with ng generate
  • Javascript
    • When JavaScript's Set Falls Short for Ensuring Uniqueness in Arrays of Objects
    • Demonstrating a Function to Get the Last N Months in JavaScript
    • How to Convert Numbers to Words in the Indian Numbering System Using JavaScript
    • Sorting Based on Multiple Criteria
  • TYPESCRIPT
    • Using Omit in TypeScript
Powered by GitBook
On this page
  • Create the DateTime Type Adapter
  • With Multiple Format Support
  • Usage Examples
  • Testing Different Scenarios
  • Configuration with Spring Boot
  • Key Features of this Implementation:
  1. java
  2. GSON

Joda Datetime Custom Serializer and Deserializer

By Taking help of Custom Type Adapters we can create a comprehensive custom serializers and deserializers for Joda DateTime with Gson. This will handle both serialization (DateTime to JSON) and deserialization (JSON to DateTime) with proper error handling and format control.

Create the DateTime Type Adapter

import com.google.gson.*;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;

import java.lang.reflect.Type;

public class JodaDateTimeAdapter implements JsonSerializer<DateTime>, JsonDeserializer<DateTime> {
    private final DateTimeFormatter formatter;
    
    public JodaDateTimeAdapter() {
        // Using ISO format as default
        this.formatter = ISODateTimeFormat.dateTime();
    }
    
    public JodaDateTimeAdapter(DateTimeFormatter formatter) {
        this.formatter = formatter;
    }

    @Override
    public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
        try {
            return new JsonPrimitive(formatter.print(src));
        } catch (Exception e) {
            throw new JsonParseException("Error serializing DateTime", e);
        }
    }

    @Override
    public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 
            throws JsonParseException {
        try {
            String dateTimeStr = json.getAsString();
            return formatter.parseDateTime(dateTimeStr);
        } catch (IllegalArgumentException e) {
            throw new JsonParseException("Error parsing DateTime", e);
        }
    }
}

With Multiple Format Support

import com.google.gson.*;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;
import org.joda.time.format.ISODateTimeFormat;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

public class AdvancedJodaDateTimeAdapter implements JsonSerializer<DateTime>, JsonDeserializer<DateTime> {
    private final List<DateTimeFormatter> formatters;
    private final DateTimeFormatter primaryFormatter;

    public AdvancedJodaDateTimeAdapter() {
        this.formatters = new ArrayList<>();
        
        // Primary formatter for serialization
        this.primaryFormatter = ISODateTimeFormat.dateTime();
        
        // Add multiple formats for deserialization attempts
        formatters.add(ISODateTimeFormat.dateTime());
        formatters.add(ISODateTimeFormat.dateTimeNoMillis());
        formatters.add(ISODateTimeFormat.basicDateTime());
        formatters.add(ISODateTimeFormat.basicDateTimeNoMillis());
        formatters.add(new DateTimeFormatterBuilder()
            .appendPattern("yyyy-MM-dd HH:mm:ss")
            .toFormatter());
    }

    @Override
    public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
        try {
            return new JsonPrimitive(primaryFormatter.print(src));
        } catch (Exception e) {
            throw new JsonParseException("Error serializing DateTime: " + e.getMessage(), e);
        }
    }

    @Override
    public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 
            throws JsonParseException {
        String dateTimeStr = json.getAsString();
        
        // Try each formatter in sequence
        for (DateTimeFormatter formatter : formatters) {
            try {
                return formatter.parseDateTime(dateTimeStr);
            } catch (IllegalArgumentException ignored) {
                // Continue to next formatter if this one fails
            }
        }
        
        throw new JsonParseException("Unable to parse DateTime with any of the registered formats: " 
                + dateTimeStr);
    }
}

Usage Examples

public class JodaDateTimeExample {
    
    public static void main(String[] args) {
        // Example class with DateTime field
        class Event {
            private String name;
            private DateTime timestamp;
            
            public Event(String name, DateTime timestamp) {
                this.name = name;
                this.timestamp = timestamp;
            }
            
            // Getters and setters
        }

        // Basic usage
        Gson gson = new GsonBuilder()
            .registerTypeAdapter(DateTime.class, new JodaDateTimeAdapter())
            .create();

        // Advanced usage with multiple format support
        Gson advancedGson = new GsonBuilder()
            .registerTypeAdapter(DateTime.class, new AdvancedJodaDateTimeAdapter())
            .create();

        // Create test data
        Event event = new Event("Meeting", new DateTime());

        // Serialization
        String json = gson.toJson(event);
        System.out.println("Serialized: " + json);

        // Deserialization
        Event deserializedEvent = gson.fromJson(json, Event.class);
        System.out.println("Deserialized timestamp: " + deserializedEvent.timestamp.toString());

        // Test with different date formats
        String[] testDates = {
            "{\"timestamp\": \"2023-04-01T14:30:00.000Z\"}",
            "{\"timestamp\": \"2023-04-01T14:30:00Z\"}",
            "{\"timestamp\": \"2023-04-01 14:30:00\"}"
        };

        for (String testDate : testDates) {
            try {
                Event parsedEvent = advancedGson.fromJson(testDate, Event.class);
                System.out.println("Successfully parsed: " + parsedEvent.timestamp.toString());
            } catch (JsonParseException e) {
                System.err.println("Failed to parse: " + testDate + " Error: " + e.getMessage());
            }
        }
    }
}

Testing Different Scenarios

public class JodaDateTimeAdapterTest {
    private Gson gson;
    private AdvancedJodaDateTimeAdapter adapter;

    @Before
    public void setUp() {
        adapter = new AdvancedJodaDateTimeAdapter();
        gson = new GsonBuilder()
            .registerTypeAdapter(DateTime.class, adapter)
            .create();
    }

    @Test
    public void testSerializeDateTime() {
        DateTime now = new DateTime();
        String json = gson.toJson(now);
        DateTime parsed = gson.fromJson(json, DateTime.class);
        assertEquals(now, parsed);
    }

    @Test
    public void testDeserializeMultipleFormats() {
        // Test cases
        String[] validDateTimes = {
            "2023-04-01T14:30:00.000Z",  // ISO format with milliseconds
            "2023-04-01T14:30:00Z",      // ISO format without milliseconds
            "2023-04-01 14:30:00"        // Simple format
        };

        for (String dateTimeStr : validDateTimes) {
            DateTime parsed = gson.fromJson("\"" + dateTimeStr + "\"", DateTime.class);
            assertNotNull("Failed to parse: " + dateTimeStr, parsed);
        }
    }

    @Test(expected = JsonParseException.class)
    public void testInvalidFormat() {
        gson.fromJson("\"invalid-date-format\"", DateTime.class);
    }
}

Configuration with Spring Boot

We can configure the Gson bean with the custom adapter:

@Configuration
public class GsonConfig {

    @Bean
    public Gson gson() {
        return new GsonBuilder()
            .registerTypeAdapter(DateTime.class, new AdvancedJodaDateTimeAdapter())
            .setPrettyPrinting()
            .create();
    }
}

Key Features of this Implementation:

  1. Multiple Format Support: The advanced adapter can handle various datetime formats.

  2. Error Handling: Proper exception handling with meaningful error messages.

  3. Thread Safety: The implementation is thread-safe.

  4. Flexible Configuration: Can be customized with different formatters.

  5. Null Safety: Handles null values appropriately.

PreviousType TokenNextNginx

Last updated 4 months ago