DATAREST-523 - Re-enabled POST for collection based association resources.
We now support augmenting elements of a collection resource by using POST which previously only worked with PATCH requests. Took the chance to clean up RepositoryPropertyReferenceController by quite a bit and refactor functionality to discover the supported HTTP methods for a PersistentProperty into RootResourceInformation.
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.
|
||||
@@ -15,12 +15,16 @@
|
||||
*/
|
||||
package org.springframework.data.rest.core.mapping;
|
||||
|
||||
import static org.springframework.data.rest.core.mapping.ResourceType.*;
|
||||
import static org.springframework.http.HttpMethod.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.repository.core.CrudMethods;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
import org.springframework.http.HttpMethod;
|
||||
@@ -48,19 +52,6 @@ public class CrudMethodsSupportedHttpMethods implements SupportedHttpMethods {
|
||||
this.exposedMethods = new DefaultExposureAwareCrudMethods(crudMethods);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.SupportedHttpMethods#supports(org.springframework.http.HttpMethod, org.springframework.data.rest.core.mapping.ResourceType)
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(HttpMethod method, ResourceType type) {
|
||||
|
||||
Assert.notNull(method, "HTTP method must not be null!");
|
||||
Assert.notNull(type, "Resource type must not be null!");
|
||||
|
||||
return getMethodsFor(type).contains(method);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.SupportedHttpMethods#getSupportedHttpMethods(org.springframework.data.rest.core.mapping.ResourceType)
|
||||
@@ -71,18 +62,18 @@ public class CrudMethodsSupportedHttpMethods implements SupportedHttpMethods {
|
||||
Assert.notNull(resourcType, "Resource type must not be null!");
|
||||
|
||||
Set<HttpMethod> methods = new HashSet<HttpMethod>();
|
||||
methods.add(HttpMethod.OPTIONS);
|
||||
methods.add(OPTIONS);
|
||||
|
||||
switch (resourcType) {
|
||||
case COLLECTION:
|
||||
|
||||
if (exposedMethods.exposesFindAll()) {
|
||||
methods.add(HttpMethod.GET);
|
||||
methods.add(HttpMethod.HEAD);
|
||||
methods.add(GET);
|
||||
methods.add(HEAD);
|
||||
}
|
||||
|
||||
if (exposedMethods.exposesSave()) {
|
||||
methods.add(HttpMethod.POST);
|
||||
methods.add(POST);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -90,17 +81,17 @@ public class CrudMethodsSupportedHttpMethods implements SupportedHttpMethods {
|
||||
case ITEM:
|
||||
|
||||
if (exposedMethods.exposesDelete() && exposedMethods.exposesFindOne()) {
|
||||
methods.add(HttpMethod.DELETE);
|
||||
methods.add(DELETE);
|
||||
}
|
||||
|
||||
if (exposedMethods.exposesFindOne()) {
|
||||
methods.add(HttpMethod.GET);
|
||||
methods.add(HttpMethod.HEAD);
|
||||
methods.add(GET);
|
||||
methods.add(HEAD);
|
||||
}
|
||||
|
||||
if (exposedMethods.exposesSave()) {
|
||||
methods.add(HttpMethod.PUT);
|
||||
methods.add(HttpMethod.PATCH);
|
||||
methods.add(PUT);
|
||||
methods.add(PATCH);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -112,6 +103,34 @@ public class CrudMethodsSupportedHttpMethods implements SupportedHttpMethods {
|
||||
return Collections.unmodifiableSet(methods);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.SupportedHttpMethods#getMethodsFor(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public Set<HttpMethod> getMethodsFor(PersistentProperty<?> property) {
|
||||
|
||||
if (!property.isAssociation()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Set<HttpMethod> methods = new HashSet<HttpMethod>();
|
||||
|
||||
methods.add(GET);
|
||||
|
||||
if (property.isWritable() && getMethodsFor(ITEM).contains(PUT)) {
|
||||
methods.add(PUT);
|
||||
methods.add(PATCH);
|
||||
methods.add(DELETE);
|
||||
}
|
||||
|
||||
if (property.isCollectionLike() && property.isWritable()) {
|
||||
methods.add(POST);
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.rest.core.mapping;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
/**
|
||||
@@ -27,22 +28,21 @@ import org.springframework.http.HttpMethod;
|
||||
*/
|
||||
public interface SupportedHttpMethods {
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link HttpMethod} is supported for the given {@link ResourceType}.
|
||||
*
|
||||
* @param httpMethod must not be {@literal null}.
|
||||
* @param resourceType must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
boolean supports(HttpMethod method, ResourceType type);
|
||||
|
||||
/**
|
||||
* Returns the supported {@link HttpMethod}s for the given {@link ResourceType}.
|
||||
*
|
||||
* @param resourcType must not be {@literal null}.
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
Set<HttpMethod> getMethodsFor(ResourceType resourcType);
|
||||
Set<HttpMethod> getMethodsFor(ResourceType type);
|
||||
|
||||
/**
|
||||
* Returns the supported {@link HttpMethod}s for the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
Set<HttpMethod> getMethodsFor(PersistentProperty<?> property);
|
||||
|
||||
/**
|
||||
* Null object to abstract the absence of any support for any HTTP method.
|
||||
@@ -64,11 +64,11 @@ public interface SupportedHttpMethods {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.SupportedHttpMethods#supports(org.springframework.http.HttpMethod, org.springframework.data.rest.core.mapping.ResourceType)
|
||||
* @see org.springframework.data.rest.core.mapping.SupportedHttpMethods#getMethodsFor(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(HttpMethod method, ResourceType type) {
|
||||
return false;
|
||||
public Set<HttpMethod> getMethodsFor(PersistentProperty<?> property) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -15,15 +15,21 @@
|
||||
*/
|
||||
package org.springframework.data.rest.core.mapping;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.rest.core.mapping.ResourceType.*;
|
||||
import static org.springframework.http.HttpMethod.*;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.core.CrudMethods;
|
||||
@@ -91,6 +97,30 @@ public class CrudMethodsSupportedHttpMethodsUnitTests {
|
||||
assertMethodsSupported(supportedHttpMethods, ITEM, false, DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-523
|
||||
*/
|
||||
@Test
|
||||
public void exposesMethodsForProperties() {
|
||||
|
||||
MongoMappingContext context = new MongoMappingContext();
|
||||
MongoPersistentEntity<?> entity = context.getPersistentEntity(Entity.class);
|
||||
|
||||
SupportedHttpMethods methods = getSupportedHttpMethodsFor(EntityRepository.class);
|
||||
|
||||
assertThat(methods.getMethodsFor(entity.getPersistentProperty("embedded")), is(empty()));
|
||||
assertThat(methods.getMethodsFor(entity.getPersistentProperty("embeddedCollection")), is(empty()));
|
||||
|
||||
assertThat(methods.getMethodsFor(entity.getPersistentProperty("related")),
|
||||
allOf(hasItems(GET, DELETE, PATCH, PUT), not(hasItem(POST))));
|
||||
|
||||
assertThat(methods.getMethodsFor(entity.getPersistentProperty("relatedCollection")),
|
||||
hasItems(GET, DELETE, PATCH, PUT, POST));
|
||||
|
||||
assertThat(methods.getMethodsFor(entity.getPersistentProperty("readOnlyReference")),
|
||||
allOf(hasItem(GET), not(hasItems(DELETE, PATCH, PUT, POST))));
|
||||
}
|
||||
|
||||
private static SupportedHttpMethods getSupportedHttpMethodsFor(Class<?> repositoryInterface) {
|
||||
|
||||
RepositoryMetadata metadata = new DefaultRepositoryMetadata(repositoryInterface);
|
||||
@@ -102,12 +132,12 @@ public class CrudMethodsSupportedHttpMethodsUnitTests {
|
||||
private static void assertMethodsSupported(SupportedHttpMethods methods, ResourceType type, boolean supported,
|
||||
HttpMethod... httpMethods) {
|
||||
|
||||
Matcher<Iterable<HttpMethod>> isSupported = supported ? hasItems(httpMethods) : not(hasItems(httpMethods));
|
||||
Set<HttpMethod> result = methods.getMethodsFor(type);
|
||||
|
||||
assertThat(methods.getMethodsFor(type), isSupported);
|
||||
assertThat(result, supported ? hasItems(httpMethods) : not(hasItems(httpMethods)));
|
||||
|
||||
for (HttpMethod method : httpMethods) {
|
||||
assertThat(methods.supports(method, type), is(supported));
|
||||
if (supported) {
|
||||
assertThat(result, hasSize(httpMethods.length));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,4 +150,15 @@ public class CrudMethodsSupportedHttpMethodsUnitTests {
|
||||
@RestResource(exported = false)
|
||||
void delete(Object id);
|
||||
}
|
||||
|
||||
interface EntityRepository extends CrudRepository<Entity, Long> {}
|
||||
|
||||
class Entity {
|
||||
|
||||
Entity embedded;
|
||||
@Reference Entity related;
|
||||
List<Entity> embeddedCollection;
|
||||
@Reference List<Entity> relatedCollection;
|
||||
@ReadOnlyProperty @Reference Entity readOnlyReference;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user