Java 11 ve sonrası için, Gson ile bir nesneyi JSON'a çevirirken eğer içerisinde Exception objesi var ise aşağıdaki gibi bir hata oluşmaktadır :
Exception in thread "main" com.google.gson.JsonIOException: Failed making field 'java.lang.Throwable#detailMessage' accessible; either increase its visibility or write a custom TypeAdapter for its declaring type.
at com.google.gson.internal.reflect.ReflectionHelper.makeAccessible(ReflectionHelper.java:38)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:286)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:130)
at com.google.gson.Gson.getAdapter(Gson.java:556)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:160)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:294)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:130)
at com.google.gson.Gson.getAdapter(Gson.java:556)
at com.google.gson.Gson.toJson(Gson.java:834)
at com.google.gson.Gson.toJson(Gson.java:812)
at com.google.gson.Gson.toJson(Gson.java:759)
at com.google.gson.Gson.toJson(Gson.java:736)
at com.fibiler.test.ThrowableAdapterFactory.main(ThrowableAdapterFactory.java:75)
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private java.lang.String java.lang.Throwable.detailMessage accessible: module java.base does not "opens java.lang" to unnamed module @31dc339b
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)
at java.base/java.lang.reflect.Field.setAccessible(Field.java:172)
at com.google.gson.internal.reflect.ReflectionHelper.makeAccessible(ReflectionHelper.java:35)
... 12 more
Bunu çözmek için aşağıdaki gibi bir adapter sınıfı eklenebilir :
import java.io.IOException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
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;
public class ThrowableAdapterFactory implements TypeAdapterFactory {
private ThrowableAdapterFactory() {
}
public static final ThrowableAdapterFactory INSTANCE = new ThrowableAdapterFactory();
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
// Only handles Throwable and subclasses; let other factories handle any other
// type
if (!Throwable.class.isAssignableFrom(type.getRawType())) {
return null;
}
@SuppressWarnings("unchecked")
TypeAdapter<T> adapter = (TypeAdapter<T>) new TypeAdapter<Throwable>() {
@Override
public Throwable read(JsonReader in) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void write(JsonWriter out, Throwable value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.beginObject();
// Include exception type name to give more context; for example
// NullPointerException might
// not have a message
out.name("type");
out.value(value.getClass().getSimpleName());
out.name("message");
out.value(value.getMessage());
Throwable cause = value.getCause();
if (cause != null) {
out.name("cause");
write(out, cause);
}
Throwable[] suppressedArray = value.getSuppressed();
if (suppressedArray.length > 0) {
out.name("suppressed");
out.beginArray();
for (Throwable suppressed : suppressedArray) {
write(out, suppressed);
}
out.endArray();
}
out.endObject();
}
};
return adapter;
}
}
bu sınıfı aşağıdaki gibi kullanabiliriz :
public static void main(String[] args) {
System.out.println(new Gson().toJson(new ExBean()));
}
static class ExBean {
Throwable throwable = new Exception("Test exception");
}
Bu şekilde test edildiğinde hata alınmayacaktır.
public static void main(String[] args) {
Gson gson=new GsonBuilder()
.registerTypeAdapterFactory(ThrowableAdapterFactory.INSTANCE).create();
System.out.println(gson.toJson(new ExBean()));
}
static class ExBean {
Throwable throwable = new Exception("Test exception");
}
Çıktı :
{"throwable":{"type":"Exception","message":"Test exception"}}
Kaynak :
github.com/google/gson/issues/2352