Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >如何让jackson与kotlin友好相处

如何让jackson与kotlin友好相处

原创
作者头像
王沛文
修改于 2018-12-14 10:30:37
修改于 2018-12-14 10:30:37
6.7K0
举报
文章被收录于专栏:王沛文的专栏王沛文的专栏

jackson是个常用的java json库,功能很强大。

kotlin中有一个很好的特性叫data classlombok@Data很类似,会自动帮类生成getter/setter/hashCode/equal/toString。

语法也很简洁

代码语言:txt
AI代码解释
复制
data class Foo(val bar:String, val fuck:Int)

但是当我们要同时使用data class和jackson的时候问题就来了。

问题一、构造

直接对上面Foo类进行反序列化时

代码语言:txt
AI代码解释
复制
ObjectMapper().readValue("""{"bar":"a","fuck":1}""", Foo::class.java)

会出现类似异常

代码语言:txt
AI代码解释
复制
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of test.Foo: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
 at [Source: {"bar":"a","fuck":1}; line: 1, column: 2]
	at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:270)
	at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1469)
	at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1012)
	...

其实看原因很简单,没有默认构造方法或JsonCreator的方法。

问题二、命名

当我们想对字段自定义json key的时候,通常会使用@JsonProperty来指定field name。就像下面这样

代码语言:txt
AI代码解释
复制
data class Foo(val bar:String, @JsonProperty("a") val fuck:Int)

但是会发现注解好像一点作用都没有

问题三、自定义序列化

而当我们相对某些字段采用特殊序列化方法的时候,会用@JsonSerialize/@JsonDeserialize

代码语言:txt
AI代码解释
复制
data class Foo(val bar:String, @JsonSerialize(using = XXX::class) val fuck:Int)

但是也会发现注解好像一点作用都没有

问题探究

这时候我们来面向google编程,通常会有以下几种方案

  • https://github.com/FasterXML/jackson-module-kotlin 使用jackson的kotlin module,让jackson能够识别kotlin的类型信息
  • 使用Mixin给每个类指定构造方法
  • 给data class增加默认构造函数,方法通常是kotlin-noarg插件或给每个字段设置默认值
  • 使用@get:JsonSerialize @set/get:JsonProperty之类的特殊注解

其实用jackson官方的kotlin模块是最简单有效的方法,但是对于我们目前遇到的场景有一个非常致命的问题,那就是我们会使用proguard来混淆kotlin代码。一般来说是没有问题的,但是jackson kotlin module会从kotlin编译器给每个类添加的@Metadata注解获取反射信息,而这个注解内的内容proguard混淆时不会处理。最终会导致混淆后的代码经常出现各种ClassNotFoundException。所以我们目前的场景不能使用这种方案。

最后还是只能使用基于jvm的基础方法。

kotlin的类声明结构

虽然kotlin号称对java 100%兼容,但是语法上由于多了很多东西,所以实际兼容的时候还会有很多技巧在其中,下面的样例代码其实就很好的解释了为什么平时在Java中的注解对kotlin一点用处都没有

代码语言:txt
AI代码解释
复制
@AnnotationClass
data class Foo @AnnotationConstructorMethod constructor(
    @AnnotationConstructorParameter
	val field : String
) {
    @AnnotationMethod fun method1(@AnnotationParam param:Int) {}
}

像是@JsonCreator这种需要在构造函数等方法上使用的注解,需要在类名后增加constructor关键字来使用。

而对类构造参数直接添加的注解实际上是被当成构造函数参数的注解对待的,所以这时候并不起真正的作用。而我们可以通过kotlin的use-site target特性来给具体字段的不同场景增加注解。

代码语言:txt
AI代码解释
复制
class Example(@field:Ann val foo,    // annotate Java field
              @get:Ann val bar,      // annotate Java getter
              @param:Ann val quux)   // annotate Java constructor parameter

就像这样在普通的注解前根据需要增加限定范围。所以当了解到这里的之后我们就知道,并不是jackson和kotlin不兼容,只是我们使用的姿势不对。

当我们能正确使用kotlin的注解之后,不管是jackson还是别的库,很多问题也就迎刃而解了。

具体详细注解文档可以参见官方文档

最后给个例子

Java类如下

代码语言:txt
AI代码解释
复制
@AnnotationClass
public class Demo {
    @AnnotationField
    private String field;

    @AnnotationGetter
    public String getField() {
        return field;
    }

    @AnnotationSetter
    public void setField(@AnnotationConstructorParam String field) {
        this.field = field;
    }

    @AnnotationConstructor
    public Demo(@AnnotationConstructorParam String field) {
        this.field = field;
    }

    @AnnotationConstructor
    public Demo(@AnnotationConstructorParam String field, @AnnotationConstructorParam String field2) {
        this.field = field;
        this.field2 = field2;
    }

    @AnnotationField
    private String field2 = "1";

    @AnnotationGetter
    public String getField2() {
        return field2;
    }

    @AnnotationSetter
    public void setField2(@AnnotationSetterParam String field2) {
        this.field2 = field2;
    }
}

可以转化成如下kotlin类,当然并不是只有这一种方式。

代码语言:txt
AI代码解释
复制
@AnnotationClass
data class Demo @AnnotationConstructor constructor(
        @field:AnnotationField
        @get:AnnotationGetter
        @set:AnnotationSetter
        @AnnotationConstructorParam
        var field: String? = null
) {
    @AnnotationField
    @get:AnnotationGetter
    @set:AnnotationSetter
    var field2: String = "1"

    @AnnotationConstructor
    constructor(@AnnotationConstructorParam field: String, @AnnotationConstructorParam field2: String) : this(field) {
        this.field2 = field2
    }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Jackson 使用
老版本的 Jackson 使用的包名为 org.codehaus.jackson,而新版本使用的是com.fasterxml.jackson。
acc8226
2022/05/17
1.9K0
Jackson用法详解
Jackson 是当前用的比较广泛的,用来序列化和反序列化 json 的 Java 的开源框架。Jackson 社区相对比较活跃,更新速度也比较快, 从 Github 中的统计来看,Jackson 是最流行的 json 解析器之一 。 Spring MVC 的默认 json 解析器便是 Jackson。 Jackson 优点很多。 Jackson 所依赖的 jar 包较少 ,简单易用。与其他 Java 的 json 的框架 Gson 等相比, Jackson 解析大的 json 文件速度比较快;Jackson 运行时占用内存比较低,性能比较好;Jackson 有灵活的 API,可以很容易进行扩展和定制。
三分恶
2020/07/16
15.6K0
jackson序列化和反序列化中的注解和扩展点大全【收藏】
通过在属性、getter 方法或类级别上使用 @JsonSerialize 注解,可以指定要使用的序列化器。
公众号:码到三十五
2024/03/19
3.6K0
jackson error 含义log
1. 反序列化失败,类型不匹配 Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserial ize instance of java.lang.String out of START_OBJECT token at [Source: org.apache.http.conn.EofSensorInputStream@51796217; line: 1, column : 274] (through ref
Ryan-Miao
2018/03/13
1.2K0
Jackson反序列化不可变类
如下ImmutableUser类属性都被final修饰,只有全参构造器,没有setter方法,它的实例一经创建就不可变。如何使用Jackson反序列化它呢?
科技新语
2024/11/13
1270
Jackson反序列化不可变类
jackson学习之八:常用方法注解
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 系列文章汇总 jackson学习之一:基本信息 jackson学习之二:jackson-core jackson学习之三:常用API操作 jackson学习之四:WRAP_ROOT_VALUE(root对象) jackson学习之五:JsonInclude注解 jackson学习之六:常用类注解 jackson学习之七:常用Field注解 jackson学习
程序员欣宸
2022/05/06
3640
jackson学习之八:常用方法注解
用了几年的 Fastjson,最终替换成了 Jackson!
> 公众号:[Java小咖秀](https://t.1yb.co/jwkk),网站:[javaxks.com](https://www.javaxks.com)
Java小咖秀
2021/05/06
2.4K0
除了FastJson,你也应该了解一下Jackson(二)
上一篇文章介绍了Jackson中的映射器ObjectMapper,以及如何使用它来实现Json与Java对象之间的序列化和反序列化,最后介绍了Jackson中一些序列化/反序列化的高级特性。而本文将会介绍Jackson中的一些常用的(序列化/反序列化)注解,并且通过示例来演示如何使用这些注解,从而来提高我们在处理Json上的工作效率。
东溪陈姓少年
2020/08/06
1.7K0
jackson学习之七:常用Field注解
最后要介绍的是JsonRawValue,使用该注解的字段或者方法,都会被序列化,但是序列化结果是原始值,例如字符串是不带双引号的:
程序员欣宸
2022/05/06
7380
jackson学习之七:常用Field注解
lombok1.16.20序列化bug分析
记录下使用 lombok遇到的反序列问题,一开始在 lombok1.16.18中并没有发现,然后应用中没有指定lombok全局版本,引入的其他二方包将lombok版本提升到了 1.16.20,然后报错。因为这个问题需要允许时才能发现,很可能会造成线上故障,所以不能等到出现问题时才发现,需要提前知晓。
方丈的寺院
2019/08/05
1.1K0
使用com.fasterxml.jackson.annotation的注解
是类注解,作用是json序列化时将java bean中的一些属性忽略掉,序列化和反序列化都受影响。
用户4396583
2024/08/01
6150
Jackson笔记
Jackson 是当前用的比较广泛的,用来序列化和反序列化 json 的 Java 的开源框架。Jackson 社 区相对比较活跃,更新速度也比较快, 从 Github 中的统计来看,Jackson 是最流行的 json 解析器之一 。 Spring MVC 的默认 json 解析器便是 Jackson。 Jackson 优点很多。 Jackson 所依赖的 jar 包较少 ,简单易用。与其他 Java 的 json 的框架 Gson 等相比, Jackson 解析大的 json 文件速度比较快;Jackson 运行时占用内存比较低,性能比较好;Jackson 有灵活的 API,可以很容易进行扩展和定制。
Remember_Ray
2020/08/05
12.1K0
揭秘 Jackson:Java 对象转 JSON 注解的魔法
嗨,亲爱的同学们!欢迎来到这篇关于 Jackson JSON 解析器中 Java 对象转 JSON 注解的详细解析指南。JSON(JavaScript Object Notation)是一种常用于数据交换的轻量级数据格式,而 Jackson 作为一款优秀的 JSON 解析库,通过注解提供了便捷而强大的方式,让我们能够更自由地掌控 Java 对象与 JSON 之间的转换。在这篇博客中,我将带你一探 Jackson 注解的奇妙世界,通过示例代码揭秘 Java 对象转 JSON 注解的魔法!
繁依Fanyi
2023/11/21
3990
Java中的JSON序列化和反序列化
JSON 起源于 1999 年的 JS 语言规范 ECMA262 的一个子集,后来 2003 年作为一个数据格式ECMA404(404???)发布。 2006 年,作为 rfc4627 发布,这时规范增加到 18 页,去掉没用的部分,十页不到。
鱼找水需要时间
2023/03/23
2.3K0
Java中的JSON序列化和反序列化
Fastxml 简单常用注解学习笔记
更多详见:http://blog.csdn.net/sdyy321/article/details/40298081
干货满满张哈希
2021/04/12
1.2K0
Jackson,最牛掰的 Java JSON 解析器
在当今的编程世界里,JSON 已经成为将信息从客户端传输到服务器端的首选协议,可以好不夸张的说,XML 就是那个被拍死在沙滩上的前浪。
沉默王二
2020/12/15
1.9K0
Java使用Lombok详解
Lombok 是一种 Java 实用工具,可用来帮助开发人员消除 Java 的冗长,尤其是对于简单的 Java 对象(POJO)。它通过注释实现这一目的。通过在开发环境中实现 Lombok,开发人员可以节省构建诸如 hashCode() 和 equals() 、getter / setter 这样的方法以及以往用来分类各种 accessor 和 mutator 的大量时间。
鱼找水需要时间
2023/03/28
7840
返回对象的序列化实现
问题产生: 近来在写代码的时候,有一个返回的vo对象中,有一个属性是带有xml标签的,而页面展示的内容需要将xml标签转换成html标签进行展示,所以实现了一个工具类,然后再返回的地方调用一下工具类,但是随着使用的地方越来越多,每一次改动修改的地方太多,故查询后找了另外的实现逻辑.
用户4235284
2022/12/03
1.1K0
Jackson常用注解详解1 初级2 中级
1 初级 我们从几个简单的使用场景开始:重命名属性,忽略属性,以及修改属性所使用的类型。 注意 下面的例子仅仅显示了成员属性,注解同样也可以用在成员方法(getter/setter)上 ①属性重命名时使用的注解 最常见的使用方式之一就是改变某个成员属性所使用的JSON名称,例如: public class Name { @JsonProperty("firstName") public String _first_name; } 将会生成如下所示的JSON数据结果: { "firstNa
JavaEdge
2018/06/13
1.5K0
实现自定义序列化和反序列化控制的5种方式
你可以编写自定义的序列化器(Serializer)和反序列化器(Deserializer),并将它们应用到特定的类或属性上。通过实现 JsonSerializer 和 JsonDeserializer 接口,你可以完全控制序列化和反序列化过程中的行为,包括如何读取属性、生成 JSON 或者解析 JSON 等。
公众号:码到三十五
2024/03/19
1.8K0
相关推荐
Jackson 使用
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档