`

Json常见用法

    博客分类:
  • json
阅读更多

JACKSON处理JSON的一些常见使用

接下来就介绍一些处理json时常见的使用场景,文中的例子都是在1.9版本下运行的。
Jackson的json库提供了3种API:

  • Streaming API : 性能最好
  • Tree Model : 最灵活
  • Data Binding : 最方便

其中最常用到的就是Data Binding了,基本的用法如下

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(foo);
Foo foo = mapper.readValue(json, Foo.class);

ObjectMapper是线程安全的,应该尽量的重用。
需要注意的是,Jackson是基于JavaBean来串行化属性的,如果属性没有GETTER方法,默认是不会输出该属性的。

但是在串行化的时候,经常会有特殊的需求来对输出的结果进行自定义。
比如不输出某几个属性,或者自定义属性的名字,等等。
Jackson提供了非常多的方法来满足我们的自定义需求。

假设有这么一个对象:

class User {
        private long id;
        private String name;
        private String avator240;
        private String avator160;
        private String address;
        public long getId() {
            return id;
        }
        public String getName() {
            return name;
        }
        public String getAvator240() {
            return avator240;
        }
        public String getAvator160() {
            return avator160;
        }
        public String getAddress() {
            return address;
        }
    }

如果不想输出id,最简单的方法,就是给该属性加上注解JsonIgnore:

@JsonIgnore
private long id;

或者

@JsonIgnore
public long getId() {
    return id;
}

因为JsonIgnoretarget可以是CONSTRUCTOR, FIELD, METHOD

如果不想输出多个属性,比如idaddressavator160,除了在每个属性上添加JsonIgnore,也可以直接在类上添加注解JsonIgnoreProperties:

@JsonIgnoreProperties({"id","avator160","address"})
class User {

这里的User类只有5个属性,使用annotation控制忽略哪些属性还是绰绰有余的。
加入有一个类有上百个属性,如果只想输出其中的10来个属性,使用JsonIgnore就显得太繁琐了。
此时就可以使用JSON View或MixIn Annotation了。

先来看一下JSON View,和数据库的view一样,可以为一个对象创建view,输出时只会输出view中定义的那些属性。 特别的,一个对象可以定义任意多个view,同时view也是可以继承的。
先来看看如何使用view来过滤idaddressavator160

public class JsonViewDemo {
    private static class User {
        private long id;
        @JsonView({FilterView.Output.class})
        private String name;
        @JsonView({FilterView.Output.class})
        private String avator240;
        private String avator160;
        private String address;
        public long getId() {
            return id;
        }
        public String getName() {
            return name;
        }
        public String getAvator240() {
            return avator240;
        }
        public String getAvator160() {
            return avator160;
        }
        public String getAddress() {
            return address;
        }
    }

    private static class FilterView {
        static class Output {}
    }

    public static void main(String[] args) throws Exception {
        User user = new User();
        user.id = 1000L;
        user.name = "test name";
        user.avator240 = "240.jpg";
        user.avator160 = "160.jpg";
        user.address = "some address";

        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION, false);
        System.out.println(mapper.writerWithView(FilterView.Output.class).writeValueAsString(user));
    }
}

首先需要定义一个需要输出的属性的View:FilterView.Output,然后在需要输出属性上声明该View,之后使用writerWithView(FilterView.Output.class)来串行化就可以了。
需要注意的是,在这里需要把DEFAULT_VIEW_INCLUSION设置为false,因为默认是会输出没有JsonView注解的属性的。

其实View的作用远不止如此,再来看一个更实用的例子: 假设现有个API接口,需要针对不同的客户端(ios,android)输出不同的属性,通过创建多个View就能轻松完成。

public class JsonApiViewDemo {

    private static class User {
        private long id;

        @JsonView({ApiView.Default.class})
        private String name;

        @JsonView({ApiView.Ios.class})
        private String avator240;

        @JsonView({ApiView.Android.class})
        private String avator160;

        private String address;

        public long getId() {
            return id;
        }
        public String getName() {
            return name;
        }
        public String getAddress() {
            return address;
        }
        public String getAvator240() {
            return avator240;
        }
        public String getAvator160() {
            return avator160;
        }

    }

    private static class ApiView {
        static class Default {}
        static class Ios extends Default {}
        static class Android extends Default {}
    }

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION, false);

        User user = new User();
        user.id = 10000L;
        user.name = "test name";
        user.avator240 = "240.jpg";
        user.avator160 = "160.jpg";
        user.address = "some address";

        String apiViewJson = mapper.writerWithView(ApiView.Default.class).writeValueAsString(user);
        String iosViewJson = mapper.writerWithView(ApiView.Ios.class).writeValueAsString(user);
        String androidViewJson = mapper.writerWithView(ApiView.Android.class).writeValueAsString(user);

        System.out.println(apiViewJson);
        System.out.println(iosViewJson);
        System.out.println(androidViewJson);

    }

}

使用ApiView.Ios只会输出nameavator240
使用ApiView.Android只会输出nameavator160

但是,以上的所有方法都有一个缺点,那就是需要修改源代码,它们都需要在要输出的类上加上annotation。
假设没有那些要串行化的类的源代码,甚至那些类都不符合JavaBean规范,又该怎么办呢? 此时就可以使用MixIn Annotation了,其实和View差不多,也相当于是为要串行化的对象定义了一个View。

public class JsonMixInDemo {
    static class User {
        private long id;
        private String name;
        private String avator240;
        private String avator160;
        private String address;

        public long getId() {
            return id;
        }

        public String getName() {
            return name;
        }

        public String getAddress() {
            return address;
        }

    }

    abstract class MixIn {
        @JsonIgnore abstract int getAddress();

        @JsonIgnore long id;

        @JsonProperty("custom_name") abstract String getName();

        @JsonProperty("avator") String avator240;
    }


    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        User user = new User();
        user.id = 1234567L;
        user.name = "test name";
        user.avator240 = "240.jpg";
        user.avator160 = "160.jpg";
        user.address = "some address";

        mapper.getSerializationConfig().addMixInAnnotations(User.class, MixIn.class);
        String json = mapper.writeValueAsString(user);
        System.out.println(json);

    }
}

将输出

{"custom_name":"test name","avator":"240.jpg"}

其中关键在于MixIn这个类,MixIn也可以定义成接口。
在这里,既可以过滤属性/方法,也可以定义哪些属性/方法会被输出,顺便还可以自定义输出的属性名。
在串行化前只要配置一下

addMixInAnnotations(User.class, MixIn.class)

就可以在完全不修改该类的情况下自定义输出了。

MixIn Annotation应该能满足几乎所有需要对属性进行自定义的情况了,但是MixIn Annotation的配置是静态的,不能在运行时修改。
结合JSON Filter和Mixin就可以实现动态的过滤属性了

public class JsonFilterDemo {

    private static class User {
        private long id;
        private String name;
        private String avator240;
        private String avator160;
        private String address;

        public String getName() {
            return name;
        }
        public String getAddress() {
            return address;
        }
        public String getAvator240() {
            return avator240;
        }
        public String getAvator160() {
            return avator160;
        }
        public long getId() {
            return id;
        }
    }

    @JsonFilter("userFilter")
    private static interface UserFilterMixIn
    {

    }

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        User user = new User();
        user.id = 1000L;
        user.name = "test name";
        user.avator240 = "240.jpg";
        user.avator160 = "160.jpg";
        user.address = "some address";


        FilterProvider idFilterProvider = new SimpleFilterProvider().addFilter("userFilter", SimpleBeanPropertyFilter.filterOutAllExcept(new String[]{"name", "avator240"}));
        mapper.setFilters(idFilterProvider);
        mapper.getSerializationConfig().addMixInAnnotations(User.class, UserFilterMixIn.class);
        String userFilterJson = mapper.writeValueAsString(user);

        System.out.println(userFilterJson);
    }
}

前面介绍了很多自定义输出属性的方法,如果需要在串行化时修改值,要怎么办呢?
只要实现自己的JsonSerializer就可以了,下面这个例子就会输出id的md5值

public class JsonCustomSerializerDemo {
    static class User {
        @JsonSerialize(using = Md5IdSerializer.class)
        private long id;
        private String name;
        private String address;

        public long getId() {
            return id;
        }

        public String getName() {
            return name;
        }

        public String getAddress() {
            return address;
        }

    }

    public static class Md5IdSerializer extends JsonSerializer
   
   
    
     {

        public void serialize(Long value, JsonGenerator generator, SerializerProvider provider)
                throws IOException, JsonProcessingException {
            generator.writeString(md5(value));
        }

        private String md5(Long value) {
            return value + "-md5-mock";
        }

    }

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        User user = new User();
        user.id = 1234567L;
        user.name = "test name";
        user.address = "some address";

        String json = mapper.writeValueAsString(user);
        System.out.println(json);

    }
}
   
   

接下来看一下反串行化,现在很多网站都开放了api接口,支持json格式的返回。
比如在调用了某个api后,需要解析返回的json数据获取信息,这种情况下为json创建一个对应的类是很不方便的。
此时使用Tree Model来解析json就比较方便了,下面这段代码就是用来解析人人网的用户信息的

JsonNode root = mapper.readTree(rerenjson);
JsonNode user = root.get("user");
String id = user.get("id").asText();
String name = user.get("name").asText();
JsonNode avators = user.get("avatar");
if (avators.isArray()) {
    for (Iterator
   
   
    
     it = avators.getElements(); it.hasNext(); ){
        JsonNode avator = it.next();
        if ("tiny".equals(avator.get("type").asText())) {
            String ava = avator.get("url").asText();
            break;
        }
    }
}

   
   

最后列一些使用Jackson的最佳实践:

  • 重用重量级对象: ObjectMapper, JsonFactory
  • 串行化性能(从高到低): OutputStream > Writer > writeValueAsString
  • 反串行化性能(从高到低): byte[] > InputStream > Reader
  • 用更轻量ObjectReader/ObjectWriter替代ObjectMapper
  • 及时关闭JsonParser, JsonGenerator

上面这些tips都摘自https://github.com/FasterXML/jackson-docs/wiki/Presentation:-Jackson-Performance,上面还有更多tips。

分享到:
评论

相关推荐

    JSONModel的使用

    在本文中,我们将深入探讨JSONModel的使用,包括其基本用法、优点、常见问题及解决策略。 首先,让我们了解JSONModel的基本用法。要使用JSONModel,你需要在你的类中继承自JSONModel,并定义相应的属性。这些属性...

    C# NewtonJson使用说明

    在C#开发中,处理JSON数据是常见的任务,而Newtonsoft.Json(也称为Json.NET)是一个广泛使用的库,它提供了强大的JSON序列化和反序列化功能。本文将详细介绍如何使用Newtonsoft.Json进行JSON操作,包括数据结构的...

    json的应用手册

    7. JSON高级用法:如使用JSON Schema验证JSON数据结构,以及如何有效地使用JSON进行大规模数据处理。 手册的版权信息指出,除非经过出版商的书面许可,否则不允许复制、存储或传输手册内容。此外,尽管编辑和作者...

    基于json-lib.jar包 JSONObject-Java常用的四种用法

    本文将深入探讨基于`json-lib.jar`包中的`JSONObject`类的四种常用用法。 1. **创建JSONObject** 创建`JSONObject`最常见的方式是从一个Java对象映射而来。`json-lib.jar`提供了`JsonBeanUtil`工具类,可以将Java...

    json 使用实例

    这种格式在Web服务和客户端之间传输数据时非常常见。 标题“JSON使用实例”暗示我们将探讨如何在实际编程中应用JSON。JSON不仅用于存储数据,还常用于网络请求的响应数据格式,如API调用。以下是一些关于JSON使用的...

    已经实现了:(含源码)VB利用官方api读写JSON数据格式文件简单实例.zip

    在VB(Visual Basic 6)中,处理JSON数据格式文件是一项常见的任务,特别是在与Web服务交互或存储配置信息时。本实例将详细讲解如何利用官方API实现VB对JSON的读写操作,帮助开发者更好地理解这一过程。 首先,JSON...

    java 解析 json

    在Java编程语言中,解析JSON(JavaScript Object Notation)数据是一项常见的任务,因为JSON作为一种轻量级的数据交换格式,广泛用于API交互、存储和传输数据。本篇文章将深入探讨Java中解析JSON的几种主要方法,...

    Linux JSON 常用解析命令总结

    本文主要介绍两种常见的Linux下JSON解析工具:`jsonfilter` 和 `jq`。 #### jsonfilter 工具详解 `jsonfilter` 是一款由OpenWRT自带的工具,其体积小且简单易用,能够满足基本的需求。它基于`json-c`库实现,因此...

    gson和jsonBean解析json案例

    在Java开发中,处理JSON数据是一项常见的任务,而Gson和JsonBean是两个常用的库,用于将Java对象转换为JSON格式以及将JSON字符串反序列化为Java对象。本篇文章将详细探讨这两个库的使用方法,并通过一个具体的案例来...

    JSON基础归纳整理

    10. 把JSON文本转换为JavaScript对象是JSON数据处理的常见用法。可以使用JavaScript内置的eval()函数进行转换,但需要注意安全性问题,因为eval()会执行字符串中的代码。更安全的替代方法是使用JSON.parse()函数,它...

    Json与java对象之间相互转换源码

    本篇文章将详细探讨这个过程,以及如何使用常见的Java JSON库,如Gson和Jackson,进行JSON与Java对象的转换。 首先,让我们了解JSON的基本结构。JSON格式通常包含键值对(key-value pairs)和数组。键值对以冒号...

    Json数据测试

    下面我们将深入探讨JSON的基本结构和常见用法。 1. JSON的基本结构: - 对象(Object):以大括号 `{}` 包围,键值对之间用逗号分隔。键(key)必须是字符串,用双引号包围,值(value)可以是各种数据类型,如...

    json类库,Java解析json必用

    在Java中,处理JSON数据是常见的任务,尤其在开发Web服务、前后端交互等场景中。本篇文章将深入探讨Java中解析和生成JSON的类库,并介绍如何使用它们进行数据转换。 ### JSON的基本结构 JSON基于JavaScript语法,...

    notepad++ json viewer

    标题 "notepad++ json viewer" 描述的是一个用于Notepad++编辑器的插件,它扩展了Notepad++的功能,使用户能够更方便地查看和编辑...对于初次使用者,只需按照README的指示进行操作,就可以轻松掌握这款插件的用法。

    Json安装文件及实例程序

    1. **获取JSON库**:常见的JSON库有jsoncpp、libjson、nlohmann/json等。例如,nlohmann/json是一个C++11实现的轻量级JSON库,具有良好的API和性能。你可以通过Git或源代码包下载它。 2. **构建和安装**:一旦你有...

    java转json测试项目(附带json jar包)

    5. JSON操作:尝试对JSON对象进行一些常见操作,如获取键值、遍历、修改、删除等,并验证操作结果。 6. 序列化与反序列化:将JSON字符串转换回Java对象,检查数据的完整性和一致性。 7. 性能分析:通过JMH(Java ...

    复杂json格式转为对象

    处理复杂的JSON格式并将其转换为Java对象是一项常见的任务,这涉及到JSON库的使用,例如Jackson、Gson或Fastjson等。本资源提供了一个关于如何将复杂JSON转换为Java对象的学习实例,包括源码和可执行的jar包。 一、...

    java遍历JSON树

    在处理Web应用程序中的数据时,JSON(JavaScript Object Notation)是一种非常常见的数据格式。它轻量级且易于读写,因此广泛应用于前后端的数据交互中。对于Java开发者来说,能够熟练地操作JSON数据是必不可少的...

    LUA的JSON框架

    这些测试用例覆盖了各种边界条件和常见用法,是评估框架质量的重要依据。 综上所述,"LUA的JSON框架"是一个用于在LUA环境中方便地处理JSON数据的工具集,它提供了高效、安全且易用的接口,让开发者可以专注于业务...

    LUA的JSON库

    在LUA中,常见的JSON库有`json4lua`、`cjson`等。其中,`json4lua`是一个纯LUA编写的库,不需要额外的C扩展,易于安装和使用。在你提供的文件名`json4lua-master`中,我们可以推测这是一个`json4lua`库的版本。要...

Global site tag (gtag.js) - Google Analytics