我不是 Scala 程序员,我只是使用javap 和反射来检查 Scala 编译器生成的内容,并稍微“了解”了一些 Scala 内部结构的工作原理。
由于以下几个原因,它对您不起作用:
// does not work as expected
case class Test(@SerializedName("@@key") `@@key`: String)
从纯 Java 的角度来看:
final Constructor<Test> constructor = Test.class.getDeclaredConstructor(String.class);
System.out.println(constructor);
System.out.println(Arrays.deepToString(constructor.getParameterAnnotations()));
public Test(java.lang.String)
[[@com.google.gson.annotations.SerializedName(alternate=[], value=@@key)]]
不确定为什么 Scala 编译器不将注释直接复制到字段,但 Java 语言不允许使用 @SerializedName 注释对参数进行注释,从而导致编译错误(JVM 也不将其视为失败)。
从 Java 的角度来看:
final Field field = Test.class.getDeclaredField("$at$atkey"); // the real name of the `@@key` element
System.out.println(field);
System.out.println(Arrays.deepToString(field.getDeclaredAnnotations()));
private final java.lang.String Test.$at$atkey []
- Scala 允许将注释移动到字段,这将使您的代码根据 Gson
@SerializedName 的设计方式工作(当然,没有考虑到 Scala):
import scala.annotation.meta.field
...
case class Test(@(SerializedName@field)("@@key") `@@key`: String)
Test(value)
如果由于某些/任何原因您必须使用 Gson 并且不能使用 @SerializedName 注释每个字段,那么您可以实现自定义类型适配器,但恐怕您必须深入了解 Scala 的工作原理.
如果我了解 Scala 的功能,它会使用 @ScalaSignature 注释对每个生成的类进行注释。
注释提供了bytes() 方法,该方法返回一个有效负载,该有效负载最有可能用于检测带注释的类型是否为案例类,以及可能如何声明其成员。
我没有找到这样的解析器/解码器,但如果你找到了,你可以在 Gson 中执行以下操作:
- 注册一个类型适配器工厂,检查它是否可以处理它(基本上,分析
@ScalaSignature注解,我相信);
- 如果可以,则创建一个类型适配器,它知道所有案例类字段,它们的名称可能自己处理
@SerializedName,因为您既不能扩展 Gson ReflectiveTypeAdapterFactory,也不能注入名称重映射策略;
- 考虑到
transient 字段(为了良好)和其他排除策略(为了完整性);
- 读/写每个非排除字段。
工作量太大了,对吧?所以我在这里看到了两个简单的选择:要么像其他人建议的那样使用支持 Scala 的 JSON 工具,要么注释每个具有如此特殊名称的字段。