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);