diff --git a/src/main/java/org/springframework/hateoas/RenderSingleLinks.java b/src/main/java/org/springframework/hateoas/RenderSingleLinks.java deleted file mode 100644 index a369e68f..00000000 --- a/src/main/java/org/springframework/hateoas/RenderSingleLinks.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2017 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; - -/** - * Whether to render a single {@link Link} as either a single entry or a collection. - */ -public enum RenderSingleLinks { - - /** - * A single {@link Link} is rendered as a JSON object. - */ - AS_SINGLE, - - /** - * A single {@link Link} is rendered as a JSON Array. - */ - AS_ARRAY -} diff --git a/src/main/java/org/springframework/hateoas/config/EnableHypermediaSupport.java b/src/main/java/org/springframework/hateoas/config/EnableHypermediaSupport.java index 3a64f190..43526c02 100644 --- a/src/main/java/org/springframework/hateoas/config/EnableHypermediaSupport.java +++ b/src/main/java/org/springframework/hateoas/config/EnableHypermediaSupport.java @@ -25,7 +25,6 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Import; import org.springframework.hateoas.EntityLinks; import org.springframework.hateoas.LinkDiscoverer; -import org.springframework.hateoas.RenderSingleLinks; /** * Activates hypermedia support in the {@link ApplicationContext}. Will register infrastructure beans available for diff --git a/src/main/java/org/springframework/hateoas/config/HypermediaSupportBeanDefinitionRegistrar.java b/src/main/java/org/springframework/hateoas/config/HypermediaSupportBeanDefinitionRegistrar.java index 6fb1ff4d..1cb30c49 100644 --- a/src/main/java/org/springframework/hateoas/config/HypermediaSupportBeanDefinitionRegistrar.java +++ b/src/main/java/org/springframework/hateoas/config/HypermediaSupportBeanDefinitionRegistrar.java @@ -28,6 +28,7 @@ import java.util.Map; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.config.BeanDefinition; @@ -46,7 +47,6 @@ import org.springframework.hateoas.EntityLinks; import org.springframework.hateoas.LinkDiscoverer; import org.springframework.hateoas.LinkDiscoverers; import org.springframework.hateoas.RelProvider; -import org.springframework.hateoas.RenderSingleLinks; import org.springframework.hateoas.ResourceSupport; import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType; import org.springframework.hateoas.core.AnnotationRelProvider; @@ -91,8 +91,8 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe private static final boolean EVO_PRESENT = ClassUtils.isPresent("org.atteo.evo.inflector.English", null); private final ImportBeanDefinitionRegistrar linkBuilderBeanDefinitionRegistrar = new LinkBuilderBeanDefinitionRegistrar(); - - private BeanFactory beanFactory; + + private ListableBeanFactory beanFactory; /* * (non-Javadoc) @@ -130,14 +130,9 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe registerSourcedBeanDefinition(builder, metadata, registry); } - try { - this.beanFactory.getBean(HalConfiguration.class); - } catch (BeansException e) { - - // If no HalConfiguration bean, create a default one. - BeanDefinitionBuilder defaultHalConfiguration = rootBeanDefinition(HalConfiguration.class); - defaultHalConfiguration.addPropertyValue("renderSingleLinks", RenderSingleLinks.AS_SINGLE); - registerSourcedBeanDefinition(defaultHalConfiguration, metadata, registry); + // If no HalConfiguration bean, create a default one. + if (this.beanFactory.getBeanNamesForType(HalConfiguration.class).length == 0) { + registerSourcedBeanDefinition(rootBeanDefinition(HalConfiguration.class), metadata, registry); } } @@ -159,7 +154,7 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; + this.beanFactory = (ListableBeanFactory) beanFactory; } /** diff --git a/src/main/java/org/springframework/hateoas/hal/HalConfiguration.java b/src/main/java/org/springframework/hateoas/hal/HalConfiguration.java index 837832db..846c4b60 100644 --- a/src/main/java/org/springframework/hateoas/hal/HalConfiguration.java +++ b/src/main/java/org/springframework/hateoas/hal/HalConfiguration.java @@ -15,21 +15,34 @@ */ package org.springframework.hateoas.hal; +import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.Setter; import lombok.experimental.Wither; -import org.springframework.hateoas.HypermediaConfiguration; -import org.springframework.hateoas.RenderSingleLinks; +import org.springframework.hateoas.Link; /** * @author Greg Turnquist + * @author Oliver Gierke */ -@AllArgsConstructor @NoArgsConstructor -public class HalConfiguration implements HypermediaConfiguration { +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class HalConfiguration { - private @Wither @Getter @Setter RenderSingleLinks renderSingleLinks; + private @Wither @Getter RenderSingleLinks renderSingleLinks = RenderSingleLinks.AS_SINGLE; + + public enum RenderSingleLinks { + + /** + * A single {@link Link} is rendered as a JSON object. + */ + AS_SINGLE, + + /** + * A single {@link Link} is rendered as a JSON Array. + */ + AS_ARRAY + } } diff --git a/src/main/java/org/springframework/hateoas/hal/Jackson2HalModule.java b/src/main/java/org/springframework/hateoas/hal/Jackson2HalModule.java index 071864e6..f15643f2 100644 --- a/src/main/java/org/springframework/hateoas/hal/Jackson2HalModule.java +++ b/src/main/java/org/springframework/hateoas/hal/Jackson2HalModule.java @@ -32,10 +32,10 @@ import org.springframework.context.support.MessageSourceAccessor; import org.springframework.hateoas.Link; import org.springframework.hateoas.Links; import org.springframework.hateoas.RelProvider; -import org.springframework.hateoas.RenderSingleLinks; import org.springframework.hateoas.Resource; import org.springframework.hateoas.ResourceSupport; import org.springframework.hateoas.Resources; +import org.springframework.hateoas.hal.HalConfiguration.RenderSingleLinks; import org.springframework.util.Assert; import com.fasterxml.jackson.annotation.JsonInclude; @@ -126,7 +126,8 @@ public class Jackson2HalModule extends SimpleModule { private final MessageSourceAccessor accessor; private final HalConfiguration halConfiguration; - public HalLinkListSerializer(CurieProvider curieProvider, EmbeddedMapper mapper, MessageSourceAccessor accessor, HalConfiguration halConfiguration) { + public HalLinkListSerializer(CurieProvider curieProvider, EmbeddedMapper mapper, MessageSourceAccessor accessor, + HalConfiguration halConfiguration) { this(null, curieProvider, mapper, accessor, halConfiguration); } @@ -201,7 +202,8 @@ public class Jackson2HalModule extends SimpleModule { JavaType mapType = typeFactory.constructMapType(HashMap.class, keyType, valueType); MapSerializer serializer = MapSerializer.construct(new String[] {}, mapType, true, null, - provider.findKeySerializer(keyType, null), new OptionalListJackson2Serializer(property, halConfiguration), null); + provider.findKeySerializer(keyType, null), new OptionalListJackson2Serializer(property, halConfiguration), + null); serializer.serialize(sortedLinks, jgen, provider); } @@ -430,8 +432,7 @@ public class Jackson2HalModule extends SimpleModule { * @see com.fasterxml.jackson.databind.ser.std.StdSerializer#serialize(java.lang.Object, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider) */ @Override - public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) - throws IOException { + public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException { List list = (List) value; @@ -695,12 +696,14 @@ public class Jackson2HalModule extends SimpleModule { this(provider, curieProvider, accessor, true, beanFactory, halConfiguration); } - public HalHandlerInstantiator(RelProvider provider, CurieProvider curieProvider, MessageSourceAccessor messageSourceAccessor, AutowireCapableBeanFactory beanFactory) { + public HalHandlerInstantiator(RelProvider provider, CurieProvider curieProvider, + MessageSourceAccessor messageSourceAccessor, AutowireCapableBeanFactory beanFactory) { this(provider, curieProvider, messageSourceAccessor, beanFactory, beanFactory.getBean(HalConfiguration.class)); } - public HalHandlerInstantiator(RelProvider provider, CurieProvider curieProvider, MessageSourceAccessor messageSourceAccessor) { - this(provider, curieProvider, messageSourceAccessor, new HalConfiguration().withRenderSingleLinks(RenderSingleLinks.AS_SINGLE)); + public HalHandlerInstantiator(RelProvider provider, CurieProvider curieProvider, + MessageSourceAccessor messageSourceAccessor) { + this(provider, curieProvider, messageSourceAccessor, new HalConfiguration()); } /** @@ -743,7 +746,8 @@ public class Jackson2HalModule extends SimpleModule { this.delegate = delegate; this.serializers.put(HalResourcesSerializer.class, new HalResourcesSerializer(mapper)); - this.serializers.put(HalLinkListSerializer.class, new HalLinkListSerializer(curieProvider, mapper, accessor, halConfiguration)); + this.serializers.put(HalLinkListSerializer.class, + new HalLinkListSerializer(curieProvider, mapper, accessor, halConfiguration)); } /* diff --git a/src/test/java/org/springframework/hateoas/config/EnableHypermediaSupportIntegrationTest.java b/src/test/java/org/springframework/hateoas/config/EnableHypermediaSupportIntegrationTest.java index 0beec7a4..ff629b68 100644 --- a/src/test/java/org/springframework/hateoas/config/EnableHypermediaSupportIntegrationTest.java +++ b/src/test/java/org/springframework/hateoas/config/EnableHypermediaSupportIntegrationTest.java @@ -17,6 +17,7 @@ package org.springframework.hateoas.config; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; +import static org.springframework.hateoas.hal.HalConfiguration.RenderSingleLinks.*; import java.lang.reflect.Method; import java.util.List; @@ -37,7 +38,6 @@ import org.springframework.hateoas.LinkDiscoverer; import org.springframework.hateoas.LinkDiscoverers; import org.springframework.hateoas.MediaTypes; import org.springframework.hateoas.RelProvider; -import org.springframework.hateoas.RenderSingleLinks; import org.springframework.hateoas.ResourceSupport; import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType; import org.springframework.hateoas.config.HypermediaSupportBeanDefinitionRegistrar.Jackson2ModuleRegisteringBeanPostProcessor; @@ -99,8 +99,7 @@ public class EnableHypermediaSupportIntegrationTest { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(HalConfig.class); - Jackson2ModuleRegisteringBeanPostProcessor postProcessor = - new HypermediaSupportBeanDefinitionRegistrar.Jackson2ModuleRegisteringBeanPostProcessor(); + Jackson2ModuleRegisteringBeanPostProcessor postProcessor = new HypermediaSupportBeanDefinitionRegistrar.Jackson2ModuleRegisteringBeanPostProcessor(); postProcessor.setBeanFactory(context.getAutowireCapableBeanFactory()); RequestMappingHandlerAdapter adapter = context.getBean(RequestMappingHandlerAdapter.class); @@ -165,25 +164,23 @@ public class EnableHypermediaSupportIntegrationTest { ResourceSupport resourceSupport = new ResourceSupport(); resourceSupport.add(new Link("localhost").withSelfRel()); - assertThat(mapper.writeValueAsString(resourceSupport), - is("{\"_links\":{\"self\":{\"href\":\"localhost\"}}}")); + assertThat(mapper.writeValueAsString(resourceSupport), is("{\"_links\":{\"self\":{\"href\":\"localhost\"}}}")); context.close(); } - @Test public void verifyRenderSingleLinkAsArrayViaOverridingBean() throws JsonProcessingException { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(RenderLinkAsSingleLinksConfig.class); + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( + RenderLinkAsSingleLinksConfig.class); ObjectMapper mapper = context.getBean("_halObjectMapper", ObjectMapper.class); ResourceSupport resourceSupport = new ResourceSupport(); resourceSupport.add(new Link("localhost").withSelfRel()); - assertThat(mapper.writeValueAsString(resourceSupport), - is("{\"_links\":{\"self\":[{\"href\":\"localhost\"}]}}")); + assertThat(mapper.writeValueAsString(resourceSupport), is("{\"_links\":{\"self\":[{\"href\":\"localhost\"}]}}")); context.close(); } @@ -273,13 +270,12 @@ public class EnableHypermediaSupportIntegrationTest { @Bean HalConfiguration halConfiguration() { - return new HalConfiguration().withRenderSingleLinks(RenderSingleLinks.AS_ARRAY); + return new HalConfiguration().withRenderSingleLinks(AS_ARRAY); } @Bean public RequestMappingHandlerAdapter rmh() { return new RequestMappingHandlerAdapter(); } - } } diff --git a/src/test/java/org/springframework/hateoas/hal/Jackson2HalIntegrationTest.java b/src/test/java/org/springframework/hateoas/hal/Jackson2HalIntegrationTest.java index e5e18bd2..ac59acc6 100644 --- a/src/test/java/org/springframework/hateoas/hal/Jackson2HalIntegrationTest.java +++ b/src/test/java/org/springframework/hateoas/hal/Jackson2HalIntegrationTest.java @@ -27,7 +27,6 @@ import java.util.Locale; import org.junit.Before; import org.junit.Test; - import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.context.support.MessageSourceAccessor; @@ -37,13 +36,13 @@ import org.springframework.hateoas.Link; import org.springframework.hateoas.Links; import org.springframework.hateoas.PagedResources; import org.springframework.hateoas.PagedResources.PageMetadata; -import org.springframework.hateoas.RenderSingleLinks; import org.springframework.hateoas.Resource; import org.springframework.hateoas.ResourceSupport; import org.springframework.hateoas.Resources; import org.springframework.hateoas.UriTemplate; import org.springframework.hateoas.core.AnnotationRelProvider; import org.springframework.hateoas.core.EmbeddedWrappers; +import org.springframework.hateoas.hal.HalConfiguration.RenderSingleLinks; import org.springframework.hateoas.hal.Jackson2HalModule.HalHandlerInstantiator; import com.fasterxml.jackson.databind.ObjectMapper; @@ -82,12 +81,13 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg static final String SINGLE_WITH_ONE_EXTRA_ATTRIBUTES = "{\"_links\":{\"self\":{\"href\":\"localhost\",\"title\":\"the title\"}}}"; static final String SINGLE_WITH_ALL_EXTRA_ATTRIBUTES = "{\"_links\":{\"self\":{\"href\":\"localhost\",\"hreflang\":\"en\",\"title\":\"the title\",\"type\":\"the type\",\"deprecation\":\"/customers/deprecated\"}}}"; - + @Before public void setUpModule() { mapper.registerModule(new Jackson2HalModule()); - mapper.setHandlerInstantiator(new HalHandlerInstantiator(new AnnotationRelProvider(), null, null, new HalConfiguration().withRenderSingleLinks(RenderSingleLinks.AS_SINGLE))); + mapper.setHandlerInstantiator( + new HalHandlerInstantiator(new AnnotationRelProvider(), null, null, new HalConfiguration())); } /** @@ -109,12 +109,12 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg public void rendersAllExtraRFC5988Attributes() throws Exception { ResourceSupport resourceSupport = new ResourceSupport(); - resourceSupport.add(new Link("localhost", "self") - .withHreflang("en") - .withTitle("the title") - .withType("the type") - .withMedia("the media") - .withDeprecation("/customers/deprecated")); + resourceSupport.add(new Link("localhost", "self") // + .withHreflang("en") // + .withTitle("the title") // + .withType("the type") // + .withMedia("the media") // + .withDeprecation("/customers/deprecated")); assertThat(write(resourceSupport), is(SINGLE_WITH_ALL_EXTRA_ATTRIBUTES)); } @@ -123,8 +123,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg public void rendersWithOneExtraRFC5988Attribute() throws Exception { ResourceSupport resourceSupport = new ResourceSupport(); - resourceSupport.add(new Link("localhost", "self") - .withTitle("the title")); + resourceSupport.add(new Link("localhost", "self").withTitle("the title")); assertThat(write(resourceSupport), is(SINGLE_WITH_ONE_EXTRA_ATTRIBUTES)); } @@ -415,7 +414,8 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg @Test public void rendersSingleLinkAsArrayWhenConfigured() throws Exception { - mapper.setHandlerInstantiator(new HalHandlerInstantiator(new AnnotationRelProvider(), null, null, new HalConfiguration().withRenderSingleLinks(RenderSingleLinks.AS_ARRAY))); + mapper.setHandlerInstantiator(new HalHandlerInstantiator(new AnnotationRelProvider(), null, null, + new HalConfiguration().withRenderSingleLinks(RenderSingleLinks.AS_ARRAY))); ResourceSupport resourceSupport = new ResourceSupport(); resourceSupport.add(new Link("localhost").withSelfRel());