Swagger自动生成Java客户端DateTimeParseException问题排查
解决Swagger生成Java客户端解析无Z后缀ISO日期的异常问题
这个问题我之前帮同事排查过,本质是Swagger Codegen生成的Java客户端默认的Jackson日期序列化/反序列化配置没有兼容不带Z后缀的ISO 8601格式。下面给你几个循序渐进的解决办法,从根源修复到临时兼容都有:
方案1:重新生成客户端时指定兼容的日期配置(推荐)
如果还能重新生成客户端,直接在生成命令里指定日期库和格式参数,从根源避免问题。用swagger-codegen命令时加上--additional-properties参数:
swagger-codegen generate -i your-swagger-spec.yaml -l java -o ./your-client-dir \ --additional-properties dateLibrary=java8-localdatetime,jacksonDateFormat=yyyy-MM-dd'T'HH:mm:ss.SSS
dateLibrary=java8-localdatetime:让客户端使用Java 8的LocalDateTime替代旧的java.util.Date,更符合现代Java时间API规范jacksonDateFormat:指定兼容不带Z后缀的日期格式,这样生成的客户端会自动用这个格式解析日期
方案2:在现有项目中覆盖Jackson配置(无需重新生成客户端)
如果不想重新生成客户端,可以在你的业务项目里自定义Jackson的ObjectMapper,覆盖客户端默认的解析规则:
如果你用的是Spring Boot项目
创建一个Jackson配置类,全局生效:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @Configuration public class CustomJacksonConfig { // 匹配不带Z的ISO日期格式 private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"); @Bean @Primary public ObjectMapper customObjectMapper() { ObjectMapper mapper = new ObjectMapper(); JavaTimeModule timeModule = new JavaTimeModule(); // 注册自定义的反序列化器,兼容无Z格式 timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_FORMATTER)); // 如果需要序列化时也输出同样格式,加上这个 timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DATE_FORMATTER)); mapper.registerModule(timeModule); // 如果服务端返回的无Z日期实际是UTC时间,别忘了设置时区 mapper.setTimeZone(java.util.TimeZone.getTimeZone("UTC")); return mapper; } }
如果是非Spring项目
手动给Swagger生成的ApiClient设置自定义的ObjectMapper:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; // 初始化ApiClient时配置 ApiClient apiClient = new ApiClient(); ObjectMapper mapper = apiClient.getJSON().getObjectMapper(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"); JavaTimeModule module = new JavaTimeModule(); module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter)); mapper.registerModule(module); mapper.setTimeZone(java.util.TimeZone.getTimeZone("UTC")); // 把配置好的mapper设置回ApiClient apiClient.setJSON(new JSON(mapper));
方案3:兼容旧版java.util.Date的情况
如果生成的客户端用的是java.util.Date而不是Java 8时间类,直接设置Jackson的日期格式即可:
ObjectMapper mapper = new ObjectMapper(); mapper.setDateFormat(new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS")); mapper.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
问题根源补充
Swagger Codegen默认生成的客户端,Jackson的日期解析规则是严格匹配带Z后缀的UTC格式(比如2017-07-18T03:41:57.427Z),而不带Z的ISO格式不在默认解析范围内,所以会抛出反序列化异常。上面的方案都是通过调整Jackson的解析规则,让它兼容这种格式。
内容的提问来源于stack exchange,提问作者Tibberzz
相关产品推荐
相关产品推荐

