Jackson API 的优势
- 是可用于处理 JSON 文件的最快库之一。
- 具有更广泛的注解支持,甚至接受来自其他 API(如 JAXB)的注解。
- 与 JAX-RS 有更好的集成。
流式传输(核心)
这是 Jackson 的核心,它是解析器/序列化器所在的地方,处理输入/输出数据的流处理。
- 这是解析/序列化数据的最快方式。
- 不是处理 JSON 内容的最便捷方式。
- 内容必须按照与输入/输出完全相同的顺序进行处理才能正常工作,即不能随机访问。
- 更多地被中间件和框架使用,但在应用程序中不是很常见。
这是我们必须实现的 API,以拥有支持我们想要的数据格式的完整功能版本的 Jackson。它也是唯一由 XML、Java 属性、YAML 等其他数据格式实现的 API。
实现此 API 后将自动支持 DataBinding 和 TreeModel。
GSON也和Jackson一起被研究过,但由于与Jackson相似,表现欠佳,所以Jackson是本报告的主要对象。
性能的差异是由于这些 API 处理数据的方式,Jackson 最初使用的是流,这是一种快速的低级方法,它使 Jackson 成为最快的处理 JSON 的 API当它启动时。
虽然 GSON 也开始使用这种方法来处理数据,但根据基准测试,Jackson 仍然是最快的 API,可以在参考部分找到。
树模型
这是提供 JSON 文档的可变内存树表示的 api 部分。
当处理一些类似于 XML 的数据格式时,这个 API 是最灵活的。
数据绑定
这是 API 的一部分,它根据属性访问器约定或注释将 JSON 与 POJO 相互转换。
处理 JSON 内容的最便捷方式。
它允许在 JSON 数据和 JAVA 对象之间进行转换。
类似于 TreeModel,但使用 Java 对象而不是基于节点的模型。
这个API在应用方面是最常用的
Jackson Streaming 实施注意事项
由于这是我们唯一需要实现的 API,我们将更加关注这一点。
Streaming API 的实现使用所谓的JsonToken 来识别即将进入流中的 JSON 对象,即输入/输出数据。
JsonToken 枚举具有以下定义:
NOT_AVAILABLE(null),
START_OBJECT("{"),
END_OBJECT("}"),
START_ARRAY("["),
END_ARRAY("]"),
FIELD_NAME(null),
VALUE_STRING(null),
VALUE_NUMBER_INT(null),
VALUE_NUMBER_FLOAT(null),
VALUE_TRUE("true"),
VALUE_FALSE("false"),
VALUE_NULL("null")
这些令牌可以通过所谓的ReadContext 检索。 ReadContext 有一些常量来定义自己的类型。
内部用于表示JsonStreamContext 类型的常量。
protected final static int TYPE_ROOT = 0; // Means the root element.
protected final static int TYPE_ARRAY = 1; // Means the array elements.
protected final static int TYPE_OBJECT = 2; // Means the JSON object elements.
Java Properties 数据格式的 ReadContext 的构造方法片段。
JPropReadContext extends JsonStreamContext {
// Static factory method used to create the JPropReadContext instance.
public static JPropReadContext create(JPropNode root) {
if (root.isArray()) { // can this ever occur?
return new ArrayContext(null, root);
}
return new ObjectContext(null, root);
}
…
ArrayContext extends JPropReadContext {
// Constructor for ArrayContext.
public ArrayContext(JPropReadContext p, JPropNode arrayNode) {
super(JsonStreamContext.TYPE_ARRAY, p, arrayNode);
_contents = arrayNode.arrayContents();
_state = STATE_START;
}
…
}
…
ObjectContext extends JPropReadContext {
// Constructor for ObjectContext.
public ObjectContext(JPropReadContext p, JPropNode objectNode) {
super(JsonStreamContext.TYPE_OBJECT, p, objectNode);
_contents = objectNode.objectContents();
_state = STATE_START;
}
…
}
…
}
JPropReadContext只是扩展JsonStreamContext,所以它需要从JsonStreamContext传递一个常量给它,指示上下文的类型,如果它是根、数组或对象。常量是一个简单的 int 值,所以在此之前没有问题。
这里是相同的信息,但现在是 XML 数据格式。
…
// Static factory method used to create the XmlReadContext instance of type ROOT.
public static XmlReadContext createRootContext(int lineNr, int colNr) {
return new XmlReadContext(null, TYPE_ROOT, lineNr, colNr);
}
// Static factory method used to create the XmlReadContext instance of type ARRAY.
public final XmlReadContext createChildArrayContext(int lineNr, int colNr) {
XmlReadContext ctxt = _child;
if (ctxt == null) {
_child = ctxt = new XmlReadContext(this, TYPE_ARRAY, lineNr, colNr);
return ctxt;
}
ctxt.reset(TYPE_ARRAY, lineNr, colNr);
return ctxt;
}
// Static factory method used to create the XmlReadContext instance of type OBJECT.
public final XmlReadContext createChildObjectContext(int lineNr, int colNr) {
XmlReadContext ctxt = _child;
if (ctxt == null) {
_child = ctxt = new XmlReadContext(this, TYPE_OBJECT, lineNr, colNr);
return ctxt;
}
ctxt.reset(TYPE_OBJECT, lineNr, colNr);
return ctxt;
}
…
Jackson 的其他数据格式的实现只是简单地使用这些常量和JsonToken,就好像它们的格式是 Json 实例一样,换句话说,它伪造自己的格式以使其看起来像 Json 实例杰克逊,这不是一个干净的方式。例如,他们可以使用TYPE_OBJECT 来表示<element>value<element> 或property = "string containing the value of the property." 之类的东西。
这适用于与 Json 具有相同/更少功能的格式,因为每个功能都可以实现,但对于具有更多功能的数据格式是不可能的。
此报告是为 GlobalMentor Inc. 制作的,作为 https://globalmentor.atlassian.net/browse/URF-33 的一部分,我们尝试在杰克逊实现对 SURF data format 的支持。