#286 - EmbeddedWrappers now allows empty collections if a rel or type is provided.
EmbeddedWrappers.wrap(Object, String) now allows empty collections. Also a new emptyCollectionOfType(Class<?>) was introduced to allow the RelProvider kick in and dynamically resolve the lazily. Added more details to the JavaDoc of EmbeddedWrapper to make clear that we either expect a static rel returned or a type to resolve the rel from. Make HalEmbeddedBuilder detect invalid implementations and reject them although that should never occur if users use EmbeddedWrappers factory.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2015 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.
|
||||
@@ -26,14 +26,16 @@ public interface EmbeddedWrapper {
|
||||
|
||||
/**
|
||||
* Returns the rel to be used when embedding. If this returns {@literal null}, the rel will be calculated based on the
|
||||
* type of the embedded value.
|
||||
* type returned by {@link #getRelTargetType()}. A wrapper returning {@literal null} for both {@link #getRel()} and
|
||||
* {@link #getRelTargetType()} is considered invalid.
|
||||
*
|
||||
* @return
|
||||
* @see #getRelTargetType()
|
||||
*/
|
||||
String getRel();
|
||||
|
||||
/**
|
||||
* Returns whether the wrapper hast the given rel.
|
||||
* Returns whether the wrapper has the given rel.
|
||||
*
|
||||
* @param rel can be {@literal null}.
|
||||
* @return
|
||||
@@ -55,7 +57,9 @@ public interface EmbeddedWrapper {
|
||||
Object getValue();
|
||||
|
||||
/**
|
||||
* Returns the type to be used to calculate a type based rel.
|
||||
* Returns the type to be used to calculate a type based rel. Can return {@literal null} in case an explicit rel is
|
||||
* returned in {@link #getRel()}. A wrapper returning {@literal null} for both {@link #getRel()} and
|
||||
* {@link #getRelTargetType()} is considered invalid.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2015 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.
|
||||
@@ -50,6 +50,16 @@ public class EmbeddedWrappers {
|
||||
return wrap(source, AbstractEmbeddedWrapper.NO_REL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link EmbeddedWrapper} for an empty {@link Collection} with the given element type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public EmbeddedWrapper emptyCollectionOf(Class<?> type) {
|
||||
return new EmptyCollectionEmbeddedWrapper(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link EmbeddedWrapper} with the given rel.
|
||||
*
|
||||
@@ -123,6 +133,11 @@ public class EmbeddedWrappers {
|
||||
public Class<?> getRelTargetType() {
|
||||
|
||||
Object peek = peek();
|
||||
|
||||
if (peek == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
peek = peek instanceof Resource ? ((Resource<Object>) peek).getContent() : peek;
|
||||
|
||||
return AopUtils.getTargetClass(peek);
|
||||
@@ -204,7 +219,10 @@ public class EmbeddedWrappers {
|
||||
super(rel);
|
||||
|
||||
Assert.notNull(value, "Collection must not be null!");
|
||||
Assert.notEmpty(value, "Collection must not be empty");
|
||||
|
||||
if (AbstractEmbeddedWrapper.NO_REL.equals(rel) && value.isEmpty()) {
|
||||
throw new IllegalArgumentException("Cannot wrap an empty collection with no rel given!");
|
||||
}
|
||||
|
||||
this.value = value;
|
||||
}
|
||||
@@ -224,7 +242,7 @@ public class EmbeddedWrappers {
|
||||
*/
|
||||
@Override
|
||||
protected Object peek() {
|
||||
return value.iterator().next();
|
||||
return value.isEmpty() ? null : value.iterator().next();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -236,4 +254,71 @@ public class EmbeddedWrappers {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link EmbeddedWrapper} to simulate a {@link Collection} of a given element type.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 0.17
|
||||
*/
|
||||
private static class EmptyCollectionEmbeddedWrapper implements EmbeddedWrapper {
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
/**
|
||||
* Creates a new {@link EmptyCollectionEmbeddedWrapper}.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
*/
|
||||
public EmptyCollectionEmbeddedWrapper(Class<?> type) {
|
||||
|
||||
Assert.notNull(type, "Element type must not be null!");
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.hateoas.core.EmbeddedWrapper#getRel()
|
||||
*/
|
||||
@Override
|
||||
public String getRel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.hateoas.core.EmbeddedWrapper#getValue()
|
||||
*/
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.hateoas.core.EmbeddedWrapper#getRelTargetType()
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getRelTargetType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.hateoas.core.EmbeddedWrapper#isCollectionValue()
|
||||
*/
|
||||
@Override
|
||||
public boolean isCollectionValue() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.hateoas.core.EmbeddedWrapper#hasRel(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean hasRel(String rel) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2015 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.
|
||||
@@ -39,6 +39,7 @@ import org.springframework.util.StringUtils;
|
||||
class HalEmbeddedBuilder {
|
||||
|
||||
private static final String DEFAULT_REL = "content";
|
||||
private static final String INVALID_EMBEDDED_WRAPPER = "Embedded wrapper %s returned null for both the static rel and the rel target type! Make sure one of the two returns a non-null value!";
|
||||
|
||||
private final Map<String, Object> embeddeds = new HashMap<String, Object>();
|
||||
private final RelProvider provider;
|
||||
@@ -117,6 +118,10 @@ class HalEmbeddedBuilder {
|
||||
|
||||
Class<?> type = wrapper.getRelTargetType();
|
||||
|
||||
if (type == null) {
|
||||
throw new IllegalStateException(String.format(INVALID_EMBEDDED_WRAPPER, wrapper));
|
||||
}
|
||||
|
||||
String rel = forCollection ? provider.getCollectionResourceRelFor(type) : provider.getItemResourceRelFor(type);
|
||||
|
||||
if (curieProvider != null) {
|
||||
|
||||
Reference in New Issue
Block a user