如何在Gson序列化/反序列化中获取XmlEnumValue值?
问题原因
你当前的XsdAnnotation仅处理类字段的命名映射,但Gson默认对枚举的序列化逻辑是直接输出枚举常量的名称(比如AM_09),不会读取@XmlEnumValue注解或枚举类中自定义的value()方法返回值,因此导致序列化结果不符合预期。
解决方案
需要自定义Gson的枚举类型适配器,覆盖默认的枚举序列化/反序列化逻辑,让Gson使用枚举的value()返回值(或@XmlEnumValue注解值)进行转换。
方案1:针对特定枚举的极简适配器
因为你的CBPRCancellationReasonCode已经实现了value()返回目标字符串,且提供了fromValue()方法用于反向解析,直接基于这两个方法写适配器即可:
import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import java.io.IOException; public class CBPRCancellationReasonCodeAdapter extends TypeAdapter<CBPRCancellationReasonCode> { @Override public void write(JsonWriter out, CBPRCancellationReasonCode value) throws IOException { if (value == null) { out.nullValue(); return; } // 序列化时输出枚举的value()返回值 out.value(value.value()); } @Override public CBPRCancellationReasonCode read(JsonReader in) throws IOException { String value = in.nextString(); // 反序列化时调用枚举自带的fromValue方法 return CBPRCancellationReasonCode.fromValue(value); } }
然后在创建Gson实例时注册这个适配器:
Gson gson = new GsonBuilder() .setFieldNamingStrategy(new XsdAnnotation()) .setPrettyPrinting() .registerTypeHierarchyAdapter(XMLGregorianCalendar.class, new XMLGregorianCalendarConverter.Serializer()) .registerTypeHierarchyAdapter(XMLGregorianCalendar.class, new XMLGregorianCalendarConverter.Deserializer()) .registerTypeAdapter(CBPRCancellationReasonCode.class, new CBPRCancellationReasonCodeAdapter()) // 注册枚举适配器 .create();
方案2:通用枚举适配器(支持所有带@XmlEnumValue的枚举)
如果需要处理多个带@XmlEnumValue注解的枚举,可以写一个通用的适配器工厂,自动识别并处理这类枚举:
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapterFactory; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import javax.xml.bind.annotation.XmlEnumValue; import java.io.IOException; import java.lang.reflect.Field; public class EnumXmlAdapterFactory implements TypeAdapterFactory { @Override @SuppressWarnings("unchecked") public <T> TypeAdapter<T> create(com.google.gson.Gson gson, TypeToken<T> type) { Class<T> rawType = (Class<T>) type.getRawType(); if (!rawType.isEnum()) { return null; // 仅处理枚举类型 } return new TypeAdapter<T>() { @Override public void write(JsonWriter out, T value) throws IOException { if (value == null) { out.nullValue(); return; } Enum<?> enumValue = (Enum<?>) value; // 优先读取@XmlEnumValue注解的值 try { Field field = rawType.getField(enumValue.name()); XmlEnumValue annotation = field.getAnnotation(XmlEnumValue.class); if (annotation != null) { out.value(annotation.value()); return; } } catch (NoSuchFieldException ignored) {} // 没有注解则尝试调用value()方法 try { String enumValueStr = (String) rawType.getMethod("value").invoke(value); out.value(enumValueStr); } catch (Exception ignored) { // 兜底使用枚举名称 out.value(enumValue.name()); } } @Override public T read(JsonReader in) throws IOException { String value = in.nextString(); if (value == null) { return null; } // 优先调用枚举的fromValue方法 try { return (T) rawType.getMethod("fromValue", String.class).invoke(null, value); } catch (Exception e) { // 遍历枚举常量匹配注解值或value()返回值 for (T enumConstant : rawType.getEnumConstants()) { Enum<?> enumValue = (Enum<?>) enumConstant; // 匹配@XmlEnumValue try { Field field = rawType.getField(enumValue.name()); XmlEnumValue annotation = field.getAnnotation(XmlEnumValue.class); if (annotation != null && annotation.value().equals(value)) { return enumConstant; } } catch (NoSuchFieldException ignored) {} // 匹配value()返回值 try { String enumValueStr = (String) rawType.getMethod("value").invoke(enumConstant); if (enumValueStr.equals(value)) { return enumConstant; } } catch (Exception ignored) {} // 兜底匹配枚举名称 if (enumValue.name().equals(value)) { return enumConstant; } } throw new IllegalArgumentException("无匹配的枚举常量: " + rawType.getName() + "." + value); } } }; } }
注册方式:
Gson gson = new GsonBuilder() .setFieldNamingStrategy(new XsdAnnotation()) .setPrettyPrinting() .registerTypeHierarchyAdapter(XMLGregorianCalendar.class, new XMLGregorianCalendarConverter.Serializer()) .registerTypeHierarchyAdapter(XMLGregorianCalendar.class, new XMLGregorianCalendarConverter.Deserializer()) .registerTypeAdapterFactory(new EnumXmlAdapterFactory()) // 注册通用枚举适配器工厂 .create();
内容的提问来源于stack exchange,提问作者Uğur Yeşilyurt
相关产品推荐
相关产品推荐

