Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么GSON在转换对象时失败';是另一个物体的场吗?_Java_Json_Kotlin_Gson - Fatal编程技术网

Java 为什么GSON在转换对象时失败';是另一个物体的场吗?

Java 为什么GSON在转换对象时失败';是另一个物体的场吗?,java,json,kotlin,gson,Java,Json,Kotlin,Gson,当GSON位于其他对象内部时,它无法将Errorneous正确转换为JSON 但是,当它转换为顶级对象时,效果很好。为什么,以及如何修复它 例如: import com.google.gson.GsonBuilder sealed class Errorneous<R> {} data class Success<R>(val result: R) : Errorneous<R>() data class Fail<R>(val error: S

当GSON位于其他
对象
内部时,它无法将
Errorneous
正确转换为JSON

但是,当它转换为顶级对象时,效果很好。为什么,以及如何修复它

例如:

import com.google.gson.GsonBuilder

sealed class Errorneous<R> {}
data class Success<R>(val result: R) : Errorneous<R>()
data class Fail<R>(val error: String) : Errorneous<R>()

class Container(val value: Errorneous<String>)

fun main() {
  print(GsonBuilder().create().toJson(Container(Fail("some error"))))

  print(GsonBuilder().create().toJson(Fail<String>("some error")))
}
但应该是这样

{"value":{"error":"some error"}}

{"error":"some error"}

我在帖子下面对Gson的行为做了一些评论(简而言之:没有足够的运行时类型信息),所以这是使其工作并使其真正了解类型的唯一代码

private static final Gson Gson=new GsonBuilder()
.registerTypeAdapterFactory(新的TypeAdapterFactory(){
@凌驾
@可空
公共类型适配器创建(最终Gson Gson、最终TypeToken TypeToken){
最终类>successTypeToken=(TypeToken>)TypeToken.getParameterized(Fail.Class,parameterizedType.getActualTypeArguments());
final TypeAdapter>failTypeAdapter=gson.getDelegateAdapter(这是failTypeToken);
最终类型适配器>(){
@凌驾
公共无效写入(最终JsonWriter out,最终错误值)
抛出IOException{
如果(成功的值实例){
最终成功=(成功)价值;
successTypeAdapter.write(out,success);
返回;
}
if(值instanceof Fail){
最终失败=(失败)值;
failTypeAdapter.write(out,fail);
返回;
}
抛出新的AssertionError();//即使null也无法到达此处:它受下面的.nullSafe()保护
}
@凌驾
公共错误读取(最终JsonReader in){
抛出新的UnsupportedOperationException();
}
};
@抑制警告(“未选中”)
最终类型适配器类型适配器=((类型适配器)混凝土类型适配器)
.nullSafe();
返回类型适配器;
}
})
.create();
@AllArgsConstructor
@抑制警告(“未使用”)
私有抽象静态类错误{
}
@AllArgsConstructor
@抑制警告(“未使用”)
私人静态最终课程成功
错误的{
私人最终结果;
}
@AllArgsConstructor
@抑制警告(“未使用”)
私有静态最终类失败
错误的{
私有最终字符串错误;
}
@AllArgsConstructor
@抑制警告(“未使用”)
私有静态类容器{
私人最终错误价值;
}
公共静态void main(最终字符串…参数){
System.out.println(gson.toJson(新容器(新失败(“一些错误”)));
System.out.println(gson.toJson(newfail(“someerror”));
}
如您所见,类型适配器工厂首先解析
Success
Fail
的类型适配器,然后根据
Errorneous
值和
instanceof
()的实际类选择合适的类型适配器

下面是它打印的内容:

{“value”:{“error”:“some error”}
{“错误”:“某些错误”}
反序列化是一个不受支持的操作,因为它必须决定如何反序列化JSON:1)在类型指示符字段上(请参阅GitHub上存储库中Gson extras中的
RuntimeTypeAdapterFactory
;它没有捆绑并作为工件发布);2) 或者通过启发式分析来分析对象的结构(更难实现,并且可能面临不明确的情况)


我不做Kotlin,但是上面的Java代码可以很容易地转换为IntelliJ IDEA中的Kotlin对应代码。

Kotlin中的答案是从

import com.google.gson.GsonBuilder
导入com.google.gson.JsonElement
导入com.google.gson.JsonSerializationContext
导入com.google.gson.JsonSerializer
导入java.lang.reflect.Type
密封类错误{}
数据类成功(val结果:R):Errorneous()
数据类失败(val错误:String):Errorneous()
类容器(
val值:错误
)
主要内容(){
val builder=GsonBuilder()
builder.registerTypeAdapter(
Errorneous::class.java,ErrorneousSerializer()
)
val gson=builder.create()
打印(gson.toJson(容器(失败(“某些错误”)))
打印(gson.toJson(失败(“某些错误”))
}
类ErrorneousSerializer:JsonSerializer{
重写有趣的序列化(
o:Errorneous,type:type,ctx:JsonSerializationContext
):jsonement{
返回ctx.serialize(如有)
}
}

发生这种情况是因为Gson无法解析给定
上的实际子类型,而该子类型在运行时对于
容器
类作用域是未知的。这里您可以做的是从
错误的
类中删除
(这很有意义),或者尝试将
参数传播到
容器
类中,并使用类型标记(虽然它似乎不起作用;Gson bug?)。我猜这种行为的原因是Gson解析实际类型的方式。在序列化
容器
实例时,注册类型适配器工厂可以产生以下输出:
容器
错误
——它不会将最后一个类型解析为失败(因为类型适配器工厂无法访问字段类型,因此它只能执行
.getClass()
在值上),+加上对Gson来说它看起来像
Success
。核心问题是Gson不知道应该使用哪个类。@Mafor感谢您的链接,但我不喜欢这个问题的答案,公认的答案建议使用
List
类型,而不是具体的
List
,这是不好的,最流行的答案是它在Gson>v2.1中是固定的,但我使用的是v2.8,仍然是ha
{"value":{"error":"some error"}}

{"error":"some error"}
import com.google.gson.GsonBuilder
import com.google.gson.JsonElement
import com.google.gson.JsonSerializationContext
import com.google.gson.JsonSerializer
import java.lang.reflect.Type

sealed class Errorneous<R> {}
data class Success<R>(val result: R) : Errorneous<R>()
data class Fail<R>(val error: String) : Errorneous<R>()

class Container(
  val value: Errorneous<String>
 )

fun main() {
  val builder = GsonBuilder()
  builder.registerTypeAdapter(
    Errorneous::class.java, ErrorneousSerializer()
  )
  val gson = builder.create()
  print(gson.toJson(Container(Fail("some error"))))
  print(gson.toJson(Fail<String>("some error")))
}

class ErrorneousSerializer : JsonSerializer<Errorneous<Any>> {
  override fun serialize(
    o: Errorneous<Any>, type: Type, ctx: JsonSerializationContext
  ): JsonElement {
    return ctx.serialize(o as Any)
  }
}