第三方Google模型类DateTime反序列化问题求助
Got it, let's work through this issue where your ObjectMapper can't deserialize Google's DateTime objects from API responses—leading to that annoying IllegalArgumentException when trying to set a String to a DateTime field. Since you can't modify the third-party Google model classes and want to avoid the hassle of writing extensive Mixins, here are three practical, low-friction solutions:
Solution 1: Register a Global DateTime Deserializer with ObjectMapper
This is the most straightforward approach—create a custom deserializer for Google's DateTime and wire it into your ObjectMapper so it works everywhere without needing annotations.
Step 1: Build the Deserializer
This handles both ISO date strings (like "2024-05-20T14:30:00Z") and timestamp values, which Google's API might return:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.google.api.client.util.DateTime; import java.io.IOException; public class GoogleDateTimeDeserializer extends JsonDeserializer<DateTime> { @Override public DateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException { String dateValue = parser.getText(); if (dateValue == null) return null; // Try parsing as timestamp first, fall back to ISO string try { long timestamp = Long.parseLong(dateValue); return new DateTime(timestamp); } catch (NumberFormatException e) { return new DateTime(dateValue); } } }
Step 2: Register It with Your ObjectMapper
If you're creating your own ObjectMapper instance:
ObjectMapper objectMapper = new ObjectMapper(); SimpleModule googleDateTimeModule = new SimpleModule(); googleDateTimeModule.addDeserializer(DateTime.class, new GoogleDateTimeDeserializer()); objectMapper.registerModule(googleDateTimeModule);
For Spring Boot users configuring RestTemplate, replace the default Jackson message converter with your custom one:
@Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); // Create custom Jackson converter with our deserializer MappingJackson2HttpMessageConverter customJacksonConverter = new MappingJackson2HttpMessageConverter(); ObjectMapper objectMapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addDeserializer(DateTime.class, new GoogleDateTimeDeserializer()); objectMapper.registerModule(module); customJacksonConverter.setObjectMapper(objectMapper); // Replace the default Jackson converter with our custom one restTemplate.getMessageConverters().removeIf( conv -> conv instanceof MappingJackson2HttpMessageConverter ); restTemplate.getMessageConverters().add(customJacksonConverter); return restTemplate; }
Solution 2: Minimal Mixin for DateTime Fields
If you don't want a global solution, you can use a stripped-down Mixin that only targets the DateTime fields in Google's models—no need to map every single field.
Step 1: Create a Minimal Mixin for Your Target Model
For example, for the Events class, only define the DateTime fields you need to handle:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.google.api.client.util.DateTime; abstract class EventsDateTimeMixin { @JsonDeserialize(using = GoogleDateTimeDeserializer.class) private DateTime updated; // Add other DateTime fields here (e.g., created, start, end) as needed }
Step 2: Attach the Mixin to ObjectMapper
objectMapper.addMixIn(Events.class, EventsDateTimeMixin.class);
This is way less work than writing a full Mixin for the entire class, and it won't interfere with your dependency injection setup.
Solution 3: Use Google's Own JSON Parser
Since you can access Google's model classes, why not leverage their built-in JSON handling? Google's JsonFactory is designed to work seamlessly with their models, so it'll handle DateTime out of the box.
Here's how to use it with RestTemplate:
import com.google.api.client.json.JsonFactory; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.services.calendar.model.Events; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; // Fetch the raw JSON response as a String ResponseEntity<String> apiResponse = restTemplate.getForEntity(YOUR_GOOGLE_CALENDAR_API_URL, String.class); String jsonBody = apiResponse.getBody(); // Parse directly with Google's JsonFactory JsonFactory googleJsonFactory = JacksonFactory.getDefaultInstance(); Events events = googleJsonFactory.fromString(jsonBody, Events.class);
This is the most "native" solution—no custom deserializers or Mixins required, since Google's tools are already tailored to their own models.
内容的提问来源于stack exchange,提问作者Raúl Garcia

