Scala中Gson序列化出现Bitmap$0字段的问题咨询与解决
问题解答
1. Bitmap$0字段的来源是什么?
这个字段是Scala编译器混入特质时生成的内部辅助字段。LazyLogging是一个Scala特质,当你的Statistics类继承它时,Scala编译器会在编译阶段生成一些匿名类(比如Bitmap$0这类命名的内部类)来实现特质的逻辑,这些类的实例会作为隐藏字段附加到你的Statistics对象上。Gson默认会序列化对象的所有字段——包括这些编译器自动生成的、你并没有显式定义的字段,所以就出现在了JSON输出里。
简单说:它是Scala实现特质混入机制的产物,和LazyLogging的底层实现有关,并非你代码里定义的业务字段。
2. 如何阻止Gson序列化该字段?
这里有两种可靠的方案,你可以根据自己的场景选择:
方案一:自定义字段排除策略(推荐,无需修改case类)
写一个ExclusionStrategy来过滤掉编译器生成的特殊字段,然后把它添加到Gson的配置中:
// 自定义排除策略:过滤掉带$的编译器生成字段,或者非当前类声明的字段 class ScalaGeneratedFieldExclusion extends ExclusionStrategy { override def shouldSkipField(f: FieldAttributes): Boolean = { // 两种判断方式选一个就行: // 方式1:直接过滤字段名包含$的(Scala编译器生成的字段大多带$) f.getName.contains("$") // 方式2:只保留Statistics类自己声明的字段(更严谨) // !f.getDeclaringClass.equals(classOf[Statistics]) } override def shouldSkipClass(clazz: Class[_]): Boolean = false }
然后更新你的Gson配置:
lazy val GSON: Gson = new GsonBuilder() .setPrettyPrinting() .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE) .disableHtmlEscaping() .addSerializationExclusionStrategy(new ScalaGeneratedFieldExclusion) // 添加这一行 .create()
方案二:使用@Expose注解显式指定要序列化的字段
这种方式需要给Statistics的每个业务字段加上@Expose注解,然后配置Gson只序列化带该注解的字段:
首先修改case类:
import com.google.gson.annotations.Expose case class Statistics( @Expose source: String, @Expose count: Integer, @Expose sum: Double, @Expose average: Double, @Expose median: Double, @Expose maximum: Double, @Expose minimum: Double ) extends LazyLogging { def toJson: JsonElement = Config.GSON.toJsonTree(this) // ... 其他代码 }
然后更新Gson配置:
lazy val GSON: Gson = new GsonBuilder() .setPrettyPrinting() .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE) .disableHtmlEscaping() .excludeFieldsWithoutExposeAnnotation() // 添加这一行 .create()
为什么你之前的排除策略没生效?
大概率是你之前的策略只针对LazyLogging的类进行排除,但Bitmap$0是附加在Statistics实例上的字段,并非LazyLogging类本身的字段,所以没匹配到。上面两种方案都是直接针对字段本身进行过滤,能准确命中这类编译器生成的隐藏字段。
内容的提问来源于stack exchange,提问作者Carsten
相关产品推荐
相关产品推荐

