#135 - HAL embedded resources are now rendered as collection by default.
To get consistent representations rendered for single-item collections and multi-item collections, we now use an enforceEmbeddedCollections flag in the Jackson 2 HAL module. Adapted HalEmbeddedBuilder to respect that setting and exposed it via the HandlerInstantiator for user level customization. Changed RelProvider.getSingleResourceRel(…) to getItemResourceRel(…).
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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,11 +18,25 @@ package org.springframework.hateoas;
|
||||
import org.springframework.plugin.core.Plugin;
|
||||
|
||||
/**
|
||||
* API to provide relation types for collections and items of the given type.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface RelProvider extends Plugin<Class<?>> {
|
||||
|
||||
String getSingleResourceRelFor(Class<?> type);
|
||||
/**
|
||||
* Returns the relation type to be used to point to an item resource of the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
String getItemResourceRelFor(Class<?> type);
|
||||
|
||||
/**
|
||||
* Returns the relation type to be used to point to a collection resource of the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
String getCollectionResourceRelFor(Class<?> type);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -52,7 +52,7 @@ public class AnnotationRelProvider implements RelProvider {
|
||||
* @see org.springframework.hateoas.RelProvider#getRelForSingleResource(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String getSingleResourceRelFor(Class<?> type) {
|
||||
public String getItemResourceRelFor(Class<?> type) {
|
||||
|
||||
Relation annotation = lookupAnnotation(type);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -52,7 +52,7 @@ public class DefaultRelProvider implements RelProvider {
|
||||
* @see org.springframework.hateoas.RelProvider#getRelForSingleResource(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public String getSingleResourceRelFor(Class<?> type) {
|
||||
public String getItemResourceRelFor(Class<?> type) {
|
||||
return StringUtils.uncapitalize(type.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -37,8 +37,8 @@ public class DelegatingRelProvider implements RelProvider {
|
||||
* @see org.springframework.hateoas.RelProvider#getRelForSingleResource(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public String getSingleResourceRelFor(Class<?> type) {
|
||||
return providers.getPluginFor(type).getSingleResourceRelFor(type);
|
||||
public String getItemResourceRelFor(Class<?> type) {
|
||||
return providers.getPluginFor(type).getItemResourceRelFor(type);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -33,6 +33,6 @@ public class EvoInflectorRelProvider extends DefaultRelProvider {
|
||||
*/
|
||||
@Override
|
||||
public String getCollectionResourceRelFor(Class<?> type) {
|
||||
return English.plural(getSingleResourceRelFor(type));
|
||||
return English.plural(getItemResourceRelFor(type));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -38,14 +38,16 @@ class HalEmbeddedBuilder {
|
||||
|
||||
private final Map<String, List<Object>> embeddeds = new HashMap<String, List<Object>>();
|
||||
private final RelProvider provider;
|
||||
private final boolean enforceCollections;
|
||||
|
||||
/**
|
||||
* Creates a new {@link HalEmbeddedBuilder} using the given {@link RelProvider}.
|
||||
*
|
||||
* @param provider can be {@literal null}.
|
||||
*/
|
||||
public HalEmbeddedBuilder(RelProvider provider) {
|
||||
public HalEmbeddedBuilder(RelProvider provider, boolean enforceCollections) {
|
||||
this.provider = provider;
|
||||
this.enforceCollections = enforceCollections;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,7 +67,7 @@ class HalEmbeddedBuilder {
|
||||
String rel = getDefaultedRelFor(type, true);
|
||||
|
||||
if (!embeddeds.containsKey(rel)) {
|
||||
rel = getDefaultedRelFor(type, false);
|
||||
rel = getDefaultedRelFor(type, enforceCollections);
|
||||
}
|
||||
|
||||
List<Object> currentValue = embeddeds.get(rel);
|
||||
@@ -89,7 +91,7 @@ class HalEmbeddedBuilder {
|
||||
return DEFAULT_REL;
|
||||
}
|
||||
|
||||
String rel = forCollection ? provider.getCollectionResourceRelFor(type) : provider.getSingleResourceRelFor(type);
|
||||
String rel = forCollection ? provider.getCollectionResourceRelFor(type) : provider.getItemResourceRelFor(type);
|
||||
return rel == null ? DEFAULT_REL : rel;
|
||||
}
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ public class Jackson1HalModule extends SimpleModule {
|
||||
public void serialize(Collection<?> value, JsonGenerator jgen, SerializerProvider provider) throws IOException,
|
||||
JsonGenerationException {
|
||||
|
||||
HalEmbeddedBuilder builder = new HalEmbeddedBuilder(relProvider);
|
||||
HalEmbeddedBuilder builder = new HalEmbeddedBuilder(relProvider, false);
|
||||
|
||||
for (Object resource : value) {
|
||||
builder.add(resource);
|
||||
|
||||
@@ -238,17 +238,19 @@ public class Jackson2HalModule extends SimpleModule {
|
||||
|
||||
private final BeanProperty property;
|
||||
private final RelProvider relProvider;
|
||||
private final boolean enforceEmbeddedCollections;
|
||||
|
||||
public HalResourcesSerializer(RelProvider relPorvider) {
|
||||
this(null, relPorvider);
|
||||
public HalResourcesSerializer(RelProvider relPorvider, boolean enforceEmbeddedCollections) {
|
||||
this(null, relPorvider, enforceEmbeddedCollections);
|
||||
}
|
||||
|
||||
public HalResourcesSerializer(BeanProperty property, RelProvider relProvider) {
|
||||
public HalResourcesSerializer(BeanProperty property, RelProvider relProvider, boolean enforceEmbeddedCollections) {
|
||||
|
||||
super(Collection.class, false);
|
||||
|
||||
this.property = property;
|
||||
this.relProvider = relProvider;
|
||||
this.enforceEmbeddedCollections = enforceEmbeddedCollections;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -261,7 +263,7 @@ public class Jackson2HalModule extends SimpleModule {
|
||||
public void serialize(Collection<?> value, JsonGenerator jgen, SerializerProvider provider) throws IOException,
|
||||
JsonGenerationException {
|
||||
|
||||
HalEmbeddedBuilder builder = new HalEmbeddedBuilder(relProvider);
|
||||
HalEmbeddedBuilder builder = new HalEmbeddedBuilder(relProvider, enforceEmbeddedCollections);
|
||||
|
||||
for (Object resource : value) {
|
||||
builder.add(resource);
|
||||
@@ -272,8 +274,11 @@ public class Jackson2HalModule extends SimpleModule {
|
||||
JavaType valueType = typeFactory.constructCollectionType(ArrayList.class, Resource.class);
|
||||
JavaType mapType = typeFactory.constructMapType(HashMap.class, keyType, valueType);
|
||||
|
||||
JsonSerializer<Object> valueSerializer = enforceEmbeddedCollections ? provider.findValueSerializer(valueType,
|
||||
property) : new OptionalListJackson2Serializer(property);
|
||||
|
||||
MapSerializer serializer = MapSerializer.construct(new String[] {}, mapType, true, null,
|
||||
provider.findKeySerializer(keyType, null), new OptionalListJackson2Serializer(property), null);
|
||||
provider.findKeySerializer(keyType, null), valueSerializer, null);
|
||||
|
||||
serializer.serialize(builder.asMap(), jgen, provider);
|
||||
}
|
||||
@@ -281,12 +286,11 @@ public class Jackson2HalModule extends SimpleModule {
|
||||
@Override
|
||||
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
|
||||
throws JsonMappingException {
|
||||
return new HalResourcesSerializer(property, relProvider);
|
||||
return new HalResourcesSerializer(property, relProvider, enforceEmbeddedCollections);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType getContentType() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -601,9 +605,14 @@ public class Jackson2HalModule extends SimpleModule {
|
||||
private final Map<Class<?>, Object> instanceMap = new HashMap<Class<?>, Object>();
|
||||
|
||||
public HalHandlerInstantiator(RelProvider resolver, CurieProvider curieProvider) {
|
||||
this(resolver, curieProvider, true);
|
||||
}
|
||||
|
||||
public HalHandlerInstantiator(RelProvider resolver, CurieProvider curieProvider, boolean enforceEmbeddedCollections) {
|
||||
|
||||
Assert.notNull(resolver, "RelProvider must not be null!");
|
||||
this.instanceMap.put(HalResourcesSerializer.class, new HalResourcesSerializer(resolver));
|
||||
this.instanceMap.put(HalResourcesSerializer.class, new HalResourcesSerializer(resolver,
|
||||
enforceEmbeddedCollections));
|
||||
this.instanceMap.put(HalLinkListSerializer.class, new HalLinkListSerializer(curieProvider));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -56,8 +56,8 @@ public class ControllerRelProvider implements RelProvider {
|
||||
* @see org.springframework.hateoas.RelProvider#getRelForSingleResource(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public String getSingleResourceRelFor(Class<?> resource) {
|
||||
return providers.getPluginFor(entityType).getSingleResourceRelFor(resource);
|
||||
public String getItemResourceRelFor(Class<?> resource) {
|
||||
return providers.getPluginFor(entityType).getItemResourceRelFor(resource);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user