From dd0f9e89056a041ea7913a83357e5a3ee33ba6ee Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 4 Jan 2016 17:17:14 +0100 Subject: [PATCH] #421 - DefaultCurieProvider now automatically prefixes URIs in case they're not absolute. DefaultCurieProvider now automatically adds the application URI (servlet mapping) in case the UriTemplate configured does not contain an absolute URI in the first place. --- .../hateoas/hal/DefaultCurieProvider.java | 53 ++++++++++++++----- .../hal/DefaultCurieProviderUnitTest.java | 30 ++++++++++- 2 files changed, 69 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/springframework/hateoas/hal/DefaultCurieProvider.java b/src/main/java/org/springframework/hateoas/hal/DefaultCurieProvider.java index 63ee94dc..aedf6f7a 100644 --- a/src/main/java/org/springframework/hateoas/hal/DefaultCurieProvider.java +++ b/src/main/java/org/springframework/hateoas/hal/DefaultCurieProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2016 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. @@ -15,9 +15,10 @@ */ package org.springframework.hateoas.hal; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -27,6 +28,7 @@ import org.springframework.hateoas.Links; import org.springframework.hateoas.UriTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; /** * Default implementation of {@link CurieProvider} rendering a single configurable {@link UriTemplate} based curie. @@ -37,8 +39,8 @@ import org.springframework.util.StringUtils; */ public class DefaultCurieProvider implements CurieProvider { - private final Map curies; - private final Curie defaultCurie; + private final Map curies; + private final String defaultCurie; /** * Creates a new {@link DefaultCurieProvider} for the given name and {@link UriTemplate}. The curie will be used to @@ -76,8 +78,6 @@ public class DefaultCurieProvider implements CurieProvider { Assert.notNull(curies, "Curies must not be null!"); - Map map = new HashMap(curies.size()); - for (Entry entry : curies.entrySet()) { String name = entry.getKey(); @@ -87,13 +87,11 @@ public class DefaultCurieProvider implements CurieProvider { Assert.notNull(template, "UriTemplate must not be null!"); Assert.isTrue(template.getVariableNames().size() == 1, String.format("Expected a single template variable in the UriTemplate %s!", template.toString())); - - map.put(name, new Curie(name, template.toString())); } - this.defaultCurie = StringUtils.hasText(defaultCurieName) ? map.get(defaultCurieName) - : map.size() == 1 ? map.values().iterator().next() : null; - this.curies = Collections.unmodifiableMap(map); + this.defaultCurie = StringUtils.hasText(defaultCurieName) ? defaultCurieName + : curies.size() == 1 ? curies.keySet().iterator().next() : null; + this.curies = Collections.unmodifiableMap(curies); } /* @@ -102,7 +100,18 @@ public class DefaultCurieProvider implements CurieProvider { */ @Override public Collection getCurieInformation(Links links) { - return Collections.unmodifiableCollection(curies.values()); + + List result = new ArrayList(curies.size()); + + for (Entry source : curies.entrySet()) { + + String name = source.getKey(); + UriTemplate template = source.getValue(); + + result.add(new Curie(name, getCurieHref(name, template))); + } + + return Collections.unmodifiableCollection(result); } /* @@ -122,7 +131,25 @@ public class DefaultCurieProvider implements CurieProvider { public String getNamespacedRelFor(String rel) { boolean prefixingNeeded = defaultCurie != null && !IanaRels.isIanaRel(rel) && !rel.contains(":"); - return prefixingNeeded ? String.format("%s:%s", defaultCurie.name, rel) : rel; + return prefixingNeeded ? String.format("%s:%s", defaultCurie, rel) : rel; + } + + /** + * Returns the href for the {@link Curie} instance to be created. Will prepend the current application URI (servlet + * mapping) in case the template is not an absolute one in the first place. + * + * @param name will never be {@literal null} or empty. + * @param template will never be {@literal null}. + * @return the {@link String} to be used as href in the {@link Curie} to be created, must not be {@literal null}. + */ + protected String getCurieHref(String name, UriTemplate template) { + + if (template.toString().startsWith("http")) { + return template.toString(); + } + + String applicationUri = ServletUriComponentsBuilder.fromCurrentServletMapping().build().expand().toString(); + return applicationUri.concat(template.toString()); } /** diff --git a/src/test/java/org/springframework/hateoas/hal/DefaultCurieProviderUnitTest.java b/src/test/java/org/springframework/hateoas/hal/DefaultCurieProviderUnitTest.java index 2c880beb..5e20279d 100644 --- a/src/test/java/org/springframework/hateoas/hal/DefaultCurieProviderUnitTest.java +++ b/src/test/java/org/springframework/hateoas/hal/DefaultCurieProviderUnitTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2016 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. @@ -18,6 +18,7 @@ package org.springframework.hateoas.hal; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; +import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -25,6 +26,10 @@ import org.junit.Test; import org.springframework.hateoas.Link; import org.springframework.hateoas.Links; import org.springframework.hateoas.UriTemplate; +import org.springframework.hateoas.hal.DefaultCurieProvider.Curie; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; /** * Unit tests for {@link DefaultCurieProvider}. @@ -125,6 +130,29 @@ public class DefaultCurieProviderUnitTest { assertThat(provider.getNamespacedRelFor("some"), is("foo:some")); } + /** + * #421 + */ + @Test + public void expandsNonAbsoluteUriWithApplicationUri() { + + DefaultCurieProvider provider = new DefaultCurieProvider("name", new UriTemplate("/docs/{rel}")); + + MockHttpServletRequest request = new MockHttpServletRequest(); + ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + + Links links = new Links(new Link("http://localhost", "name:foo")); + + Collection curies = provider.getCurieInformation(links); + assertThat(curies, hasSize(1)); + + Object curie = curies.iterator().next(); + assertThat(curie, is(instanceOf(Curie.class))); + + assertThat(((Curie) curie).getHref(), startsWith("http://localhost")); + } + private static Map getCuries() { Map curies = new HashMap(2);