Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 108 additions & 73 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,115 +2,150 @@
[![Maven Central](https://img.shields.io/maven-central/v/com.cosium.hal_model/hal-model.svg)](https://central.sonatype.com/artifact/com.cosium.hal_model/hal-model)

# HAL Model
A java modelisation of HAL (Hypertext Application Language)

A java modelisation of HAL (Hypertext Application Language).

# Prerequisites

- Java 17+

# Quick start

1. Add the `hal-model` dependency:
```xml
<dependency>
<groupId>com.cosium.hal_model</groupId>
<artifactId>hal-model2</artifactId>
<version>${hal-model.version}</version>
</dependency>
```
2. Add `HalModelJacksonModule` to your [Jackson ObjectMapper](https://github.com/fasterxml/jackson):
```java
JsonMapper jsonMapper = JsonMapper.builder().addModule(new HalModelJacksonModule()).build();
```
3. Use [Jackson ObjectMapper](https://github.com/fasterxml/jackson) to parse any HAL(-FORMS) JSON body
# Setup

Add the `hal-model` dependency:

```xml
<dependency>
<groupId>com.cosium.hal_model</groupId>
<artifactId>hal-model2</artifactId>
<version>${hal-model.version}</version>
</dependency>
```

# JSON parsing

## HalFormsBodies#parseJson

```java
record User(@JsonProperty("username") String username) {
}

void main() {
HalFormsBody<User> halFormsBody = HalFormsBodies.parseJson(json);
}
```

## Custom Jackson JsonMapper

```java
record User(@JsonProperty("username") String username) {
}

void main() {
JsonMapper jsonMapper = JsonMapper.builder().addModule(new HalModelJacksonModule()).build();
HalFormsBody<User> halFormsBody = jsonMapper.readValue(json, new TypeReference<>() {
});
}
```

# Atomic representation parsing

```json
{
"username" : "jdoe",
"_links" : {
"self" : {
"href" : "http://localhost/self"
"username": "jdoe",
"_links": {
"self": {
"href": "http://localhost/self"
}
},
"_templates" : {
"default" : {
"method" : "PUT",
"properties" : [ {
"name" : "foo"
} ]
"_templates": {
"default": {
"method": "PUT",
"properties": [
{
"name": "foo"
}
]
}
}
}
```

```java
record User(@JsonProperty("username") String username) {}
record User(@JsonProperty("username") String username) {
}

void main() {
JsonMapper jsonMapper = JsonMapper.builder().addModule(new HalModelJacksonModule()).build();
HalFormsBody<User> halFormsBody = jsonMapper.readValue(json, new TypeReference<>() {});
assertThat(halFormsBody.representation().username()).isEqualTo("jdoe");
assertThat(halFormsBody.linkByName()).containsOnlyKeys("self");
assertThat(halFormsBody.requireLink("self").href().expand())
.isEqualTo("http://localhost/self");
assertThat(halFormsBody.requireSelfUri()).isEqualTo("http://localhost/self");

assertThat(halFormsBody.templateByKey()).containsOnlyKeys("default");

TemplateRepresentation template = halFormsBody.requireTemplate("default");
assertThat(template.method()).isEqualTo("PUT");
assertThat(template.propertyByName()).containsOnlyKeys("foo");

TemplatePropertyRepresentation property = template.propertyByName().get("foo");
assertThat(property.type()).isEqualTo("text");
HalFormsBody<User> halFormsBody = HalFormsBodies.parseJson(json);
assertThat(halFormsBody.representation().username()).isEqualTo("jdoe");
assertThat(halFormsBody.linkByName()).containsOnlyKeys("self");
assertThat(halFormsBody.requireLink("self").href().expand())
.isEqualTo("http://localhost/self");
assertThat(halFormsBody.requireSelfUri()).isEqualTo("http://localhost/self");

assertThat(halFormsBody.templateByKey()).containsOnlyKeys("default");

TemplateRepresentation template = halFormsBody.requireTemplate("default");
assertThat(template.method()).isEqualTo("PUT");
assertThat(template.propertyByName()).containsOnlyKeys("foo");

TemplatePropertyRepresentation property = template.propertyByName().get("foo");
assertThat(property.type()).isEqualTo("text");
}
```

# Collection representation parsing

```json
{
"_embedded" : {
"content" : [ "element1", "element2" ]
"_embedded": {
"content": [
"element1",
"element2"
]
},
"_links" : {
"self" : {
"href" : "http://localhost/self"
"_links": {
"self": {
"href": "http://localhost/self"
}
},
"_templates" : {
"default" : {
"method" : "PUT",
"properties" : [ {
"name" : "foo"
} ]
"_templates": {
"default": {
"method": "PUT",
"properties": [
{
"name": "foo"
}
]
}
}
}
```

```java
record ContentList<T>(@JsonProperty("content") @Nullable List<T> content) {}
record ContentList<T>(@JsonProperty("content") @Nullable List<T> content) {
}

void main() {
JsonMapper jsonMapper = JsonMapper.builder().addModule(new HalModelJacksonModule()).build();
HalFormsBody<EmbeddedContainer<ContentList<String>>> halFormsBody =
JSON_MAPPER.readValue(json, new TypeReference<>() {});
assertThat(halFormsBody.representation().requireEmbedded().content())
.containsExactly("element1", "element2");
assertThat(halFormsBody.linkByName()).containsOnlyKeys("self");
assertThat(halFormsBody.requireLink("self").href().expand())
.isEqualTo("http://localhost/self");

assertThat(halFormsBody.templateByKey()).containsOnlyKeys("default");

TemplateRepresentation template = halFormsBody.requireTemplate("default");
assertThat(template.method()).isEqualTo("PUT");
assertThat(template.propertyByName()).containsOnlyKeys("foo");

TemplatePropertyRepresentation property = template.propertyByName().get("foo");
assertThat(property.type()).isEqualTo("text");
HalFormsBody<EmbeddedContainer<ContentList<String>>> halFormsBody = HalFormsBodies.parseJson(json);
assertThat(halFormsBody.representation().requireEmbedded().content())
.containsExactly("element1", "element2");
assertThat(halFormsBody.linkByName()).containsOnlyKeys("self");
assertThat(halFormsBody.requireLink("self").href().expand())
.isEqualTo("http://localhost/self");

assertThat(halFormsBody.templateByKey()).containsOnlyKeys("default");

TemplateRepresentation template = halFormsBody.requireTemplate("default");
assertThat(template.method()).isEqualTo("PUT");
assertThat(template.propertyByName()).containsOnlyKeys("foo");

TemplatePropertyRepresentation property = template.propertyByName().get("foo");
assertThat(property.type()).isEqualTo("text");
}
```

# Dependencies

```
- [Jackson 3](https://github.com/fasterxml/jackson)
- [JSpecify](https://jspecify.dev/)
- [Handy-URI-Templates](https://github.com/damnhandy/Handy-URI-Templates)
19 changes: 19 additions & 0 deletions src/main/java/com/cosium/hal_model2/HalFormsBodies.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.cosium.hal_model2;

import tools.jackson.core.type.TypeReference;
import tools.jackson.databind.json.JsonMapper;

/**
* @author Réda Housni Alaoui
*/
public class HalFormsBodies {

private static final JsonMapper JSON_MAPPER =
JsonMapper.builder().addModule(new HalModelJacksonModule()).build();

private HalFormsBodies() {}

public static <T> HalFormsBody<T> parseJson(String json) {
return JSON_MAPPER.readValue(json, new TypeReference<>() {});
}
}
1 change: 1 addition & 0 deletions src/main/java/com/cosium/hal_model2/HalFormsBody.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* @author Réda Housni Alaoui
*/
public class HalFormsBody<T> {

private final T representation;
private final Map<String, Link> linkByName;
private final @Nullable String selfUri;
Expand Down
Loading