#128 - Severe refactoring regarding LinkDiscoverers.

The LinkDiscoverer interface is now a Plugin<MediaType> to allow selecting a discoverer per media type. We also provide a LinkDiscoverers wrapper around a PluginRegistry for easier injection.

Dropped DefaultLinkDiscoverer as the above mentioned changed prohibits the usage of a discoverer without a media type. Clients that previously used DefaultLinkDiscoverer should switch to JsonPathLinkDiscoverer with a custom JsonPath expression and media type.

@EnableHypermediaSupport now supports multiple HypermediaType values set to be able to set up support for multiple hypermedia formats. Admittedly, the only currently supported type is HAL but we prepare for the addition of other (e.g. Collection/JSON or the like). We changed the infrastructure setup taken care of by @EnableHypermediaSupport to not enrich all ObjectMapper instances with our HAL modules but explicitly register an ObjectMapper with the application context and then registering a custom MappingJackson(2)HttpMessageConverter with the HandlerAdapter instances present in the ApplicationContext. We skip the registration if an already registered MJ2HMC has an ObjectMapper already supporting the Spring HATEOAS mixins.

Removed some compiler warnings.
This commit is contained in:
Oliver Gierke
2013-12-18 10:34:19 +01:00
parent 9eacd07203
commit 137e7c390f
17 changed files with 356 additions and 151 deletions

View File

@@ -18,12 +18,15 @@ package org.springframework.hateoas;
import java.io.InputStream;
import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.plugin.core.Plugin;
/**
* Interface to allow discovering links by relation type from some source.
*
* @author Oliver Gierke
*/
public interface LinkDiscoverer {
public interface LinkDiscoverer extends Plugin<MediaType> {
/**
* Finds a single link with the given relation type in the given {@link String} representation.

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2013 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 org.springframework.http.MediaType;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.util.Assert;
/**
* Value object to wrap a {@link PluginRegistry} for {@link LinkDiscoverer} so that it's easier to inject them into
* clients wanting to lookup a {@link LinkDiscoverer} for a given {@link MediaTypes}.
*
* @author Oliver Gierke
*/
public class LinkDiscoverers {
private final PluginRegistry<LinkDiscoverer, MediaType> discoverers;
/**
* Creates a new {@link LinkDiscoverers} instance with the given {@link PluginRegistry}.
*
* @param discoverers must not be {@literal null}.
*/
public LinkDiscoverers(PluginRegistry<LinkDiscoverer, MediaType> discoverers) {
Assert.notNull(discoverers, "Registry of LinkDiscoverer must not be null!");
this.discoverers = discoverers;
}
/**
* Returns the {@link LinkDiscoverer} suitable for the given {@link MediaType}.
*
* @param mediaType
* @return
*/
public LinkDiscoverer getLinkDiscovererFor(MediaType mediaType) {
return discoverers.getPluginFor(mediaType);
}
/**
* Returns the {@link LinkDiscoverer} suitable for the given media type.
*
* @param mediaType
* @return
*/
public LinkDiscoverer getLinkDiscovererFor(String mediaType) {
return getLinkDiscovererFor(MediaType.valueOf(mediaType));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 the original author or authors.
* Copyright 2013 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.
@@ -13,19 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.hateoas.core;
package org.springframework.hateoas;
import org.springframework.http.MediaType;
/**
* {@link JsonPathLinkDiscoverer} based on the default link representation we expose.
* Constants for well-known hypermedia types.
*
* @author Oliver Gierke
*/
public class DefaultLinkDiscoverer extends JsonPathLinkDiscoverer {
public class MediaTypes {
/**
* Creates a new {@link DefaultLinkDiscoverer}.
*/
public DefaultLinkDiscoverer() {
super("$links[?(@.rel == '%s')].href");
}
public static final MediaType HAL_JSON = MediaType.valueOf("application/hal+json");
}

View File

@@ -54,7 +54,7 @@ public @interface EnableHypermediaSupport {
*
* @return
*/
HypermediaType type() default HypermediaType.DEFAULT;
HypermediaType[] type();
/**
* Hypermedia representation types supported.
@@ -63,8 +63,6 @@ public @interface EnableHypermediaSupport {
*/
static enum HypermediaType {
DEFAULT,
/**
* HAL - Hypermedia Application Language.
*

View File

@@ -15,8 +15,13 @@
*/
package org.springframework.hateoas.config;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*;
import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.*;
import static org.springframework.hateoas.MediaTypes.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -29,6 +34,7 @@ import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
@@ -36,10 +42,10 @@ import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.hateoas.EntityLinks;
import org.springframework.hateoas.LinkDiscoverer;
import org.springframework.hateoas.LinkDiscoverers;
import org.springframework.hateoas.RelProvider;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.hateoas.core.AnnotationRelProvider;
import org.springframework.hateoas.core.DefaultLinkDiscoverer;
import org.springframework.hateoas.core.DefaultRelProvider;
import org.springframework.hateoas.core.DelegatingRelProvider;
import org.springframework.hateoas.core.EvoInflectorRelProvider;
@@ -68,8 +74,9 @@ import com.fasterxml.jackson.databind.ObjectMapper;
@SuppressWarnings("deprecation")
class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
private static final String LINK_DISCOVERER_BEAN_NAME = "_linkDiscoverer";
private static final String DELEGATING_REL_PROVIDER_BEAN_NAME = "_relProvider";
private static final String LINK_DISCOVERER_REGISTRY_BEAN_NAME = "_linkDiscovererRegistry";
private static final String HAL_OBJECT_MAPPER_BEAN_NAME = "_halObjectMapper";
private static final boolean JACKSON1_PRESENT = ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper", null);
private static final boolean JACKSON2_PRESENT = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper",
@@ -84,30 +91,54 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe
* @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar#registerBeanDefinitions(org.springframework.core.type.AnnotationMetadata, org.springframework.beans.factory.support.BeanDefinitionRegistry)
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
linkBuilderBeanDefinitionRegistrar.registerBeanDefinitions(importingClassMetadata, registry);
linkBuilderBeanDefinitionRegistrar.registerBeanDefinitions(metadata, registry);
Map<String, Object> attributes = importingClassMetadata.getAnnotationAttributes(EnableHypermediaSupport.class
.getName());
HypermediaType type = (HypermediaType) attributes.get("type");
Map<String, Object> attributes = metadata.getAnnotationAttributes(EnableHypermediaSupport.class.getName());
Collection<HypermediaType> types = Arrays.asList((HypermediaType[]) attributes.get("type"));
if (JSONPATH_PRESENT) {
registerBeanDefinition(
new BeanDefinitionHolder(getLinkDiscovererBeanDefinition(type), LINK_DISCOVERER_BEAN_NAME), registry);
for (HypermediaType type : types) {
if (JSONPATH_PRESENT) {
AbstractBeanDefinition linkDiscovererBeanDefinition = getLinkDiscovererBeanDefinition(type);
registerBeanDefinition(
new BeanDefinitionHolder(linkDiscovererBeanDefinition, BeanDefinitionReaderUtils.generateBeanName(
linkDiscovererBeanDefinition, registry)), registry);
}
}
if (type == HypermediaType.HAL) {
if (types.contains(HypermediaType.HAL)) {
if (JACKSON2_PRESENT) {
registerWithGeneratedName(new RootBeanDefinition(Jackson2ModuleRegisteringBeanPostProcessor.class), registry);
BeanDefinitionBuilder halQueryMapperBuilder = rootBeanDefinition(ObjectMapper.class);
registerSourcedBeanDefinition(halQueryMapperBuilder, metadata, registry, HAL_OBJECT_MAPPER_BEAN_NAME);
BeanDefinitionBuilder builder = rootBeanDefinition(Jackson2ModuleRegisteringBeanPostProcessor.class);
registerSourcedBeanDefinition(builder, metadata, registry);
}
if (JACKSON1_PRESENT) {
registerWithGeneratedName(new RootBeanDefinition(Jackson1ModuleRegisteringBeanPostProcessor.class), registry);
BeanDefinitionBuilder builder = rootBeanDefinition(Jackson1ModuleRegisteringBeanPostProcessor.class);
registerSourcedBeanDefinition(builder, metadata, registry);
}
}
if (!types.isEmpty()) {
BeanDefinitionBuilder linkDiscoverersRegistryBuilder = BeanDefinitionBuilder
.rootBeanDefinition(PluginRegistryFactoryBean.class);
linkDiscoverersRegistryBuilder.addPropertyValue("type", LinkDiscoverer.class);
registerSourcedBeanDefinition(linkDiscoverersRegistryBuilder, metadata, registry,
LINK_DISCOVERER_REGISTRY_BEAN_NAME);
BeanDefinitionBuilder linkDiscoverersBuilder = BeanDefinitionBuilder.rootBeanDefinition(LinkDiscoverers.class);
linkDiscoverersBuilder.addConstructorArgReference(LINK_DISCOVERER_REGISTRY_BEAN_NAME);
registerSourcedBeanDefinition(linkDiscoverersBuilder, metadata, registry);
}
registerRelProviderPluginRegistryAndDelegate(registry);
}
@@ -156,15 +187,33 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe
case HAL:
definition = new RootBeanDefinition(HalLinkDiscoverer.class);
break;
case DEFAULT:
default:
definition = new RootBeanDefinition(DefaultLinkDiscoverer.class);
throw new IllegalStateException(String.format("Unsupported hypermedia type %s!", type));
}
definition.setSource(this);
return definition;
}
private static String registerSourcedBeanDefinition(BeanDefinitionBuilder builder, AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
String generateBeanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, registry);
return registerSourcedBeanDefinition(builder, metadata, registry, generateBeanName);
}
private static String registerSourcedBeanDefinition(BeanDefinitionBuilder builder, AnnotationMetadata metadata,
BeanDefinitionRegistry registry, String name) {
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
beanDefinition.setSource(metadata);
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, name);
registerBeanDefinition(holder, registry);
return name;
}
/**
* {@link BeanPostProcessor} to register {@link Jackson2HalModule} with {@link ObjectMapper} instances registered in
* the {@link ApplicationContext}.
@@ -173,7 +222,9 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe
*/
private static class Jackson2ModuleRegisteringBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
private BeanFactory factory;
private CurieProvider curieProvider;
private RelProvider relProvider;
private ObjectMapper halObjectMapper;
/*
* (non-Javadoc)
@@ -181,7 +232,10 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.factory = beanFactory;
this.curieProvider = getCurieProvider(beanFactory);
this.relProvider = beanFactory.getBean(DELEGATING_REL_PROVIDER_BEAN_NAME, RelProvider.class);
this.halObjectMapper = beanFactory.getBean(HAL_OBJECT_MAPPER_BEAN_NAME, ObjectMapper.class);
}
/*
@@ -201,39 +255,49 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
registerModule(((RequestMappingHandlerAdapter) bean).getMessageConverters());
RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter) bean;
adapter.setMessageConverters(potentiallyRegisterModule(adapter.getMessageConverters()));
}
if (bean instanceof AnnotationMethodHandlerAdapter) {
registerModule(((AnnotationMethodHandlerAdapter) bean).getMessageConverters());
}
if (bean instanceof ObjectMapper) {
registerModule(bean);
AnnotationMethodHandlerAdapter adapter = (AnnotationMethodHandlerAdapter) bean;
List<HttpMessageConverter<?>> augmentedConverters = potentiallyRegisterModule(Arrays
.asList(adapter.getMessageConverters()));
adapter
.setMessageConverters(augmentedConverters.toArray(new HttpMessageConverter<?>[augmentedConverters.size()]));
}
return bean;
}
private void registerModule(List<HttpMessageConverter<?>> converters) {
private List<HttpMessageConverter<?>> potentiallyRegisterModule(List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof MappingJackson2HttpMessageConverter) {
registerModule(((MappingJackson2HttpMessageConverter) converter).getObjectMapper());
MappingJackson2HttpMessageConverter halConverterCandidate = (MappingJackson2HttpMessageConverter) converter;
ObjectMapper objectMapper = halConverterCandidate.getObjectMapper();
if (Jackson2HalModule.isAlreadyRegisteredIn(objectMapper)) {
return converters;
}
}
}
halObjectMapper.registerModule(new Jackson2HalModule());
halObjectMapper.setHandlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(relProvider, curieProvider));
MappingJackson2HttpMessageConverter halConverter = new MappingJackson2HttpMessageConverter();
halConverter.setSupportedMediaTypes(Arrays.asList(HAL_JSON));
halConverter.setObjectMapper(halObjectMapper);
List<HttpMessageConverter<?>> result = new ArrayList<HttpMessageConverter<?>>(converters.size());
result.add(halConverter);
result.addAll(converters);
return result;
}
private void registerModule(Object objectMapper) {
RelProvider provider = factory.getBean(DELEGATING_REL_PROVIDER_BEAN_NAME, RelProvider.class);
ObjectMapper mapper = (ObjectMapper) objectMapper;
mapper.registerModule(new Jackson2HalModule());
mapper.setHandlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(provider, getCurieProvider()));
}
private CurieProvider getCurieProvider() {
private static CurieProvider getCurieProvider(BeanFactory factory) {
try {
return factory.getBean(CurieProvider.class);
@@ -252,7 +316,7 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe
@Deprecated
private static class Jackson1ModuleRegisteringBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
private BeanFactory beanFactory;
private RelProvider relProvider;
/*
* (non-Javadoc)
@@ -260,7 +324,7 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
this.relProvider = beanFactory.getBean(DELEGATING_REL_PROVIDER_BEAN_NAME, RelProvider.class);
}
/*
@@ -279,37 +343,39 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof AnnotationMethodHandlerAdapter) {
registerModule(((AnnotationMethodHandlerAdapter) bean).getMessageConverters());
}
if (bean instanceof RequestMappingHandlerAdapter) {
registerModule(((RequestMappingHandlerAdapter) bean).getMessageConverters());
RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter) bean;
adapter.setMessageConverters(registerModule(adapter.getMessageConverters()));
}
if (bean instanceof org.codehaus.jackson.map.ObjectMapper) {
registerModule(bean);
if (bean instanceof AnnotationMethodHandlerAdapter) {
AnnotationMethodHandlerAdapter adapter = (AnnotationMethodHandlerAdapter) bean;
List<HttpMessageConverter<?>> augmentedConverters = registerModule(Arrays
.asList(adapter.getMessageConverters()));
adapter
.setMessageConverters(augmentedConverters.toArray(new HttpMessageConverter<?>[augmentedConverters.size()]));
}
return bean;
}
private void registerModule(List<HttpMessageConverter<?>> converters) {
private List<HttpMessageConverter<?>> registerModule(List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof MappingJacksonHttpMessageConverter) {
registerModule(((MappingJacksonHttpMessageConverter) converter).getObjectMapper());
}
}
}
org.codehaus.jackson.map.ObjectMapper objectMapper = new org.codehaus.jackson.map.ObjectMapper();
private void registerModule(Object objectMapper) {
objectMapper.registerModule(new Jackson1HalModule());
objectMapper.setHandlerInstantiator(new Jackson1HalModule.HalHandlerInstantiator(relProvider));
RelProvider relProvider = beanFactory.getBean(DELEGATING_REL_PROVIDER_BEAN_NAME, RelProvider.class);
MappingJacksonHttpMessageConverter halConverter = new MappingJacksonHttpMessageConverter();
halConverter.setSupportedMediaTypes(Arrays.asList(HAL_JSON));
halConverter.setObjectMapper(objectMapper);
org.codehaus.jackson.map.ObjectMapper mapper = (org.codehaus.jackson.map.ObjectMapper) objectMapper;
mapper.registerModule(new Jackson1HalModule());
mapper.setHandlerInstantiator(new Jackson1HalModule.HalHandlerInstantiator(relProvider));
List<HttpMessageConverter<?>> result = new ArrayList<HttpMessageConverter<?>>(converters.size());
result.add(halConverter);
result.addAll(converters);
return result;
}
}
}

View File

@@ -26,6 +26,7 @@ import net.minidev.json.JSONArray;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkDiscoverer;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -39,19 +40,23 @@ import com.jayway.jsonpath.JsonPath;
public class JsonPathLinkDiscoverer implements LinkDiscoverer {
private final String pathTemplate;
private final MediaType mediaType;
/**
* 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.
* Creates a new {@link JsonPathLinkDiscoverer} using the given path template supporting the given {@link MediaType}.
* 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.
* @param mediaType the {@link MediaType} to support.
*/
public JsonPathLinkDiscoverer(String pathTemplate) {
public JsonPathLinkDiscoverer(String pathTemplate, MediaType mediaType) {
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;
this.mediaType = mediaType;
}
/*
@@ -136,4 +141,13 @@ public class JsonPathLinkDiscoverer implements LinkDiscoverer {
Link link = new Link(parseResult.toString(), rel);
return Collections.unmodifiableList(Arrays.asList(link));
}
/*
* (non-Javadoc)
* @see org.springframework.plugin.core.Plugin#supports(java.lang.Object)
*/
@Override
public boolean supports(MediaType delimiter) {
return this.mediaType == null ? true : this.mediaType.isCompatibleWith(delimiter);
}
}

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.hateoas.hal;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.LinkDiscoverer;
import org.springframework.hateoas.core.JsonPathLinkDiscoverer;
@@ -26,6 +27,6 @@ import org.springframework.hateoas.core.JsonPathLinkDiscoverer;
public class HalLinkDiscoverer extends JsonPathLinkDiscoverer {
public HalLinkDiscoverer() {
super("$_links..%s.href");
super("$_links..%s.href", MediaTypes.HAL_JSON);
}
}

View File

@@ -48,6 +48,7 @@ import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
@@ -83,6 +84,18 @@ public class Jackson2HalModule extends SimpleModule {
setMixInAnnotation(Resources.class, ResourcesMixin.class);
}
/**
* Returns whether the module was already registered in the given {@link ObjectMapper}.
*
* @param mapper must not be {@literal null}.
* @return
*/
public static boolean isAlreadyRegisteredIn(ObjectMapper mapper) {
Assert.notNull(mapper, "ObjectMapper must not be null!");
return LinkMixin.class.equals(mapper.findMixInClassFor(Link.class));
}
/**
* Custom {@link JsonSerializer} to render Link instances in HAL compatible JSON.
*

View File

@@ -22,15 +22,22 @@ import javax.xml.bind.annotation.XmlElement;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.ResourceSupport;
@SuppressWarnings("deprecation")
abstract class ResourceSupportMixin extends ResourceSupport {
@Override
@XmlElement(name = "link")
@org.codehaus.jackson.annotate.JsonProperty("_links")
@com.fasterxml.jackson.annotation.JsonProperty("_links")
@org.codehaus.jackson.map.annotate.JsonSerialize(include = org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion.NON_EMPTY, using = org.springframework.hateoas.hal.Jackson1HalModule.HalLinkListSerializer.class)
@org.codehaus.jackson.map.annotate.JsonDeserialize(using = org.springframework.hateoas.hal.Jackson1HalModule.HalLinkListDeserializer.class)
@com.fasterxml.jackson.databind.annotation.JsonSerialize(include = com.fasterxml.jackson.databind.annotation.JsonSerialize.Inclusion.NON_EMPTY, using = org.springframework.hateoas.hal.Jackson2HalModule.HalLinkListSerializer.class)
@com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = org.springframework.hateoas.hal.Jackson2HalModule.HalLinkListDeserializer.class)
@org.codehaus.jackson.map.annotate.JsonSerialize(
include = org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion.NON_EMPTY,
using = org.springframework.hateoas.hal.Jackson1HalModule.HalLinkListSerializer.class)
@org.codehaus.jackson.map.annotate.JsonDeserialize(
using = org.springframework.hateoas.hal.Jackson1HalModule.HalLinkListDeserializer.class)
@com.fasterxml.jackson.databind.annotation.JsonSerialize(
include = com.fasterxml.jackson.databind.annotation.JsonSerialize.Inclusion.NON_EMPTY,
using = org.springframework.hateoas.hal.Jackson2HalModule.HalLinkListSerializer.class)
@com.fasterxml.jackson.databind.annotation.JsonDeserialize(
using = org.springframework.hateoas.hal.Jackson2HalModule.HalLinkListDeserializer.class)
public abstract List<Link> getLinks();
}

View File

@@ -21,16 +21,23 @@ import javax.xml.bind.annotation.XmlElement;
import org.springframework.hateoas.Resources;
@SuppressWarnings("deprecation")
public abstract class ResourcesMixin<T> extends Resources<T> {
@Override
@XmlElement(name = "embedded")
@org.codehaus.jackson.annotate.JsonProperty("_embedded")
@com.fasterxml.jackson.annotation.JsonProperty("_embedded")
@org.codehaus.jackson.map.annotate.JsonSerialize(include = org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion.NON_EMPTY, using = org.springframework.hateoas.hal.Jackson1HalModule.HalResourcesSerializer.class)
@org.codehaus.jackson.map.annotate.JsonDeserialize(using = org.springframework.hateoas.hal.Jackson1HalModule.HalResourcesDeserializer.class)
@com.fasterxml.jackson.databind.annotation.JsonSerialize(include = com.fasterxml.jackson.databind.annotation.JsonSerialize.Inclusion.NON_EMPTY, using = org.springframework.hateoas.hal.Jackson2HalModule.HalResourcesSerializer.class)
@com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = org.springframework.hateoas.hal.Jackson2HalModule.HalResourcesDeserializer.class)
@org.codehaus.jackson.map.annotate.JsonSerialize(
include = org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion.NON_EMPTY,
using = org.springframework.hateoas.hal.Jackson1HalModule.HalResourcesSerializer.class)
@org.codehaus.jackson.map.annotate.JsonDeserialize(
using = org.springframework.hateoas.hal.Jackson1HalModule.HalResourcesDeserializer.class)
@com.fasterxml.jackson.databind.annotation.JsonSerialize(
include = com.fasterxml.jackson.databind.annotation.JsonSerialize.Inclusion.NON_EMPTY,
using = org.springframework.hateoas.hal.Jackson2HalModule.HalResourcesSerializer.class)
@com.fasterxml.jackson.databind.annotation.JsonDeserialize(
using = org.springframework.hateoas.hal.Jackson2HalModule.HalResourcesDeserializer.class)
public abstract Collection<T> getContent();
}

View File

@@ -202,6 +202,7 @@ public class ControllerLinkBuilder extends LinkBuilderSupport<ControllerLinkBuil
*
* @return
*/
@SuppressWarnings("null")
private static HttpServletRequest getCurrentRequest() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();