Somehow below code is failing even after creating a custom type adapter. Its working for other type like string. Any idea how can I resolve the issue. Below is the code:
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;
}
}
And below is the error stacktrace:
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
Java object should be successfully parsed to JSON but it is not working
2
Answers
I’m guessing that you are using Java 17+.
As of Java 17, the module system is enforced and java-xml doesn’t export the internal classes for other modules to use.
See: https://github.com/openjdk/jdk17/blob/74007890bb9a3fa3a65683a3f480e399f2b1a0b6/src/java.xml/share/classes/module-info.java
This is why
XMLGregorianCalendarImpl
‘s fields are not available to theGsonBuilder
.https://github.com/openjdk/jdk17/blob/74007890bb9a3fa3a65683a3f480e399f2b1a0b6/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/datatype/XMLGregorianCalendarImpl.java
I don’t think that
GsonBuilder
can use an object’s getters and setters.So you need to make a proper TypeAdapter should map all the getters and setters in
XMLGregorianCalendar
to an object that can be serialized, something likeLocalDate
.https://github.com/openjdk/jdk17/blob/74007890bb9a3fa3a65683a3f480e399f2b1a0b6/src/java.xml/share/classes/javax/xml/datatype/XMLGregorianCalendar.java
Or you simply switch from
XMLGregorianCalendar
toLocalDate
?The reason why Gson is unable to make fields of that class accessible is a combination of the JDK restricting access to implementation details and Gson not having a built-in adapter for
XMLGregorianCalendar
so it falls back to using reflection.Though it sounds your question is rather why your custom adapter is not called. The answer for this is most likely that (as seen in the exception message) you are not actually serializing an object of type
XMLGregorianCalendar
, but a JDK internal subclass. However,GsonBuilder.registerTypeAdapter
which you are using registers the adapter for that specific class and not for subclasses.To solve this you should use
GsonBuilder.registerTypeHierarchyAdapter
instead.