Перейти к основному содержимому

Сериализация гипермедиа с помощью JSON-LD

· 8 мин. чтения

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 .