Java对象转JSON触发JsonIOException,自定义XMLGregorianCalendar TypeAdapter无效
解决XMLGregorianCalendar转JSON失败问题
问题背景
已为XMLGregorianCalendar接口编写自定义TypeAdapter,但转换包含该类型的Java对象到JSON时仍抛出权限异常,代码及错误栈如下:
问题代码
package com; import java.io.IOException; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; public class DateConversion { public static void main(String[] args) throws DatatypeConfigurationException { XMLGregorianCalendar date = DatatypeFactory.newInstance().newXMLGregorianCalendar(); Request req = new Request(); req.setDate(date); TypeAdapter<XMLGregorianCalendar> adapter = new TypeAdapter<XMLGregorianCalendar>() { @Override public void write(JsonWriter writer, XMLGregorianCalendar value) throws IOException { System.out.println("Inside write"); if(value==null) { writer.nullValue(); return; } writer.value("value"); } @Override public XMLGregorianCalendar read(JsonReader reader) throws IOException { System.out.println("Inside read"); return null; } }; Gson gsonBuilder = (new GsonBuilder()).registerTypeAdapter(XMLGregorianCalendar.class, adapter).serializeNulls().create(); System.out.println(gsonBuilder.toJson(req)); } } class Request { private XMLGregorianCalendar date; public XMLGregorianCalendar getDate() { return date; } public void setDate(XMLGregorianCalendar date) { this.date = date; } }
错误栈
Exception in thread "main" com.google.gson.JsonIOException: Failed making field 'com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl#eon' accessible; either change its visibility or write a custom TypeAdapter for its declaring type
错误原因
XMLGregorianCalendar是接口,通过DatatypeFactory创建的实例实际是其内部实现类XMLGregorianCalendarImpl。使用registerTypeAdapter仅会为精确匹配的XMLGregorianCalendar类型注册适配器,Gson处理实际对象时会尝试反射访问XMLGregorianCalendarImpl的私有字段,触发权限异常。
解决方法
将registerTypeAdapter替换为registerTypeHierarchyAdapter,该方法会为目标类型及其所有子类/实现类注册适配器,确保Gson处理XMLGregorianCalendarImpl时使用自定义适配器而非反射:
修改后的Gson构建代码:
Gson gsonBuilder = new GsonBuilder() .registerTypeHierarchyAdapter(XMLGregorianCalendar.class, adapter) .serializeNulls() .create();
验证效果
修改后运行代码,控制台会输出Inside write,并打印出正确的JSON结果:
{"date":"value"}
内容的提问来源于stack exchange,提问作者A Hybris Dev
相关产品推荐
相关产品推荐

