ModelMapper映射POJO到Entity后CosmosDB存储ZonedDateTime格式异常求助
解决方案
原因分析
问题核心在于:POJO上的Jackson注解仅作用于该类的序列化/反序列化,但存入CosmosDB时实际序列化的是POJOEntity对象,而目标类POJOEntity的startTs字段缺少对应的序列化配置,导致CosmosDB使用默认逻辑序列化ZonedDateTime对象。
方案1:给POJOEntity字段添加Jackson序列化注解
直接在POJOEntity的startTs字段上补充序列化注解,确保CosmosDB序列化时采用指定格式:
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.datatype.jsr310.deser.ZonedDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.ZonedDateTimeSerializer; import java.time.ZonedDateTime; // POJOEntity类中的对应字段 @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSxxx") @JsonSerialize(using = ZonedDateTimeSerializer.class) @JsonDeserialize(using = ZonedDateTimeDeserializer.class) private ZonedDateTime startTs;
注意:原POJO仅配置了反序列化注解,这里必须补充
@JsonSerialize来指定序列化规则。
方案2:全局配置CosmosDB的Jackson ObjectMapper
如果需要统一处理所有ZonedDateTime类型的序列化/反序列化,可通过Spring Bean定制CosmosDB使用的ObjectMapper:
import com.azure.spring.data.cosmos.core.CosmosTemplate; import com.azure.spring.data.cosmos.core.convert.MappingCosmosConverter; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.ZonedDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.ZonedDateTimeSerializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.time.format.DateTimeFormatter; @Configuration public class CosmosConfig { @Bean public CosmosTemplate cosmosTemplate(CosmosClient cosmosClient, CosmosDatabase cosmosDatabase) { CosmosTemplate template = new CosmosTemplate(cosmosClient, cosmosDatabase.getId()); MappingCosmosConverter converter = (MappingCosmosConverter) template.getConverter(); ObjectMapper objectMapper = converter.getObjectMapper(); // 注册Java8时间模块,自定义ZonedDateTime的序列化/反序列化规则 JavaTimeModule javaTimeModule = new JavaTimeModule(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSxxx"); javaTimeModule.addSerializer(ZonedDateTime.class, new ZonedDateTimeSerializer(formatter)); javaTimeModule.addDeserializer(ZonedDateTime.class, new ZonedDateTimeDeserializer(formatter)); objectMapper.registerModule(javaTimeModule); return template; } }
若使用
spring-cloud-azure-starter-cosmos,也可通过Jackson2ObjectMapperBuilderCustomizer实现全局配置:@Bean public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() { return builder -> { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSxxx"); builder.serializerByType(ZonedDateTime.class, new ZonedDateTimeSerializer(formatter)); builder.deserializerByType(ZonedDateTime.class, new ZonedDateTimeDeserializer(formatter)); }; }
方案3:通过ModelMapper转换为字符串类型(备选)
如果允许POJOEntity的startTs字段为String类型,可在ModelMapper中添加转换器,直接将ZonedDateTime格式化为目标字符串:
import org.modelmapper.Converter; import org.modelmapper.ModelMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; @Configuration public class ModelMapperConfig { @Bean public ModelMapper modelMapper() { ModelMapper modelMapper = new ModelMapper(); // 添加ZonedDateTime转String的转换器 Converter<ZonedDateTime, String> dateToStringConverter = context -> { if (context.getSource() == null) { return null; } return context.getSource().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSxxx")); }; modelMapper.addConverter(dateToStringConverter); return modelMapper; } }
此方案需将POJOEntity的
startTs字段类型改为String,适合不需要对该字段做后续时间运算的场景。
内容的提问来源于stack exchange,提问作者sai23
相关产品推荐
相关产品推荐

