1. 概述
JSON-LD 是一種基於 JSON 的 RDF 格式,用於表示 鏈接數據。它允許擴展現有的 JSON 對象,幷包含機器可讀的鏈接能力。在本教程中,我們將探討一些基於 Jackson 的選項,用於直接將 JSON-LD 格式序列化和反序列化為 POJO。我們還將涵蓋 JSON-LD 的基本概念,以便我們理解示例。
2. 基本概念
第一次看到 JSON-LD 文檔時,我們會注意到一些成員名稱以 @ 字符開頭。 這些是 JSON-LD 關鍵詞,它們的取值有助於我們理解文檔的其餘部分。為了在 JSON-LD 的世界中導航,並理解本教程,我們需要了解四個關鍵詞:
- @context 是包含鍵值對映射的 JSON 對象,用於解釋文檔所需的一切描述
- @vocab 是 @context 中可能存在的鍵,它引入了默認詞彙,使 @context 對象更短
- @id 是用於標識鏈接的關鍵詞,既可以作為資源屬性來直接鏈接到資源本身,也可以作為 @type 值來標記任何字段為鏈接
- @type 是用於標識資源類型(在資源級別或在 @context 中)的關鍵詞;例如,定義嵌入資源的類型
由於我們已經熟悉了 Jackson,我們可能會意識到,可以使用 @id 和 @type 註解,在任何 POJO 中輕鬆序列化兩個自定義字段。但是,手動編寫 @context 可能會耗費大量時間和容易出錯。
因此,為了避免這種容易出錯的方法,讓我們更仔細地研究一下我們可以用來生成 @context 的兩個庫。不幸的是,它們都沒有能夠生成所有 JSON-LD 功能,稍後我們將研究它們的不足之處。
4. Serialization With Jackson-Jsonld
Jackson-Jsonld is a Jackson module that enables the annotation of POJOs in a convenient way to generate JSON-LD documents.4.1. Maven Dependencies
First, let’s add jackson-jsonld as a dependency to the pom.xml:
com.io-informatics.oss
jackson-jsonld
0.1.1
]]>
4.2. Example
Then, let’s create our example POJO and annotate it for @context generation:@JsonldResource
@JsonldNamespace(name = "s", uri = "http://schema.org/")
@JsonldType("s:Person")
@JsonldLink(rel = "s:knows", name = "knows", href = "http://example.com/person/2345")
public class Person {
@JsonldId
private String id;
@JsonldProperty("s:name")
private String name;
// constructor, getters, setters
}
Let’s deconstruct the steps to understand what we’ve done:
- With @JsonldResource we marked the POJO for processing as a JSON-LD resourceIn the @JsonldNamespace we defined a shorthand for the vocabulary we want to useThe parameter we specified in @JsonldType will become the @type of the resourceWe used the @JsonldLink annotation to add links to the resource. When processed, the name parameter will be used as a field name and also added as a key to the @context. href will be the field value and rel will be the mapped value in the @contextThe field we marked with @JsonldId will become the @id of the resourceThe parameter we specified in @JsonldProperty will become the value mapped to the field’s name in the @context
Next, let’s generate the JSON-LD document.
First, we should register the JsonldModule in the ObjectMapper. This module contains a custom Serializer that Jackson will use for POJOs marked with the @JsonldResource annotation.
Then, we’ll continue and use the ObjectMapper to generate the JSON-LD document:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JsonldModule());
Person person = new Person("http://example.com/person/1234", "Example Name");
String personJsonLd = objectMapper.writeValueAsString(person);
As a result, the personJsonLd variable should now contain:
{
"@type": "s:Person",
"@context": {
"s": "http://schema.org/",
"name": "s:name",
"knows": {
"@id": "s:knows",
"@type": "@id"
}
},
"name": "Example Name",
"@id": "http://example.com/person/1234",
"knows": "http://example.com/person/2345"
}
4.3. Considerations
Before we choose this library for a project, we should consider the following:- Using the @vocab keyword is not possible, so we’ll have to either use the @JsonldNamespace to provide a shorthand for resolving field names or write out the full Internationalized Resource Identifier (IRI) every timeWe can only define links at compile-time, so in order to add a link runtime, we would need to use reflection to change that parameter in the annotation
5. Serialization With Hydra-Jsonld
Hydra-Jsonld 是 Hydra-Java 庫的一個模塊,主要用於為 Spring 應用程序創建方便的 JSON-LD 響應。
它使用 Hydra Vocabulary 使 JSON-LD 文檔更具表現力。
但是,Hydra-Jsonld 模塊包含一個 Jackson 序列化器 及其一些註解,我們可以使用它們在 Spring 框架之外生成 JSON-LD 文檔。
5.1. Maven Dependencies
首先,讓我們將 hydra-jsonld 依賴添加到 pom.xml 中:
<dependency>
<groupId>de.escalon.hypermedia</groupId>
<artifactId>hydra-jsonld</artifactId>
<version>0.4.2</version>
</dependency>
5.2. Example
其次,讓我們為 POJO 註釋生成 @context:
@Vocab("http://example.com/vocab/")
@Expose("person")
public class Person {
private String id;
private String name;
// constructor
@JsonProperty("@id")
public String getId() {
return id;
}
@Expose("fullName")
public String getName() {
return name;
}
}
- 與 Jackson-Jsonld 示例不同,我們從我們的 POJO 中刪除了 knows 字段,因為 Hydra-Jsonld 在 Spring 框架之外的限制。
- 我們使用 @Vocab 註解設置了我們的首選詞彙。
- 通過在類上使用 @Expose 註解,我們設置了不同的資源 @type。
- 我們使用 @Expose 註解在一個屬性上設置其映射到 @context 中的自定義值。
- 為了從屬性中生成 @id,我們使用了 Jackson 的 @JsonProperty 註解。
接下來,讓我們配置一個可以註冊到 ObjectMapper 中的 Jackson 模塊。我們將 JacksonHydraSerializer 添加為 BeanSerializerModifier,以便將其應用於正在序列化的所有 POJO。
SimpleModule getJacksonHydraSerializerModule() {
return new SimpleModule() {
@Override
public void setupModule(SetupContext context) {
super.setupModule(context);
context.addBeanSerializerModifier(new BeanSerializerModifier() {
@Override
public JsonSerializer<?> modifySerializer(
SerializationConfig config,
BeanDescription beanDesc,
JsonSerializer<?> serializer) {
if (serializer instanceof BeanSerializerBase) {
return new JacksonHydraSerializer((BeanSerializerBase) serializer);
} else {
return serializer;
}
}
});
}
};
}
然後,讓我們在 ObjectMapper 中註冊模塊並使用它。我們還應該將 ObjectMapper 設置為僅包含非 null 值以生成有效的 JSON-LD 文檔:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(getJacksonHydraSerializerModule());
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
Person person = new Person("http://example.com/person/1234", "Example Name");
String personJsonLd = objectMapper.writeValueAsString(person);
現在,personJsonLd 變量應包含:
{
"@context": {
"@vocab": "http://example.com/vocab/",
"name": "fullName"
},
"@type": "person",
"name": "Example Name",
"@id": "http://example.com/person/1234"
}
5.3. Considerations
雖然在技術上可以使用 Hydra-Jsonld 在 Spring 框架之外,但它最初是為了與 Spring-HATEOAS 配合而設計的。因此,我們無法使用註解生成鏈接,就像在 Jackson-Jsonld 中看到的那樣。另一方面,它們對於某些 Spring 特定類自動生成。
在選擇此庫用於項目之前,我們應該考慮以下內容:
- 使用它與 Spring 框架一起將啓用附加功能。
- 如果未使用 Spring 框架,則沒有簡單的方法來生成鏈接。
- 我們無法禁用 @vocab 的使用,只能覆蓋它。
6. Deserialization With Jsonld-Java and Jackson
Jsonld-Java 是 JSON-LD 1.0 規範和 API 的 Java 實現,不幸的是,它不是最新版本。
對於 1.1 規範版本的實現,請查看 Titanium JSON-LD 庫。
要反序列化一個 JSON-LD 文檔,讓我們使用 JSON-LD API 功能“壓縮”將其轉換為可以映射到 POJO 的格式,使用 ObjectMapper。
6.1. Maven 依賴
首先,讓我們添加 jsonld-java 的依賴項:
<dependency>
<groupId>com.github.jsonld-java</groupId>
<artifactId>jsonld-java</artifactId>
<version>0.13.0</version>
</dependency>
6.2. 示例
讓我們將此 JSON-LD 文檔作為輸入:
{
"@context": {
"@vocab": "http://schema.org/",
"knows": {
"@type": "@id"
}
},
"@type": "Person",
"@id": "http://example.com/person/1234",
"name": "Example Name",
"knows": "http://example.com/person/2345"
}
為了簡化,假設文檔的內容存儲在 String 變量 inputJsonLd 中。
首先,讓我們壓縮它並將其轉換回 String:
Object jsonObject = JsonUtils.fromString(inputJsonLd);
Object compact = JsonLdProcessor.compact(jsonObject, new HashMap<>(), new JsonLdOptions());
String compactContent = JsonUtils.toString(compact);
- 我們可以使用 Jsonld-Java 庫中的 JsonUtils 方法解析和寫入 JSON-LD 對象
- 在使用 compact 方法時,作為第二個參數,我們可以使用一個空 Map。 這樣,壓縮算法將產生一個簡單的 JSON 對象,其中鍵已解析為 IRI 形式
compactContent 變量應包含:
{
"@id": "http://example.com/person/1234",
"@type": "http://schema.org/Person",
"http://schema.org/knows": {
"@id": "http://example.com/person/2345"
},
"http://schema.org/name": "Example Name"
}
其次,讓我們根據此結構定製我們的 POJO 註釋:
@JsonIgnoreProperties(ignoreUnknown = true)
public class Person {
@JsonProperty("@id")
private String id;
@JsonProperty("http://schema.org/name")
private String name;
@JsonProperty("http://schema.org/knows")
private Link knows;
// constructors, getters, setters
public static class Link {
@JsonProperty("@id")
private String id;
// constructors, getters, setters
}
}
最後,讓我們將 JSON-LD 映射到 POJO:
ObjectMapper objectMapper = new ObjectMapper();
Person person = objectMapper.readValue(compactContent, Person.class);
7. 結論
在本文中,我們探討了兩種基於 Jackson 的庫,用於將 POJO 序列化為 JSON-LD 文檔,以及一種將 JSON-LD 序列化為 POJO 的方法。
正如我們所強調的,這兩個序列化庫都存在一些不足之處,我們應該在將其使用之前加以考慮。 如果我們需要使用 JSON-LD 的更多功能,這些庫無法提供,我們可以通過使用 RDF 庫,並以 JSON-LD 輸出格式來創建文檔。