我有一个名为游戏的课程:
public class Game {
private String name;
private int id;
private GameFields[] gameFields;
@Expose(deserialize = false)
public ArrayList<Player> players = new ArrayList<>();
public Game() {
}
public Game(String name, int id, GameFields[] gameFields) {
this.name = name;
this.id = id;
this.gameFields = gameFields;
}
}
我想使用 GSON.fromJson 方法为此类创建对象。 但问题是方法返回
Failed to make field 'com.example.Models.Game#name' accessible; either change its visibility or write a custom TypeAdapter for its declaring type
这就是我调用该方法的方式
Gson gson = new Gson();
Game object = null;
try {
object = gson.fromJson("{\"name\":\"test\",\"id\":1}", Game.class);
}catch (JsonParseException e){
System.out.println(e.getMessage());
}
我不知道为什么会发生这种情况,因为在我看到的每个示例中,用户都对其字段使用了私有可见性。 但就我而言,只有当我将字段的可见性更改为公共时,它才有效。
更新
整个堆栈跟踪:
com.google.gson.JsonIOException: Failed making field 'com.example.server.Models.Game#name' accessible; either change its visibility or write a custom TypeAdapter for its declaring type
at [email protected]/com.google.gson.internal.reflect.ReflectionHelper.makeAccessible(ReflectionHelper.java:22)
at [email protected]/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:158)
at [email protected]/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:101)
at [email protected]/com.google.gson.Gson.getAdapter(Gson.java:501)
at [email protected]/com.google.gson.Gson.fromJson(Gson.java:990)
at [email protected]/com.google.gson.Gson.fromJson(Gson.java:956)
at [email protected]/com.google.gson.Gson.fromJson(Gson.java:905)
at [email protected]/com.google.gson.Gson.fromJson(Gson.java:876)
at com.example.server/com.example.server.Server$2.onData(Server.java:55)
at com.example.server/com.example.server.Server$2.onData(Server.java:44)
at [email protected]/com.corundumstudio.socketio.namespace.Namespace.onEvent(Namespace.java:146)
at [email protected]/com.corundumstudio.socketio.handler.PacketListener.onPacket(PacketListener.java:106)
at [email protected]/com.corundumstudio.socketio.handler.InPacketHandler.channelRead0(InPacketHandler.java:92)
at [email protected]/com.corundumstudio.socketio.handler.InPacketHandler.channelRead0(InPacketHandler.java:36)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:294)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at [email protected]/com.corundumstudio.socketio.transport.PollingTransport.onPost(PollingTransport.java:161)
at [email protected]/com.corundumstudio.socketio.transport.PollingTransport.handleMessage(PollingTransport.java:120)
at [email protected]/com.corundumstudio.socketio.transport.PollingTransport.channelRead(PollingTransport.java:97)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at [email protected]/com.corundumstudio.socketio.handler.AuthorizeHandler.channelRead(AuthorizeHandler.java:137)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:316)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private java.lang.String com.example.server.Models.Game.name accessible: module com.example.server does not "opens com.example.server.Models" to module com.google.gson
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:180)
at java.base/java.lang.reflect.Field.setAccessible(Field.java:174)
at [email protected]/com.google.gson.internal.reflect.ReflectionHelper.makeAccessible(ReflectionHelper.java:19)
... 75 more
我通过添加以下行解决了问题:
opens com.example.server.Models to com.google.gson;
到
module-info.java
在 java 升级版本 11 到 17 期间,我在使用 gson 反序列化 java.time.Instant 时遇到了同样的问题,请参阅 gson 文档,了解发生这种情况的原因: https://github.com/google/gson/blob/main/UserGuide.md#gsons-expose
解决方案: 使用 -
new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()
创建 Gson
示例:
Gson gson = new GsonBuilder().setPrettyPrinting()
.excludeFieldsWithoutExposeAnnotation()
.create();
我在使用 gson 反序列化 java.time.LocalDate 时遇到了同样的问题,我认为 gson 文档的这一部分揭示了发生这种情况的原因:
我引用文档:
说明:当某个类型不存在内置适配器并且没有自定义适配器时 适配器已注册,Gson 回退到使用反射来 访问类的字段(包括私有字段)。最有可能的是你 看到此错误是因为您(意外地)依赖于 用于第三方类的基于反射的适配器。那应该是 避免因为你让自己依赖于实现 这些类的详细信息可能随时发生变化。对于JDK 也不可能再使用访问内部字段 从 JDK 17 开始反射,请参阅 JEP 403。如果你想阻止 将来使用第三方类的反射你可以编写 您自己的 ReflectionAccessFilter 或使用预定义的之一, 例如ReflectionAccessFilter.BLOCK_ALL_PLATFORM。
这可能是因为
Gson
可能无法将 Arraylists
从你的类转换为 json 字符串。因此,这就是为什么它推荐类型适配器。类型适配器基本上用于转换 gson 无法转换为 json 的类。在此适配器中,您将描述您的类应如何与 json 字符串相互转换。这是文档
GameFields
。所以,这可能是另一个错误点。
我遇到了类似的问题,涉及更复杂的类,其中包括几个涉及反序列化的对象。通过使用
@Expose
注释显式标记类的哪些字段参与反序列化,解决了该问题。
此外,
@SerializedName
注释用于每个字段,用于字段和 JSON 元素之间的映射。
我将发布在我类似的错误场景中对我来说完美有效的内容。
Gson customGson = new GsonBuilder()
.registerTypeAdapter(LocalDate.class, new LocalDateTypeAdapter())
.create();
String jsonString = customGson.toJson(member);
String responsePojo = customGson.fromJson(memberSearchResponse, MemberSearchResponsePojo.class);
LocalDateTypeAdapter
需要单独定义,这是您的自定义 TypeAdapter,可以按如下方式完成:
import com.google.gson.*;
import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class LocalDateTypeAdapter implements JsonSerializer<LocalDate>, JsonDeserializer<LocalDate> {
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@Override
public JsonElement serialize(final LocalDate date, final Type typeOfSrc,
final JsonSerializationContext context) {
return new JsonPrimitive(date.format(formatter));
}
@Override
public LocalDate deserialize(final JsonElement json, final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
return LocalDate.parse(json.getAsString(), formatter);
}
}
Reference Link-2
的这个解决方案对我有用。
您也可以尝试 module-info.java
文件解决方案方法,但不幸的是我无法使该方法为我工作。