1. Обзор
JSON-LD — это основанный на JSON формат RDF для представления связанных данных . Он позволяет расширять существующие объекты JSON с помощью возможностей гипермедиа; другими словами, возможность содержать ссылки в машиночитаемом виде.
В этом руководстве мы рассмотрим пару вариантов на основе Джексона для сериализации и десериализации формата JSON-LD непосредственно в POJO . Мы также рассмотрим основные концепции JSON-LD, которые позволят нам понять примеры.
2. Основные понятия
Когда мы впервые видим документ JSON-LD, мы замечаем, что имена некоторых элементов начинаются с символа @
. Это ключевые слова JSON-LD, и их значения помогают нам понять остальную часть документа.
Чтобы ориентироваться в мире JSON-LD и понять этот учебник, нам нужно знать четыре ключевых слова:
@context
— это описание объекта JSON, которое содержит карту ключ-значение всего, что необходимо для интерпретации документа.@vocab
— это возможный ключ в@context
, который вводит словарь по умолчанию, чтобы сделать объект@context
намного короче .@id
— это ключевое слово для идентификации ссылок либо как свойства ресурса, представляющего прямую ссылку на сам ресурс, либо как значение@type
, чтобы пометить любое поле как ссылку.@type
— ключевое слово для идентификации типов ресурсов либо на уровне ресурсов, либо в@context
; например, чтобы определить тип встроенных ресурсов
3. Сериализация в Java
Прежде чем мы продолжим, мы должны взглянуть на наши предыдущие руководства, чтобы освежить нашу память о Jackson ObjectMapper
, Jackson Annotations и пользовательских сериализаторах Jackson .
Уже будучи знакомым с Джексоном, мы можем понять, что можем легко сериализовать два настраиваемых поля в любом POJO как @id
и @type
, используя аннотацию @JsonProperty
. Тем не менее, написание @context
вручную может быть очень трудоемким и подверженным ошибкам .
Поэтому, чтобы избежать этого подверженного ошибкам подхода, давайте подробнее рассмотрим две библиотеки, которые мы могли бы использовать для генерации @context
. К сожалению, ни один из них не способен генерировать все функции JSON-LD, но позже мы также рассмотрим их недостатки.
4. Сериализация с Джексоном-Джонсом
Jackson-Jsonld — это модуль Jackson, который позволяет аннотировать POJO удобным способом для создания документов JSON-LD.
4.1. Зависимости Maven
Во-первых, давайте добавим jackson-jsonld
в качестве зависимости к pom.xml
:
<dependency>
<groupId>com.io-informatics.oss</groupId>
<artifactId>jackson-jsonld</artifactId>
<version>0.1.1</version>
</dependency>
4.2. Пример
Затем давайте создадим наш пример POJO и аннотируем его для генерации @context
:
@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
}
Давайте разберем шаги, чтобы понять, что мы сделали:
- С помощью
@JsonldResource
мы пометили POJO для обработки как ресурс JSON-LD. - В
@JsonldNamespace
мы определили сокращение для словаря, который мы хотим использовать. - Параметр, который мы указали в
@JsonldType
, станет@type
ресурса. - Мы использовали аннотацию
@JsonldLink
для добавления ссылок на ресурс. При обработке параметримени
будет использоваться как имя поля, а также добавлен как ключ к@context.
href
будет значением поля, аrel
будет сопоставленным значением в@context
- Поле, которое мы пометили
@JsonldId
, станет@id
ресурса. - Параметр, который мы указали в
@JsonldProperty
, станет значением, сопоставленным с именем поля в@context.
Далее сгенерируем документ JSON-LD.
Во-первых, мы должны зарегистрировать JsonldModule
в ObjectMapper
. Этот модуль содержит пользовательский сериализатор
, который Джексон будет использовать для объектов POJO, помеченных аннотацией @JsonldResource
.
Затем мы продолжим и используем ObjectMapper
для создания документа JSON-LD:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JsonldModule());
Person person = new Person("http://example.com/person/1234", "Example Name");
String personJsonLd = objectMapper.writeValueAsString(person);
В результате переменная personJsonLd
теперь должна содержать:
{
"@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. Соображения
Прежде чем мы выберем эту библиотеку для проекта, мы должны учитывать следующее:
- Использование ключевого слова
@vocab
невозможно, поэтому нам придется либо использовать@JsonldNamespace
, чтобы предоставить сокращение для разрешения имен полей, либо каждый раз записывать полный интернационализированный идентификатор ресурса (IRI). - Мы можем определять ссылки только во время компиляции, поэтому, чтобы добавить время выполнения ссылки, нам нужно будет использовать отражение, чтобы изменить этот параметр в аннотации.
5. Сериализация с Hydra-Jsonld
Hydra-Jsonld — это модуль библиотеки Hydra-Java , который в первую очередь создан для удобного создания ответов JSON-LD для приложений Spring. Он использует словарь Hydra , чтобы сделать документы JSON-LD более выразительными.
Однако модуль Hydra-Jsonld содержит сериализатор
Джексона и некоторые аннотации, которые мы можем использовать для генерации документов JSON-LD вне Spring Framework .
5.1. Зависимости Maven
Во-первых, давайте добавим зависимость для hydra-jsonld
в pom.xml
:
<dependency>
<groupId>de.escalon.hypermedia</groupId>
<artifactId>hydra-jsonld</artifactId>
<version>0.4.2</version>
</dependency>
5.2. Пример
Во-вторых, давайте аннотируем наш POJO для генерации @context
.
Hydra-Jsonld автоматически генерирует @context
по умолчанию без необходимости аннотаций. Если нас устраивают значения по умолчанию, нам нужно только добавить @id
, чтобы получить действительный документ JSON-LD.
Словарем по умолчанию будет словарь schema.org , @type — имя
класса
Java , а общедоступные свойства POJO — все это будет включено в результирующий документ JSON-LD.
В этом примере давайте переопределим эти значения по умолчанию пользовательскими значениями :
@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 мы исключили поле
knows
из нашего POJO из-за ограничений Hydra-Jsonld за пределами Spring Framework. - Мы устанавливаем предпочитаемый словарь с помощью аннотации
@Vocab.
- Используя аннотацию
@Expose
для класса, мы устанавливаем другой ресурс@type
- Мы использовали ту же аннотацию
@Expose
для свойства, чтобы установить его сопоставление с пользовательским значением в@context.
- Для генерации
@id
из свойства мы использовали аннотацию@JsonProperty
от Jackson .
Далее давайте настроим экземпляр модуля
Джексона , который мы можем зарегистрировать в ObjectMapper
. Мы добавим 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 так
, чтобы он включал только ненулевые
значения , чтобы создать действительный документ 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. Соображения
Хотя технически возможно использовать Hydra-Jsonld вне Spring Framework, изначально он был разработан для использования с Spring-HATEOAS . В результате нет возможности генерировать ссылки с аннотациями, как мы видели в Jackson-Jsonld. С другой стороны, для некоторых классов Spring они генерируются автоматически.
Прежде чем мы выберем эту библиотеку для проекта, мы должны учитывать следующее:
- Использование его с Spring Framework активирует дополнительные функции.
- Нет простого способа генерировать ссылки, если мы не используем Spring Framework.
- Мы не можем отключить использование
@vocab
, мы можем только переопределить его .
6. Десериализация с Jsonld-Java и Джексоном
Jsonld-Java — это Java-реализация спецификации и API JSON-LD 1.0, которая, к сожалению, не является последней версией.
Для реализации версии спецификации 1.1 взгляните на библиотеку Titanium JSON-LD .
Чтобы десериализовать документ JSON-LD, давайте преобразуем его с помощью функции API JSON-LD, называемой уплотнением, в формат, который мы можем сопоставить с 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);
- Мы можем анализировать и записывать объект JSON-LD с помощью методов из
JsonUtils,
который является частью библиотеки Jsonld-Java. - При использовании
компактного
метода в качестве второго параметра мы можем использовать пустуюкарту
. Таким образом, алгоритм сжатия создаст простой объект 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. Заключение
В этой статье мы рассмотрели две библиотеки на основе Джексона для сериализации POJO в документ JSON-LD и один способ десериализации JSON-LD в POJO.
Как мы уже отмечали, у обеих библиотек сериализации есть недостатки, которые следует учитывать перед их использованием. Если нам нужно использовать больше функций JSON-LD, чем могут предложить эти библиотеки, мы могли бы создать наш документ с помощью библиотеки RDF с выходным форматом JSON-LD.
Как обычно, исходный код можно найти на GitHub .