Sérialisation hypermédia avec JSON-LD

1. Vue d'ensemble

JSON-LD est un format RDF basé sur JSON pour représenter les données liées. Il permet d'étendre les objets JSON existants avec des capacités hypermédia; en d'autres termes, la capacité de contenir des liens de manière lisible par machine.

Dans ce didacticiel, nous examinerons quelques options basées sur Jackson pour sérialiser et désérialiser le format JSON-LD directement dans les POJO . Nous aborderons également les concepts de base de JSON-LD qui nous permettront de comprendre les exemples.

2. Concepts de base

La première fois que nous voyons un document JSON-LD, nous remarquons que certains noms de membres commencent par le caractère @ . Ce sont des mots-clés JSON-LD, et leurs valeurs nous aident à comprendre le reste du document.

Pour naviguer dans le monde de JSON-LD et pour comprendre ce tutoriel, nous devons être conscients de quatre mots-clés:

  • @context est la description de l'objet JSON qui contient une carte clé-valeur de tout ce qui est nécessaire pour l'interprétation du document
  • @vocab est une clé possible dans @context qui introduit un vocabulaire par défaut pour rendre l' objet @context beaucoup plus court
  • @id est le mot-clé pour identifier les liens soit en tant que propriété de ressource pour représenter le lien direct vers la ressource elle-même, soit en tant que valeur @type pour marquer un champ comme lien
  • @type est le mot-clé permettant d'identifier les types de ressources soit au niveau de la ressource, soit dans le @context ; par exemple, pour définir le type de ressources embarquées

3. Sérialisation en Java

Avant de continuer, nous devrions jeter un coup d'œil à nos didacticiels précédents pour rafraîchir notre mémoire sur le Jackson ObjectMapper , les Annotations Jackson et les sérialiseurs Jackson personnalisés.

Étant déjà familier avec Jackson, nous pourrions réaliser que nous pourrions facilement sérialiser deux champs personnalisés dans n'importe quel POJO en tant que @id et @type en utilisant l' annotation @JsonProperty . Cependant, écrire le @context à la main peut être beaucoup de travail et également sujet à des erreurs .

Par conséquent, pour éviter cette approche sujette aux erreurs, examinons de plus près deux bibliothèques que nous pourrions utiliser pour la génération @context . Malheureusement, aucun d'eux n'est capable de générer toutes les fonctionnalités de JSON-LD, mais nous examinerons également leurs lacunes plus tard.

4. Sérialisation avec Jackson-Jsonld

Jackson-Jsonld est un module Jackson qui permet l'annotation des POJO de manière pratique pour générer des documents JSON-LD.

4.1. Dépendances de Maven

Tout d'abord, ajoutons jackson-jsonld en tant que dépendance au pom.xml :

 com.io-informatics.oss jackson-jsonld 0.1.1 

4.2. Exemple

Ensuite, créons notre exemple de POJO et annotons-le pour la génération @context :

@JsonldResource @JsonldNamespace(name = "s", uri = "//schema.org/") @JsonldType("s:Person") @JsonldLink(rel = "s:knows", name = "knows", href = "//example.com/person/2345") public class Person { @JsonldId private String id; @JsonldProperty("s:name") private String name; // constructor, getters, setters }

Déconstruisons les étapes pour comprendre ce que nous avons fait:

  • Avec @JsonldResource, nous avons marqué le POJO pour le traitement en tant que ressource JSON-LD
  • Dans @JsonldNamespace, nous avons défini un raccourci pour le vocabulaire que nous voulons utiliser
  • Le paramètre que nous avons spécifié dans @JsonldType deviendra le @type de la ressource
  • Nous avons utilisé l' annotation @JsonldLink pour ajouter des liens vers la ressource. Une fois traité, le paramètre de nom sera utilisé comme nom de champ et également ajouté en tant que clé au @context. href sera la valeur du champ et rel sera la valeur mappée dans le @context
  • Le champ que nous avons marqué avec @JsonldId deviendra le @id de la ressource
  • Le paramètre que nous avons spécifié dans @JsonldProperty deviendra la valeur mappée au nom du champ dans le @context

Ensuite, générons le document JSON-LD.

Tout d'abord, nous devons enregistrer le JsonldModule dans l' ObjectMapper . Ce module contient un sérialiseur personnalisé que Jackson utilisera pour les POJO marqués avec l' annotation @JsonldResource .

Ensuite, nous continuerons et utiliserons l' ObjectMapper pour générer le document JSON-LD:

ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JsonldModule()); Person person = new Person("//example.com/person/1234", "Example Name"); String personJsonLd = objectMapper.writeValueAsString(person);

Par conséquent, la variable personJsonLd doit maintenant contenir:

{ "@type": "s:Person", "@context": { "s": "//schema.org/", "name": "s:name", "knows": { "@id": "s:knows", "@type": "@id" } }, "name": "Example Name", "@id": "//example.com/person/1234", "knows": "//example.com/person/2345" }

4.3. Considérations

Avant de choisir cette bibliothèque pour un projet, nous devons considérer les éléments suivants:

  • L'utilisation du mot-clé @vocab n'est pas possible, nous devrons donc soit utiliser @JsonldNamespace pour fournir un raccourci pour résoudre les noms de champ, soit écrire l'IRI (Internationalized Resource Identifier) ​​à chaque fois
  • Nous ne pouvons définir des liens qu'au moment de la compilation, donc pour ajouter un lien d'exécution, nous aurions besoin d'utiliser la réflexion pour modifier ce paramètre dans l'annotation

5. Sérialisation avec Hydra-Jsonld

Hydra-Jsonld est un module de la bibliothèque Hydra-Java, qui est principalement conçu pour permettre la création pratique de réponses JSON-LD pour les applications Spring. Il utilise le vocabulaire Hydra pour rendre les documents JSON-LD plus expressifs.

Cependant , le module Hydra-Jsonld contient un sérialiseur Jackson et quelques annotations que nous pouvons utiliser pour générer des documents JSON-LD en dehors de Spring Framework .

5.1. Dépendances de Maven

Tout d'abord, ajoutons la dépendance pour hydra-jsonld au pom.xml :

 de.escalon.hypermedia hydra-jsonld 0.4.2 

5.2. Exemple

Deuxièmement, annotons notre POJO pour la génération @context .

Hydra-Jsonld génère automatiquement un @context par défaut sans avoir besoin d'annotations. Si nous sommes satisfaits des valeurs par défaut, il suffit d'ajouter le @id pour obtenir un document JSON-LD valide.

The default vocabulary will be the schema.org vocabulary, the @type the Java class name, and the public properties of the POJO will all be included in the resulting JSON-LD document.

In this example, let's override these defaults with custom values:

@Vocab("//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; } }

Again, let’s take a closer look at the steps involved:

  • Compared to the Jackson-Jsonld example, we left out the knows field from our POJO because of the limitations of Hydra-Jsonld outside of the Spring Framework
  • We set our preferred vocabulary with the @Vocab annotation
  • By using the @Expose annotation on the class, we set a different resource @type
  • We used the same @Expose annotation on a property to set its mapping to a custom value in the @context
  • For generating the @id from a property, we used the @JsonProperty annotation from Jackson

Next, let's configure an instance of a Jackson Module that we can register in the ObjectMapper. We'll add the JacksonHydraSerializer as a BeanSerializerModifier so it can be applied to all POJOs that are being serialized:

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; } } }); } }; }

Then let's register the Module in ObjectMapper and use it. We should also set the ObjectMapper to only include non-null values to produce a valid JSON-LD document:

ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(getJacksonHydraSerializerModule()); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); Person person = new Person("//example.com/person/1234", "Example Name"); String personJsonLd = objectMapper.writeValueAsString(person);

Now, the personJsonLd variable should contain:

{ "@context": { "@vocab": "//example.com/vocab/", "name": "fullName" }, "@type": "person", "name": "Example Name", "@id": "//example.com/person/1234" }

5.3. Considerations

Although it's technically possible to use Hydra-Jsonld outside of the Spring Framework, it was originally designed for usage with Spring-HATEOAS. As a result, there's no way to generate links with annotations as we saw in Jackson-Jsonld. On the other hand, they are generated for some Spring-specific classes automatically.

Before we choose this library for a project, we should consider the following:

  • Using it with the Spring Framework will enable additional features
  • There's no easy way to generate links if we're not using the Spring Framework
  • We cannot disable the usage of @vocab, we can only override it

6. Deserialization With Jsonld-Java and Jackson

Jsonld-Java is the Java implementation of the JSON-LD 1.0 specification and API, which is unfortunately not the latest version.

For an implementation of the 1.1 specification version, have a look at the Titanium JSON-LD library.

To deserialize a JSON-LD document, let's transform it with a JSON-LD API feature, called compaction, to a format that we can map to a POJO with ObjectMapper.

6.1. Maven Dependencies

First, let's add the dependency for jsonld-java:

 com.github.jsonld-java jsonld-java 0.13.0 

6.2. Example

Let's work with this JSON-LD document as our input:

{ "@context": { "@vocab": "//schema.org/", "knows": { "@type": "@id" } }, "@type": "Person", "@id": "//example.com/person/1234", "name": "Example Name", "knows": "//example.com/person/2345" }

For the sake of simplicity, let's assume we have the content of the document in a String variable called inputJsonLd.

First, let's compact it and convert it back to a String:

Object jsonObject = JsonUtils.fromString(inputJsonLd); Object compact = JsonLdProcessor.compact(jsonObject, new HashMap(), new JsonLdOptions()); String compactContent = JsonUtils.toString(compact);
  • We can parse and write the JSON-LD object with methods from the JsonUtils, which is part of the Jsonld-Java library
  • When using the compact method, as a second parameter we can use an empty Map. This way, the compaction algorithm will produce a simple JSON object where the keys are resolved to their IRI forms

The compactContent variable should contain:

{ "@id": "//example.com/person/1234", "@type": "//schema.org/Person", "//schema.org/knows": { "@id": "//example.com/person/2345" }, "//schema.org/name": "Example Name" }

Deuxièmement, adaptons notre POJO avec des annotations Jackson pour s'adapter à une telle structure de document:

@JsonIgnoreProperties(ignoreUnknown = true) public class Person { @JsonProperty("@id") private String id; @JsonProperty("//schema.org/name") private String name; @JsonProperty("//schema.org/knows") private Link knows; // constructors, getters, setters public static class Link { @JsonProperty("@id") private String id; // constructors, getters, setters } }

Et enfin, mappons le JSON-LD au POJO:

ObjectMapper objectMapper = new ObjectMapper(); Person person = objectMapper.readValue(compactContent, Person.class);

7. Conclusion

Dans cet article, nous avons examiné deux bibliothèques basées sur Jackson pour sérialiser un POJO dans un document JSON-LD, et une façon de désérialiser un JSON-LD dans un POJO.

Comme nous l'avons souligné, les deux bibliothèques de sérialisation présentent des lacunes que nous devons prendre en compte avant de les utiliser. Si nous devons utiliser plus de fonctionnalités de JSON-LD que ces bibliothèques ne peuvent offrir, nous pourrions aborder la création de notre document via une bibliothèque RDF avec le format de sortie JSON-LD.

Comme d'habitude, le code source peut être trouvé sur GitHub.