Skip to content

Commit

Permalink
added default serializers
Browse files Browse the repository at this point in the history
  • Loading branch information
nrktkt committed Jan 21, 2016
1 parent 15f13c3 commit 587d5e8
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 16 deletions.
129 changes: 129 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,132 @@ HATEOAS with HAL for Java
[![Build Status](https://travis-ci.org/blackdoor/hate.svg)](https://travis-ci.org/blackdoor/hate)
[![Codacy Badge](https://api.codacy.com/project/badge/grade/7c1d6531e44941ed9e48b75435c9f1b8)](https://www.codacy.com/app/nfischer921/hate)

---
## Basic usage

Implement the `HalResource` interface in your model by implementing the `location()` and `asEmbedded()` methods.
For example:

```java
public class Order implements HalResource{

private int id;
private double total;
private String currency;
private String status;
//note: Basket and Customer implement HalResource
private Basket basket;
private Customer customer;

...

@Override
public URI location(){
return new URI("/orders/" + id);
}

@Override
public HalRepresentation asEmbedded() {
return HalRepresentation.builder()
.addProperty("total", total)
.addProperty("currency", currency)
.addProperty("status", status)
.addLink("basket", basket)
.addLink("customer", customer)
.addLink("self", this)
.build();
}
}
```

Now to get the `HalRepresentation` of an `Order` object, simply do `HalRepresentation hal = myOrder.asEmbedded()`. You can serialize `hal` using `hal.serialize()` or with Jackson (eg. `new ObjectMapper.writeValueAsString(hal)`)

The result would look like this:

```json
{
"total": 30,
"currency": "USD",
"status": "shipped",
"_links": {
"basket": {
"href": "/baskets/97212"
},
"self": {
"href": "/orders/123"
},
"customer": {
"href": "/customers/7809"
}
}
}
```

## Paginated Collections

To get a paginated HAL representation of a REST collection, simply use `HalRepresentation.paginated(String, String, Stream, long, long)`.
For example:

```java
Collection<Order> orders;

HalRepresentation hal = HalRepresentation.paginated(
"orders", // the name of the resource collection
"/orders", // the path the resource collection can be found at
orders.stream(), // the resources
pageNumber,
pageSize // the number of resources per page
).build();
```

Would give you something like this:

```json
{
"_links": {
"next": {
"href": "/orders?page=2"
},
"self": {
"href": "/orders"
}
},
"_embedded": {
"orders": [
{
"total": 30,
"currency": "USD",
"status": "shipped",
"_links": {
"basket": {
"href": "/baskets/97212"
},
"self": {
"href": "/orders/123"
},
"customer": {
"href": "/customers/7809"
}
}
},
{
"total": 20,
"currency": "USD",
"status": "processing",
"_links": {
"basket": {
"href": "/baskets/97213"
},
"self": {
"href": "/orders/124"
},
"customer": {
"href": "/customers/12369"
}
}
}
]
}
}
```

10 changes: 10 additions & 0 deletions src/main/java/black/door/hate/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package black.door.hate;

/**
* Created by nfischer on 12/9/2015.
*/
public interface Constants {
String _links = "_links";
String _embedded = "_embedded";
String HAL_JSON_CONTENT_TYPE = "application/hal+json";
}
2 changes: 2 additions & 0 deletions src/main/java/black/door/hate/HalLink.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package black.door.hate;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Builder;
import lombok.Getter;
import lombok.NonNull;
Expand All @@ -12,6 +13,7 @@
*/
@Builder
@Getter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class HalLink {
@NonNull
private URI href;
Expand Down
26 changes: 14 additions & 12 deletions src/main/java/black/door/hate/HalRepresentation.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Getter;

import java.io.IOException;
Expand All @@ -19,19 +16,18 @@
import java.util.stream.Stream;

import static black.door.util.Misc.require;
import static black.door.hate.Constants.*;

/**
* Created by nfischer on 12/8/2015.
*/
@Getter
public class HalRepresentation {
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonSerialize(using = HalRepresentation.HalRepresentationSerializer.class)
public class HalRepresentation implements java.io.Serializable {
private static final ObjectWriter WRITER;
static {
ObjectMapper mapper = new ObjectMapper();
SimpleModule mod = new SimpleModule();
mod.addSerializer(HalRepresentation.class, new HalRepresentationSerializer());
mapper.registerModule(mod);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
WRITER = mapper.writer();
}

Expand Down Expand Up @@ -107,13 +103,13 @@ public void serialize(HalRepresentation halRepresentation,
links.putAll(halRepresentation.links);
links.putAll(halRepresentation.multiLinks);
if(!links.isEmpty())
jsonGenerator.writeObjectField("_links", links);
jsonGenerator.writeObjectField(_links, links);

Map<String, Object> embedded = new HashMap<>();
embedded.putAll(halRepresentation.embedded);
embedded.putAll(halRepresentation.multiEmbedded);
if(!embedded.isEmpty())
jsonGenerator.writeObjectField("_embedded", embedded);
jsonGenerator.writeObjectField(_embedded, embedded);

jsonGenerator.writeEndObject();
}
Expand All @@ -139,6 +135,12 @@ public HalRepresentationBuilder addProperty(String name, Object prop){
return this;
}

public HalRepresentationBuilder addProperties(JsonNode jax){
require(jax.isObject());
jax.fields().forEachRemaining(e -> addProperty(e.getKey(), e.getValue()));
return this;
}

private <T> void add(String name, HalResource res, Map<String, T> rs,
Map<String, Collection<T>> multiRs,
Function<HalResource, T> trans){
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package black.door.hate.example;

import black.door.hate.HalRepresentation;
import black.door.hate.HalResource;
import lombok.Getter;

/**
* Created by nfischer on 12/8/2015.
*/
public class Order extends Thing implements HalResource {
@Getter
public class Order extends Thing{

private double total;
private String currency;
Expand All @@ -24,6 +25,7 @@ public Order(long id, double total, String currency, String status,
this.customer = customer;
}


@Override
public HalRepresentation asEmbedded() {
return HalRepresentation.builder()
Expand All @@ -36,9 +38,9 @@ public HalRepresentation asEmbedded() {
.build();
}


@Override
protected String resName() {
return "orders";
}

}
12 changes: 11 additions & 1 deletion src/test/java/black/door/hate/example/OrdersTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,21 @@
import static black.door.util.Misc.list;

import black.door.hate.HalRepresentation;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.val;
import org.junit.Test;

import java.util.Map;


/**
* Created by nfischer on 12/8/2015.
*/
public class OrdersTest {

@Test
public void test() throws Exception{
val basket1 = new Basket(97212);
Expand All @@ -28,7 +34,11 @@ public void test() throws Exception{
.addProperty("shippedToday", 20)
.build();

JsonNode node = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL).valueToTree(orderz);
System.out.println(new ObjectMapper().writeValueAsString(node));

System.out.println(orderz.serialize());
}


}

0 comments on commit 587d5e8

Please sign in to comment.