#31 - Introduced LinkDiscoverer to extract Link instances from representations.
LinkDiscoverer exposes an API to find Links by their relation types in representations. Added JSONPath based base class and a DefaultLinkDiscoverer that finds Links based on the default rendering of our Jackson mappings.
This commit is contained in:
9
pom.xml
9
pom.xml
@@ -61,6 +61,8 @@
|
||||
<jackson1.version>1.9.10</jackson1.version>
|
||||
<jackson2.version>2.1.1</jackson2.version>
|
||||
<jaxrs.version>1.0</jaxrs.version>
|
||||
<jsonpath.version>0.8.1</jsonpath.version>
|
||||
<minidevjson.version>1.1.1</minidevjson.version>
|
||||
<bundlor.failOnWarnings>true</bundlor.failOnWarnings>
|
||||
</properties>
|
||||
|
||||
@@ -132,6 +134,13 @@
|
||||
<version>${jaxrs.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.jayway.jsonpath</groupId>
|
||||
<artifactId>json-path</artifactId>
|
||||
<version>${jsonpath.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interface to allow discovering links by relation type from some source.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface LinkDiscoverer {
|
||||
|
||||
/**
|
||||
* Finds a single link with the given relation type in the given {@link String} representation.
|
||||
*
|
||||
* @param rel must not be {@literal null} or empty.
|
||||
* @param representation must not be {@literal null} or empty.
|
||||
* @return the first link with the given relation type found, or {@literal null} if none was found.
|
||||
*/
|
||||
Link findLinkWithRel(String rel, String representation);
|
||||
|
||||
/**
|
||||
* Finds a single link with the given relation type in the given {@link InputStream} representation.
|
||||
*
|
||||
* @param rel must not be {@literal null} or empty.
|
||||
* @param representation must not be {@literal null} or empty.
|
||||
* @return the first link with the given relation type found, or {@literal null} if none was found.
|
||||
*/
|
||||
Link findLinkWithRel(String rel, InputStream representation);
|
||||
|
||||
/**
|
||||
* Returns all links with the given relation type found in the given {@link String} representation.
|
||||
*
|
||||
* @param rel must not be {@literal null} or empty.
|
||||
* @param representation must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
List<Link> findLinksWithRel(String rel, String representation);
|
||||
|
||||
/**
|
||||
* Returns all links with the given relation type found in the given {@link InputStream} representation.
|
||||
*
|
||||
* @param rel must not be {@literal null} or empty.
|
||||
* @param representation must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
List<Link> findLinksWithRel(String rel, InputStream representation);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas.core;
|
||||
|
||||
/**
|
||||
* {@link JsonPathLinkDiscoverer} based on the default link representation we expose.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class DefaultLinkDiscoverer extends JsonPathLinkDiscoverer {
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultLinkDiscoverer}.
|
||||
*/
|
||||
public DefaultLinkDiscoverer() {
|
||||
super("$links[?(@.rel == '%s')].href");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.minidev.json.JSONArray;
|
||||
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.LinkDiscoverer;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
|
||||
/**
|
||||
* {@link LinkDiscoverer} that uses {@link JsonPath} to find links inside a representation.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class JsonPathLinkDiscoverer implements LinkDiscoverer {
|
||||
|
||||
private final String pathTemplate;
|
||||
|
||||
/**
|
||||
* Creates a new {@link JsonPathLinkDiscoverer} using the given path template. The template has to contain a single
|
||||
* {@code %s} placeholder which will be replaced by the relation type.
|
||||
*
|
||||
* @param pathTemplate must not be {@literal null} or empty and contain a single placeholder.
|
||||
*/
|
||||
public JsonPathLinkDiscoverer(String pathTemplate) {
|
||||
|
||||
Assert.hasText(pathTemplate, "Path template must not be null!");
|
||||
Assert.isTrue(StringUtils.countOccurrencesOf(pathTemplate, "%s") == 1,
|
||||
"Path template must contain a single placeholder!");
|
||||
this.pathTemplate = pathTemplate;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.hateoas.LinkDiscoverer#findLinkWithRel(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Link findLinkWithRel(String rel, String representation) {
|
||||
|
||||
List<Link> links = findLinksWithRel(rel, representation);
|
||||
return links.isEmpty() ? null : links.get(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.hateoas.LinkDiscoverer#findLinkWithRel(java.lang.String, java.io.InputStream)
|
||||
*/
|
||||
@Override
|
||||
public Link findLinkWithRel(String rel, InputStream representation) {
|
||||
|
||||
List<Link> links = findLinksWithRel(rel, representation);
|
||||
return links.isEmpty() ? null : links.get(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.hateoas.LinkDiscoverer#findLinksWithRel(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public List<Link> findLinksWithRel(String rel, String representation) {
|
||||
|
||||
Object parseResult = getExpression(rel).read(representation);
|
||||
return createLinksFrom(parseResult, rel);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.hateoas.LinkDiscoverer#findLinksWithRel(java.lang.String, java.io.InputStream)
|
||||
*/
|
||||
@Override
|
||||
public List<Link> findLinksWithRel(String rel, InputStream representation) {
|
||||
|
||||
try {
|
||||
Object parseResult = getExpression(rel).read(representation);
|
||||
return createLinksFrom(parseResult, rel);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link JsonPath} to find links with the given relation type.
|
||||
*
|
||||
* @param rel
|
||||
* @return
|
||||
*/
|
||||
private JsonPath getExpression(String rel) {
|
||||
return JsonPath.compile(String.format(pathTemplate, rel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link Link} instances from the given parse result.
|
||||
*
|
||||
* @param parseResult the result originating from parsing the source content using the JSON path expression.
|
||||
* @param rel the relation type that was parsed for.
|
||||
* @return
|
||||
*/
|
||||
private List<Link> createLinksFrom(Object parseResult, String rel) {
|
||||
|
||||
if (parseResult instanceof JSONArray) {
|
||||
|
||||
List<Link> links = new ArrayList<Link>();
|
||||
JSONArray array = (JSONArray) parseResult;
|
||||
|
||||
for (Object element : array) {
|
||||
links.add(new Link(element.toString(), rel));
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(links);
|
||||
}
|
||||
|
||||
Link link = new Link(parseResult.toString(), rel);
|
||||
return Collections.unmodifiableList(Arrays.asList(link));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas.core;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.LinkDiscoverer;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultLinkDiscoverer}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class DefaultLinkDiscovererUnitTest {
|
||||
|
||||
static final String SAMPLE = "{ links : [ " + //
|
||||
"{ rel : 'self', href : 'selfHref' }, " + //
|
||||
"{ rel : 'relation', href : 'firstHref' }, " + //
|
||||
"{ rel : 'relation', href : 'secondHref' }]}";
|
||||
|
||||
static final LinkDiscoverer discoverer = new DefaultLinkDiscoverer();
|
||||
|
||||
@Test
|
||||
public void findsSingleLink() {
|
||||
|
||||
assertThat(discoverer.findLinkWithRel("self", SAMPLE), is(new Link("selfHref")));
|
||||
|
||||
List<Link> links = discoverer.findLinksWithRel("self", SAMPLE);
|
||||
assertThat(links, hasSize(1));
|
||||
assertThat(links, hasItem(new Link("selfHref")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findsFirstLink() {
|
||||
|
||||
assertThat(discoverer.findLinkWithRel("relation", SAMPLE), is(new Link("firstHref", "relation")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findsAllLinks() {
|
||||
|
||||
List<Link> links = discoverer.findLinksWithRel("relation", SAMPLE);
|
||||
assertThat(links, hasSize(2));
|
||||
assertThat(links, hasItems(new Link("firstHref", "relation"), new Link("secondHref", "relation")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnsForInexistingLink() {
|
||||
assertThat(discoverer.findLinkWithRel("something", SAMPLE), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnsForInxistingLinkFromInputStream() throws Exception {
|
||||
|
||||
InputStream inputStream = new ByteArrayInputStream(SAMPLE.getBytes("UTF-8"));
|
||||
assertThat(discoverer.findLinkWithRel("something", inputStream), is(nullValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas.core;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link JsonPathLinkDiscoverer}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class JsonPathLinkDiscovererUnitTests {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullPattern() {
|
||||
new JsonPathLinkDiscoverer(null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsPatternWithWithoutPlaceholder() {
|
||||
new JsonPathLinkDiscoverer("$links");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsPatternWithMultiplePlaceholders() {
|
||||
new JsonPathLinkDiscoverer("$links%s%s");
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,9 @@ Bundle-Vendor: SpringSource
|
||||
Bundle-ManifestVersion: 2
|
||||
Import-Template:
|
||||
com.fasterxml.jackson.*;version="${jackson2.version:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
com.jayway.jsonpath.*;version="${jsonpath.version:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
javax.ws.rs.*;version="${jaxrs.version:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
javax.xml.bind.*;version="0",
|
||||
net.minidev.json.*;version="${minidevjson.version:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
org.springframework.*;version="${spring.version:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
org.codehaus.jackson.*;version="${jackson1.version:[=.=.=,+1.0.0)}";resolution:=optional
|
||||
|
||||
Reference in New Issue
Block a user