You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 07:45:03