#195 - HalEmbeddedBuilder now considers RelAware on objects added.

This change introduces a RelAware interface for objects to implement which want to enforce a particular rel to be used in the _embedded clause. This is useful if the objects being added are not categorized by type but rather by their role in the context of the main object.
This commit is contained in:
Oliver Gierke
2014-06-10 10:46:46 +02:00
parent 673f82d388
commit 20bfa86c5f
4 changed files with 99 additions and 12 deletions

View File

@@ -22,9 +22,11 @@ import java.util.List;
import java.util.Map;
import org.springframework.aop.support.AopUtils;
import org.springframework.hateoas.RelAware;
import org.springframework.hateoas.RelProvider;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.core.ObjectUtils;
import org.springframework.util.Assert;
/**
* Builder class that allows collecting objects under the relation types defined for the objects but moving from the
@@ -39,16 +41,22 @@ class HalEmbeddedBuilder {
private final Map<String, List<Object>> embeddeds = new HashMap<String, List<Object>>();
private final RelProvider provider;
private final boolean enforceCollections;
private final boolean preferCollectionRels;
private boolean relAwareFound;
/**
* Creates a new {@link HalEmbeddedBuilder} using the given {@link RelProvider}.
* Creates a new {@link HalEmbeddedBuilder} using the given {@link RelProvider} and prefer collection rels flag.
*
* @param provider can be {@literal null}.
* @param preferCollectionRels whether to prefer to ask the provider for collection rels.
*/
public HalEmbeddedBuilder(RelProvider provider, boolean enforceCollections) {
public HalEmbeddedBuilder(RelProvider provider, boolean preferCollectionRels) {
Assert.notNull(provider, "Relprovider must not be null!");
this.provider = provider;
this.enforceCollections = enforceCollections;
this.preferCollectionRels = preferCollectionRels;
}
/**
@@ -59,16 +67,14 @@ class HalEmbeddedBuilder {
*/
public void add(Object value) {
Object unwrapped = ObjectUtils.getResourceType(value);
if (unwrapped == null) {
if (ObjectUtils.getResourceType(value) == null) {
return;
}
String rel = getDefaultedRelFor(unwrapped, true);
String rel = getDefaultedRelFor(value, true);
if (!embeddeds.containsKey(rel)) {
rel = getDefaultedRelFor(unwrapped, enforceCollections);
rel = getDefaultedRelFor(value, preferCollectionRels);
}
List<Object> currentValue = embeddeds.get(rel);
@@ -80,7 +86,7 @@ class HalEmbeddedBuilder {
} else if (currentValue.size() == 1) {
currentValue.add(value);
embeddeds.remove(rel);
embeddeds.put(getDefaultedRelFor(unwrapped, true), currentValue);
embeddeds.put(getDefaultedRelFor(value, true), currentValue);
} else {
currentValue.add(value);
}
@@ -88,16 +94,32 @@ class HalEmbeddedBuilder {
private String getDefaultedRelFor(Object value, boolean forCollection) {
Object unwrapped = ObjectUtils.getResourceType(value);
if (value instanceof RelAware) {
this.relAwareFound = true;
return ((RelAware) value).getRel();
}
if (provider == null) {
return DEFAULT_REL;
}
Class<?> type = AopUtils.getTargetClass(value);
Class<?> type = AopUtils.getTargetClass(unwrapped);
String rel = forCollection ? provider.getCollectionResourceRelFor(type) : provider.getItemResourceRelFor(type);
return rel == null ? DEFAULT_REL : rel;
}
/**
* Returns whether the builder only created collection rels.
*
* @return
*/
public boolean hasOnlyCollections() {
return preferCollectionRels && !relAwareFound;
}
/**
* Returns the added objects keyed up by their relation types.
*

View File

@@ -274,7 +274,7 @@ 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,
JsonSerializer<Object> valueSerializer = builder.hasOnlyCollections() ? provider.findValueSerializer(valueType,
property) : new OptionalListJackson2Serializer(property);
MapSerializer serializer = MapSerializer.construct(new String[] {}, mapType, true, null,