Jackson数据处理及绑定

Posted fighting-chen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jackson数据处理及绑定相关的知识,希望对你有一定的参考价值。

获取

Maven的

该软件包的功能包含在Java包中com.fasterxml.jackson.databind,可以使用以下Maven依赖项来使用:

< properties >
  ...
  <! -尽可能使用最新版本。- > 
  < jackson .version> 2.9.7 </ jackson .version>
  ...
</ properties >

< dependencies >
  ...
  < 依赖 >
    < groupId > com.fasterxml.jackson.core </ groupId >
    < artifactId > jackson-databind </ artifactId >
    < version > $ {jackson.version} </ version >
  </ dependency >
  ...
</ dependencies >

由于包依赖于jackson-corejackson-annotations包,因此如果不使用Maven,则需要下载这些包; 并且您可能还希望将它们添加为Maven依赖项以确保使用兼容版本。如果是这样,还要添加:

< dependencies >
  ...
  < dependency >
     <! -注意:core-annotations版本xy0通常与
         版本xy1,xy2等兼容(相同)- > 
    < groupId > com.fasterxml.jackson.core </ groupId >
    < artifactId > jackson-annotations </ artifactId >
    < version > $ {jackson.version} </ version >
  </ dependency >
  < 依赖 >
    < groupId > com.fasterxml.jackson.core </ groupId >
    < artifactId > jackson-core </ artifactId >
    < version > $ {jackson.version} </ version >
  </ dependency >
  ...
< dependencies >

但请注意,这是可选的,只有在jackson核心依赖关系通过传递依赖关系存在冲突时才有必要。

非Maven的

对于非Maven用例,您可以从Central Maven存储库下载jar 

Databind jar也是一个功能性的OSGi包,具有适当的导入/导出声明,因此它可以在OSGi容器上使用。


使用

可以从Jackson-docs存储库中找到更全面的文档以及来自此项目的Wiki但这里有简要的介绍性教程,建议阅读顺序。

1分钟教程:POJO到JSON并返回

最常见的用法是使用JSON,并从中构造一个Plain Old Java Object(“POJO”)。那么让我们从那里开始。简单的2属性POJO像这样:

//注意:也可以使用getter / setter; 这里我们直接使用公共字段:
public  class  MyValue {
   public  String name;
  公共 INT年龄;
  //注意:如果使用getter / setter,可以保留字段`protected`或`private` 
}

我们需要一个com.fasterxml.jackson.databind.ObjectMapper用于所有数据绑定实例,所以让我们构造一个:

ObjectMapper mapper =  new  ObjectMapper(); //创建一次,重用

默认实例适合我们使用 - 稍后我们将了解如何在必要时配置映射器实例。用法很简单:

MyValue value = mapper.readValue(new File("data.json"), MyValue.class);
// or:
value = mapper.readValue(new URL("http://some.com/api/entry.json"), MyValue.class);
// or:
value = mapper.readValue("{"name":"Bob", "age":13}", MyValue.class);

如果我们想写JSON,我们会反过来:

mapper.writeValue(new File("result.json"), myResultObject);
// or:
byte[] jsonBytes = mapper.writeValueAsBytes(myResultObject);
// or:
String jsonString = mapper.writeValueAsString(myResultObject);

到现在为止还挺好?

3分钟教程:通用集合,树模型

除了处理简单的Bean风格的POJO之外,您还可以处理JDK ListMaps:

Map<String, Integer> scoreByName = mapper.readValue(jsonSource, Map.class);
List<String> names = mapper.readValue(jsonSource, List.class);

// and can obviously write out as well
mapper.writeValue(new File("names.json"), names);

只要JSON结构匹配,类型就很简单。如果您有POJO值,则需要指明实际类型(注意:对于具有Listetc类型的POJO属性,这不是必需的):

Map<String, ResultValue> results = mapper.readValue(jsonSource,
   new TypeReference<Map<String, ResultValue>>() { } );
// why extra work? Java Type Erasure will prevent type detection otherwise

(注意:无论通用类型如何,序列化都不需要额外的工作)

可是等等!还有更多!

虽然处理Maps,Lists和其他“简单”对象类型(字符串,数字,布尔值)可能很简单,但对象遍历可能很麻烦。这就是Jackson‘s Tree模型可以派上用场的地方:

//可以读作通用的JsonNode,如果它可以是Object或Array; 或者,
//如果已知为Object,则为ObjectNode,如果是array,ArrayNode等:
ObjectNode root = mapper.readTree("stuff.json");
String name = root.get("name").asText();
int age = root.get("age").asInt();
//也可以修改:这会将子对象添加为属性‘other‘,设置属性‘root.with("other").put("type", "student");
String json = mapper.writeValueAsString(root);
//与上面一样,我们最终得到像‘json‘字符串:// {
//   "name" : "Bob", "age" : 13,
//   "other" : {
//      "type" : "student"
//   }
// }

树模型比数据绑定更方便,特别是在结构高度动态或不能很好地映射到Java类的情况下。

5分钟教程:流解析器,生成器

数据绑定(往/来自POJO)可以方便; 并且像Tree模型一样灵活,还有一个可用的规范处理模型:增量(又称“流”)模型。它是数据绑定和树模型都构建的底层处理模型,但它也向需要最终性能和/或控制解析或生成细节的用户公开。

有关深入解释,请查看Jackson Core组件但是,让我们看一个简单的预告片,以激发你的胃口。

JsonFactory f = mapper.getFactory(); // may alternatively construct directly too

// First: write simple JSON output
File jsonFile = new File("test.json");
JsonGenerator g = f.createGenerator(jsonFile);
// write JSON: { "message" : "Hello world!" }
g.writeStartObject();
g.writeStringField("message", "Hello world!");
g.writeEndObject();
g.close();

// Second: read file back
JsonParser p = f.createParser(jsonFile);

JsonToken t = p.nextToken(); // Should be JsonToken.START_OBJECT
t = p.nextToken(); // JsonToken.FIELD_NAME
if ((t != JsonToken.FIELD_NAME) || !"message".equals(p.getCurrentName())) {
   // handle error
}
t = p.nextToken();
if (t != JsonToken.VALUE_STRING) {
   // similarly
}
String msg = p.getText();
System.out.printf("My message to you is: %s! ", msg);
p.close();

10分钟教程:配置

您可能会使用两种入门级配置机制: 功能注释

常用功能

以下是您最有可能需要了解的配置功能示例。

让我们从更高级别的数据绑定配置开始。

// SerializationFeature用于更改JSON的编写方式

//启用标准缩进(“漂亮打印”):mapper.enable(SerializationFeature.INDENT_OUTPUT);
//
允许序列化“空”POJO(没有要序列化的属性) //(没有这个设置,在这些情况下抛出异常)mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); //编写java.util.Date,Calendar as number(timestamp):mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// DeserializationFeature用于更改如何将JSON读取为POJO: //在遇到未知属性时阻止异常:mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//
允许将JSON空字符串(“”)强制为null对象值:
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

此外,您可能需要更改一些低级JSON解析,生成详细信息:

//用于配置解析设置的JsonParser.Feature:

//允许JSON中的C / C ++样式注释(非标准,默认禁用)
//(注意:使用Jackson 2.5,还有`mapper.enable(feature)`/`mapper.disable(feature)`)mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
//
允许在JSON: mapper中允许(非标准)不带引号的字段名称配置( JsonParser 功能 ALLOW_UNQUOTED_FIELD_NAMES); //允许使用撇号(单引号),非标准mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
//
用于配置低级JSON生成的JsonGenerator.Feature: //强制转义非ASCII字符:
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);

Jackson功能页面上介绍了全套功能

注释:更改属性名称

最简单的基于注释的方法是使用如下@JsonProperty注释:

public  class  MyBean {
    private  String _name;

   //没有注释,我们得到“theName”,但我们想要“name”:
    @JsonProperty("name")
   public String getTheName() { return _name; }
//注意:只需在getter或setter上添加注释即可; //所以我们可以省略它 public void setTheName(String n) { _name = n; }
}

还有其他机制可用于系统命名更改:有关详细信息,请参阅自定义命名约定

另请注意,您可以使用“ 混合注释”来关联所有注释。

注释:忽略属性

有两个主要注释可用于忽略属性:@JsonIgnore对于单个属性; @JsonIgnoreProperties为每班定义

//意味着如果我们在JSON中看到“foo”或“bar”,它们将被静静地跳过
//无论POJO是否具有这样的属性
@JsonIgnoreProperties({ "foo", "bar" })
public class MyBean
{
   // will not be written as JSON; nor assigned from JSON:
   @JsonIgnore
   public String internal;

   // no annotation, public field is read/written normally
   public String external;

   @JsonIgnore
   public void setCode(int c) { _code = c; }

   // note: will also be ignored because setter has annotation!
   public int getCode() { return _code; }
}

与重命名一样,请注意注释在匹配字段,getter和setter之间“共享”:如果只有一个@JsonIgnore,则会影响其他字段但也可以使用“拆分”注释,例如:

public  class  ReadButDontWriteProps {
    private  String _name;
   @JsonProperty  public  void  setNameString  n){_ name = n; }
    @JsonIgnore  public  String  getName(){ return _name; }
}

在这种情况下,不会写出“name”属性(因为‘getter‘被忽略); 但如果从JSON中找到“name”属性,它将被分配给POJO属性!

有关在写出JSON时忽略属性的所有可能方法的更完整说明,请选中“过滤属性”一文。

注释:使用自定义构造函数

与许多其他数据绑定包不同,Jackson不要求您定义“默认构造函数”(不带参数的构造函数)。虽然它将使用一个,如果没有其他可用,您可以轻松定义使用参数构造函数:

public class CtorBean
{
  public final String name; public final int age;

  @JsonCreator // constructor can be public, private, whatever
  private CtorBean(@JsonProperty("name") String name,
    @JsonProperty("age") int age)
  {
      this.name = name;
      this.age = age;
  }
}

构造函数在支持使用Immutable对象方面特别有用 

或者,您也可以定义“工厂方法”:

public class FactoryBean
{
    // fields etc omitted for brewity

    @JsonCreator
    public static FactoryBean create(@JsonProperty("name") String name) {
      // construct and return an instance
    }
}

请注意,使用“创建者方法”(@JsonCreator带有@JsonProperty注释参数)并不排除使用setter:您可以将构造函数/工厂方法中的属性与通过setter设置的属性或直接使用字段进行混合和匹配。

教程:更高级的东西,转换

杰克逊的一个有用(但不是非常广为人知)的特征是它能够进行任意POJO到POJO的转换。从概念上讲,您可以将转换视为两个步骤的序列:首先,将POJO编写为JSON,然后将JSON绑定到另一种POJO中。实现只是跳过实际生成的JSON,并使用更有效的中间表示。

转换在任何兼容类型之间工作,并且调用非常简单:

ResultType结果=映射器convertValue(sourceObject,与resultType 类);

并且只要源和结果类型兼容 - 也就是说,如果to-JSON,from-JSON序列将成功 - 事情将“正常工作”。但是这里有几个可能有用的用例:

//从List <Integer>转换为int [] 
List<Integer> sourceList = ...;
int[] ints = mapper.convertValue(sourceList, int[].class);
//
将POJO转换为Map! Map<String,Object> propertyMap = mapper.convertValue(pojoValue, Map.class);
//
...并返回 PojoType pojo = mapper.convertValue(propertyMap, PojoType.class); //解码Base64!(缺省字节[]表示是base64编码字串)
String base64 = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz";
byte[] binary = mapper.convertValue(base64, byte[].class);

基本上,Jackson可以替代许多Apache Commons组件,用于base64编码/解码和处理“dyna beans”(映射到/来自POJO)等任务。

贡献!

我们希望得到您的贡献,无论是以错误报告,增强请求(RFE),文档或代码补丁的形式。以上所有的主要机制是GitHub Issues系统

代码贡献的基本规则

实际上只有一个主要规则,即接受任何代码贡献,我们需要从作者那里获得一份填充的贡献者许可协议(CLA)。一个CLA对于任何数量的贡献都足够了,但我们需要一个。或者说,使用我们代码的公司需要它。这让他们的律师对开源使用不那么不满。

核心组件对依赖性的限制

所谓的核心组件(流式api,jackson-annotations和jackson-databind)还存在一个额外的限制:除了以下内容外,不允许任何额外的依赖:

  • 核心组件可能依赖于受支持的JDK中包含的任何方法
    • 截至Jackson 2.4及以上版本的最低JDK版本为1.6(基线为2.3及更早版本为1.5)
  • Jackson-databind(这个包)取决于其他两个(注释,流)。

这意味着任何必须依赖其他API或库的东西都需要构建为扩展,通常是Jackson模块。


与Jackson 1.x的不同之处

项目包含2.0及更高版本:最后(1.x)版本的源代码1.9,可在 Jackson-1 repo上获得。

与1.x“mapper”jar相比的主要差异是:

  • Maven构建而不是Ant
  • Java包现在com.fasterxml.jackson.databind(而不是org.codehaus.jackson.map

































































































以上是关于Jackson数据处理及绑定的主要内容,如果未能解决你的问题,请参考以下文章

实用代码片段将json数据绑定到html元素 (转)

Spring Boot,AWS应用程序上的Jackson数据绑定依赖错误

FasterXML/Jackson-databind远程代码执行漏洞安全通告(CVE-2020-35728)

使用杰克逊数据绑定跳过嵌套字段?

使用 Jackson 序列化通用接口子类

有没有更聪明的方法将布局绑定到片段?