Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ public interface JSONAPISpecConstants {
String ERRORS = "errors";
String META = "meta";
String HREF = "href";
String PREV = "prev";
String NEXT = "next";
String FIRST = "first";
String LAST = "last";
}
44 changes: 44 additions & 0 deletions src/main/java/com/github/jasminb/jsonapi/Link.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.github.jasminb.jsonapi;

import java.util.Collections;
import java.util.Map;

/**
* Models a JSON API Link object.
*/
public class Link {

private String href;

private Map<String, ?> meta = Collections.emptyMap();

public Link() {

}

public Link(String href) {
this.href = href;
}

public Link(String href, Map<String, ?> meta) {
this.href = href;
this.meta = meta;
}

public String getHref() {
return href;
}

public void setHref(String href) {
this.href = href;
}

public Map<String, ?> getMeta() {
return meta;
}

public void setMeta(Map<String, ?> meta) {
this.meta = meta;
}

}
99 changes: 96 additions & 3 deletions src/main/java/com/github/jasminb/jsonapi/ResourceConverter.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package com.github.jasminb.jsonapi;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.github.jasminb.jsonapi.annotations.Id;
import com.github.jasminb.jsonapi.annotations.Meta;
import com.github.jasminb.jsonapi.annotations.Relationship;
Expand Down Expand Up @@ -198,7 +203,7 @@ public <T> T readObject(byte [] data, Class<T> clazz) {
* @return collection of converted elements
* @throws RuntimeException in case conversion fails
*/
public <T> List<T> readObjectCollection(byte [] data, Class<T> clazz) {
public <T> ResourceList<T> readObjectCollection(byte [] data, Class<T> clazz) {

try {
JsonNode rootNode = objectMapper.readTree(data);
Expand All @@ -216,14 +221,25 @@ public <T> List<T> readObjectCollection(byte [] data, Class<T> clazz) {
result.add(pojo);
}

return result;
ResourceList<T> wrapper = new ResourceList<>(result);

if (rootNode.has(LINKS)) {
Map<String, Link> links = mapLinks(rootNode.get(LINKS));
wrapper.setLinks(links);
}

if (rootNode.has(META)) {
Map<String, ?> meta = mapMeta(rootNode.get(META));
wrapper.setMeta(meta);
}

return wrapper;
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}


}

/**
Expand Down Expand Up @@ -394,6 +410,62 @@ private void handleRelationships(JsonNode source, Object object, Map<String, Obj
}
}

/**
* Deserializes a <a href="http://jsonapi.org/format/#document-links">JSON-API links object</a> to a {@code Map}
* keyed by the link name.
* <p>
* The {@code linksObject} may represent links in string form or object form; both are supported by this method.
* </p>
* <p>
* E.g.
* <pre>
* "links": {
* "self": "http://example.com/posts"
* }
* </pre>
* </p>
* <p>
* or
* <pre>
* "links": {
* "related": {
* "href": "http://example.com/articles/1/comments",
* "meta": {
* "count": 10
* }
* }
* }
* </pre>
* </p>
*
* @param linksObject a {@code JsonNode} representing a links object
* @return a {@code Map} keyed by link name
*/
private Map<String, Link> mapLinks(JsonNode linksObject) {
Map<String, Link> result = new HashMap<>();

Iterator<Map.Entry<String, JsonNode>> linkItr = linksObject.fields();

while (linkItr.hasNext()) {
Map.Entry<String, JsonNode> linkNode = linkItr.next();
Link linkObj = new Link();

linkObj.setHref(
getLink(
linkNode.getValue()));

if (linkNode.getValue().has(META)) {
linkObj.setMeta(
mapMeta(
linkNode.getValue().get(META)));
}

result.put(linkNode.getKey(), linkObj);
}

return result;
}

/**
* Accepts a JsonNode which encapsulates a link. The link may be represented as a simple string or as
* <a href="http://jsonapi.org/format/#document-links">link</a> object. This method introspects on the
Expand All @@ -413,6 +485,27 @@ private String getLink(JsonNode linkNode) {
return linkNode.asText();
}

/**
* Deserializes a <a href="http://jsonapi.org/format/#document-meta">JSON-API meta object</a> to a {@code Map}
* keyed by the member names. Because {@code meta} objects contain arbitrary information, the values in the
* map are of unknown type.
*
* @param metaNode a JsonNode representing a meta object
* @return a Map of the meta information, keyed by member name.
*/
private Map<String, ?> mapMeta(JsonNode metaNode) {
JsonParser p = objectMapper.treeAsTokens(metaNode);
MapType mapType = TypeFactory.defaultInstance()
.constructMapType(HashMap.class, String.class, Object.class);
try {
return objectMapper.readValue(p, mapType);
} catch (IOException e) {
// TODO: log? No recovery.
}

return null;
}

/**
* Creates relationship object by consuming provided 'data' node.
* @param relationshipDataNode relationship data node
Expand Down
Loading