Grails框架下复杂对象JSON渲染时UUID与枚举序列化问题咨询
通用解决方案
你遇到的是序列化框架没有全局配置特殊类型序列化规则的问题,不需要给每个类单独写模板,全局注册对应类型的序列化器即可全量生效,以下分别给出Jackson和Gson两种常用框架的配置方案:
如果你使用Jackson(Spring等框架默认序列化工具)
1. 自定义对应类型的序列化器
// UUID序列化器:直接输出字符串格式 public class UUIDSerializer extends StdSerializer<UUID> { public UUIDSerializer() { super(UUID.class); } @Override public void serialize(UUID value, JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeString(value.toString()); } } // 枚举序列化器:直接输出枚举的name值 public class EnumSerializer extends StdSerializer<Enum> { public EnumSerializer() { super(Enum.class); } @Override public void serialize(Enum value, JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeString(value.name()); } } // LocalDateTime序列化器:输出毫秒级时间戳,按需替换为你使用的时间类型 public class DateTimeSerializer extends StdSerializer<LocalDateTime> { public DateTimeSerializer() { super(LocalDateTime.class); } @Override public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeNumber(value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); } }
2. 全局注册序列化器
如果是SpringBoot项目,直接添加配置类即可全局生效:
@Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); // 注册自定义序列化器 module.addSerializer(UUID.class, new UUIDSerializer()); module.addSerializer(Enum.class, new EnumSerializer()); module.addSerializer(LocalDateTime.class, new DateTimeSerializer()); mapper.registerModule(module); return mapper; } }
非Spring项目直接将配置好的ObjectMapper作为单例使用即可,不要每次新建实例。
如果你使用Gson
同样全局注册自定义TypeAdapter即可:
Gson globalGson = new GsonBuilder() // UUID序列化 .registerTypeAdapter(UUID.class, new TypeAdapter<UUID>() { @Override public void write(JsonWriter out, UUID value) throws IOException { out.value(value.toString()); } @Override public UUID read(JsonReader in) throws IOException { return UUID.fromString(in.nextString()); } }) // 枚举序列化 .registerTypeAdapter(Enum.class, new TypeAdapter<Enum>() { @Override public void write(JsonWriter out, Enum value) throws IOException { out.value(value.name()); } @Override public Enum read(JsonReader in) throws IOException { // 反序列化逻辑按需实现 return null; } }) // 时间类型序列化 .registerTypeAdapter(LocalDateTime.class, new TypeAdapter<LocalDateTime>() { @Override public void write(JsonWriter out, LocalDateTime value) throws IOException { out.value(value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); } @Override public LocalDateTime read(JsonReader in) throws IOException { return Instant.ofEpochMilli(in.nextLong()).atZone(ZoneId.systemDefault()).toLocalDateTime(); } }) .create();
之前的方案报错原因
- 第一种方案:使用了框架默认的序列化逻辑,没有加载自定义序列化规则,所以还是会拆分UUID和枚举字段
- 第二、三种方案:都做了两次序列化,先把对象转成JSON字符串,再把字符串塞进集合里二次序列化,自然会出现格式错误、引号转义的问题
正确使用方式
直接用配置好的序列化工具把整个响应对象转成JSON字符串输出即可,示例:
// Jackson用法 AppResponse response = AppResponse.success(Map.of("success", true, "data", data)); String json = objectMapper.writeValueAsString(response); render(json); // Gson用法 String json = globalGson.toJson(response); render(json);
内容的提问来源于stack exchange,提问作者Dred
相关产品推荐
相关产品推荐

