DATAREST-609 - Removed server-side template expansion for incoming URI mapping.
Previously we leniently expanded incoming URIs prior to mapping them to controllers. As the original ticket describes, this can cause security issues in rather lenient security setups as the call might bypass a simple security rule but then eventually map to a URI mapped to a stricter security rule. Made sure that self links now return canonical URIs instead of templates. To still advertise projections, PersistentEntityResourceAssembler now adds an additional link to the canonical resource to resources that contains the unexpanded template. Switched from requiring a Repositories instance to PersistentEntities on the way. Related tickets: DATAREST-267, DATAREST-268, DATAREST-300, DATAREST-318, SEC-3027.
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.
|
||||
@@ -111,7 +111,6 @@ public class BaseUri {
|
||||
|
||||
Assert.notNull(lookupPath, "Lookup path must not be null!");
|
||||
|
||||
lookupPath = lookupPath.contains("{") ? lookupPath.substring(0, lookupPath.indexOf('{')) : lookupPath;
|
||||
lookupPath = trimTrailingCharacter(lookupPath, '/');
|
||||
|
||||
if (!baseUri.isAbsolute()) {
|
||||
|
||||
@@ -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.
|
||||
@@ -24,7 +24,7 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.SimpleAssociationHandler;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.webmvc.PersistentEntityResource.Builder;
|
||||
@@ -44,7 +44,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class PersistentEntityResourceAssembler implements ResourceAssembler<Object, PersistentEntityResource> {
|
||||
|
||||
private final Repositories repositories;
|
||||
private final PersistentEntities entities;
|
||||
private final EntityLinks entityLinks;
|
||||
private final Projector projector;
|
||||
private final ResourceMappings mappings;
|
||||
@@ -53,20 +53,20 @@ public class PersistentEntityResourceAssembler implements ResourceAssembler<Obje
|
||||
/**
|
||||
* Creates a new {@link PersistentEntityResourceAssembler}.
|
||||
*
|
||||
* @param repositories must not be {@literal null}.
|
||||
* @param entities must not be {@literal null}.
|
||||
* @param entityLinks must not be {@literal null}.
|
||||
* @param projector must not be {@literal null}.
|
||||
* @param mappings must not be {@literal null}.
|
||||
*/
|
||||
public PersistentEntityResourceAssembler(Repositories repositories, EntityLinks entityLinks, Projector projector,
|
||||
public PersistentEntityResourceAssembler(PersistentEntities entities, EntityLinks entityLinks, Projector projector,
|
||||
ResourceMappings mappings) {
|
||||
|
||||
Assert.notNull(repositories, "Repositories must not be null!");
|
||||
Assert.notNull(entities, "PersistentEntities must not be null!");
|
||||
Assert.notNull(entityLinks, "EntityLinks must not be null!");
|
||||
Assert.notNull(projector, "PersistentEntityProjector must not be be null!");
|
||||
Assert.notNull(mappings, "ResourceMappings must not be null!");
|
||||
|
||||
this.repositories = repositories;
|
||||
this.entities = entities;
|
||||
this.entityLinks = entityLinks;
|
||||
this.projector = projector;
|
||||
this.mappings = mappings;
|
||||
@@ -97,11 +97,12 @@ public class PersistentEntityResourceAssembler implements ResourceAssembler<Obje
|
||||
|
||||
private Builder wrap(Object instance, Object source) {
|
||||
|
||||
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(source.getClass());
|
||||
PersistentEntity<?, ?> entity = entities.getPersistentEntity(source.getClass());
|
||||
|
||||
return PersistentEntityResource.build(instance, entity).//
|
||||
withEmbedded(getEmbeddedResources(source)).//
|
||||
withLink(getSelfLinkFor(source));
|
||||
withLink(getSelfLinkFor(source)).//
|
||||
withLink(getSingleResourceLinkTo(source));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,7 +116,7 @@ public class PersistentEntityResourceAssembler implements ResourceAssembler<Obje
|
||||
|
||||
Assert.notNull(instance, "Entity instance must not be null!");
|
||||
|
||||
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(instance.getClass());
|
||||
PersistentEntity<?, ?> entity = entities.getPersistentEntity(instance.getClass());
|
||||
|
||||
final List<EmbeddedWrapper> associationProjections = new ArrayList<EmbeddedWrapper>();
|
||||
final PersistentPropertyAccessor accessor = entity.getPropertyAccessor(instance);
|
||||
@@ -183,20 +184,23 @@ public class PersistentEntityResourceAssembler implements ResourceAssembler<Obje
|
||||
* @return
|
||||
*/
|
||||
public Link getSelfLinkFor(Object instance) {
|
||||
return new Link(getSingleResourceLinkTo(instance).expand().getHref(), Link.REL_SELF);
|
||||
}
|
||||
|
||||
private Link getSingleResourceLinkTo(Object instance) {
|
||||
|
||||
Assert.notNull(instance, "Domain object must not be null!");
|
||||
|
||||
Class<? extends Object> instanceType = instance.getClass();
|
||||
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(instanceType);
|
||||
PersistentEntity<?, ?> entity = entities.getPersistentEntity(instanceType);
|
||||
|
||||
if (entity == null) {
|
||||
throw new IllegalArgumentException(String.format("Cannot create self link for %s! No persistent entity found!",
|
||||
instanceType));
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cannot create self link for %s! No persistent entity found!", instanceType));
|
||||
}
|
||||
|
||||
Object id = entity.getIdentifierAccessor(instance).getIdentifier();
|
||||
|
||||
Link resourceLink = entityLinks.linkToSingleResource(entity.getType(), id);
|
||||
return new Link(resourceLink.getHref(), Link.REL_SELF);
|
||||
return entityLinks.linkToSingleResource(entity.getType(), id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.rest.webmvc.config;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
@@ -36,7 +37,7 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
*/
|
||||
public class PersistentEntityResourceAssemblerArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
private final Repositories repositories;
|
||||
private final PersistentEntities entities;
|
||||
private final EntityLinks entityLinks;
|
||||
private final ProjectionDefinitions projectionDefinitions;
|
||||
private final ProjectionFactory projectionFactory;
|
||||
@@ -46,20 +47,20 @@ public class PersistentEntityResourceAssemblerArgumentResolver implements Handle
|
||||
* Creates a new {@link PersistentEntityResourceAssemblerArgumentResolver} for the given {@link Repositories},
|
||||
* {@link EntityLinks}, {@link ProjectionDefinitions} and {@link ProjectionFactory}.
|
||||
*
|
||||
* @param repositories must not be {@literal null}.
|
||||
* @param entities must not be {@literal null}.
|
||||
* @param entityLinks must not be {@literal null}.
|
||||
* @param projectionDefinitions must not be {@literal null}.
|
||||
* @param projectionFactory must not be {@literal null}.
|
||||
*/
|
||||
public PersistentEntityResourceAssemblerArgumentResolver(Repositories repositories, EntityLinks entityLinks,
|
||||
public PersistentEntityResourceAssemblerArgumentResolver(PersistentEntities entities, EntityLinks entityLinks,
|
||||
ProjectionDefinitions projectionDefinitions, ProjectionFactory projectionFactory, ResourceMappings mappings) {
|
||||
|
||||
Assert.notNull(repositories, "Repositories must not be null!");
|
||||
Assert.notNull(entities, "PersistentEntities must not be null!");
|
||||
Assert.notNull(entityLinks, "EntityLinks must not be null!");
|
||||
Assert.notNull(projectionDefinitions, "ProjectionDefinitions must not be null!");
|
||||
Assert.notNull(projectionFactory, "ProjectionFactory must not be null!");
|
||||
|
||||
this.repositories = repositories;
|
||||
this.entities = entities;
|
||||
this.entityLinks = entityLinks;
|
||||
this.projectionDefinitions = projectionDefinitions;
|
||||
this.projectionFactory = projectionFactory;
|
||||
@@ -87,6 +88,6 @@ public class PersistentEntityResourceAssemblerArgumentResolver implements Handle
|
||||
PersistentEntityProjector projector = new PersistentEntityProjector(projectionDefinitions, projectionFactory,
|
||||
projectionParameter, mappings);
|
||||
|
||||
return new PersistentEntityResourceAssembler(repositories, entityLinks, projector, mappings);
|
||||
return new PersistentEntityResourceAssembler(entities, entityLinks, projector, mappings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
@Configuration
|
||||
@EnableHypermediaSupport(type = HypermediaType.HAL)
|
||||
@ComponentScan(basePackageClasses = RepositoryRestController.class,
|
||||
includeFilters = @Filter(BasePathAwareController.class), useDefaultFilters = false)
|
||||
includeFilters = @Filter(BasePathAwareController.class) , useDefaultFilters = false)
|
||||
@ImportResource("classpath*:META-INF/spring-data-rest/**/*.xml")
|
||||
@Import(SpringDataJacksonConfiguration.class)
|
||||
public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebConfiguration {
|
||||
@@ -171,8 +171,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
|
||||
List<MappingContext<?, ?>> arrayList = new ArrayList<MappingContext<?, ?>>();
|
||||
|
||||
for (MappingContext<?, ?> context : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext,
|
||||
MappingContext.class).values()) {
|
||||
for (MappingContext<?, ?> context : BeanFactoryUtils
|
||||
.beansOfTypeIncludingAncestors(applicationContext, MappingContext.class).values()) {
|
||||
arrayList.add(context);
|
||||
}
|
||||
|
||||
@@ -406,7 +406,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
RestMediaTypes.JSON_PATCH_JSON, RestMediaTypes.MERGE_PATCH_JSON, //
|
||||
RestMediaTypes.SPRING_DATA_VERBOSE_JSON, RestMediaTypes.SPRING_DATA_COMPACT_JSON));
|
||||
|
||||
TypeConstrainedMappingJackson2HttpMessageConverter jacksonConverter = new ResourceSupportHttpMessageConverter(order);
|
||||
TypeConstrainedMappingJackson2HttpMessageConverter jacksonConverter = new ResourceSupportHttpMessageConverter(
|
||||
order);
|
||||
jacksonConverter.setObjectMapper(objectMapper());
|
||||
jacksonConverter.setSupportedMediaTypes(mediaTypes);
|
||||
|
||||
@@ -578,8 +579,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
|
||||
@Bean
|
||||
public RepositoryInvokerFactory repositoryInvokerFactory() {
|
||||
return new UnwrappingRepositoryInvokerFactory(new DefaultRepositoryInvokerFactory(repositories(),
|
||||
defaultConversionService()));
|
||||
return new UnwrappingRepositoryInvokerFactory(
|
||||
new DefaultRepositoryInvokerFactory(repositories(), defaultConversionService()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -661,7 +662,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
projectionFactory.setResourceLoader(applicationContext);
|
||||
|
||||
PersistentEntityResourceAssemblerArgumentResolver peraResolver = new PersistentEntityResourceAssemblerArgumentResolver(
|
||||
repositories(), entityLinks(), config().projectionConfiguration(), projectionFactory, resourceMappings());
|
||||
persistentEntities(), entityLinks(), config().projectionConfiguration(), projectionFactory, resourceMappings());
|
||||
|
||||
HateoasPageableHandlerMethodArgumentResolver pageableResolver = pageableResolver();
|
||||
HandlerMethodArgumentResolver defaultedPageableResolver = new DefaultedPageableHandlerMethodArgumentResolver(
|
||||
@@ -669,8 +670,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
|
||||
return Arrays.asList(defaultedPageableResolver, pageableResolver, sortResolver(),
|
||||
serverHttpRequestMethodArgumentResolver(), repoRequestArgumentResolver(), persistentEntityArgumentResolver(),
|
||||
resourceMetadataHandlerMethodArgumentResolver(), HttpMethodHandlerMethodArgumentResolver.INSTANCE,
|
||||
peraResolver, backendIdHandlerMethodArgumentResolver(), eTagArgumentResolver());
|
||||
resourceMetadataHandlerMethodArgumentResolver(), HttpMethodHandlerMethodArgumentResolver.INSTANCE, peraResolver,
|
||||
backendIdHandlerMethodArgumentResolver(), eTagArgumentResolver());
|
||||
}
|
||||
|
||||
@Autowired GeoModule geoModule;
|
||||
|
||||
@@ -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.
|
||||
@@ -53,7 +53,7 @@ public abstract class AbstractControllerIntegrationTests {
|
||||
|
||||
@Bean
|
||||
public PersistentEntityResourceAssembler persistentEntityResourceAssembler() {
|
||||
return new PersistentEntityResourceAssembler(repositories(), entityLinks(), StubProjector.INSTANCE,
|
||||
return new PersistentEntityResourceAssembler(persistentEntities(), entityLinks(), StubProjector.INSTANCE,
|
||||
resourceMappings());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -21,8 +21,6 @@ import static org.junit.Assert.*;
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link BaseUri}.
|
||||
@@ -89,26 +87,4 @@ public class BaseUriUnitTests {
|
||||
assertThat(uri.getRepositoryLookupPath("/foo/people"), is("/people"));
|
||||
assertThat(uri.getRepositoryLookupPath("/foo/people/"), is("/people"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-300
|
||||
*/
|
||||
@Test
|
||||
public void stripsTemplateVariablesFromPath() {
|
||||
|
||||
BaseUri uri = new BaseUri(URI.create("foo"));
|
||||
assertThat(uri.getRepositoryLookupPath("/foo/bar{?projection}"), is("/bar"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-318
|
||||
*/
|
||||
@Test
|
||||
public void stripsTemplateVariablesFromRequest() {
|
||||
|
||||
BaseUri uri = new BaseUri(URI.create("foo"));
|
||||
|
||||
ServletWebRequest request = new ServletWebRequest(new MockHttpServletRequest("GET", "/foo/bar{?projection}"));
|
||||
assertThat(uri.getRepositoryLookupPath(request), is("/bar"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* 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.data.rest.webmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
import org.mockito.internal.stubbing.answers.ReturnsArgumentAt;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.rest.webmvc.AbstractControllerIntegrationTests.TestConfiguration;
|
||||
import org.springframework.data.rest.webmvc.mongodb.MongoDbRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.mongodb.User;
|
||||
import org.springframework.data.rest.webmvc.support.Projector;
|
||||
import org.springframework.hateoas.EntityLinks;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.Links;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link PersistentEntityResourceAssembler}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@ContextConfiguration(classes = { TestConfiguration.class, MongoDbRepositoryConfig.class })
|
||||
public class PersistentEntityResourceAssemblerIntegrationTests extends AbstractControllerIntegrationTests {
|
||||
|
||||
@Autowired PersistentEntities entities;
|
||||
@Autowired EntityLinks entityLinks;
|
||||
|
||||
/**
|
||||
* @see DATAREST-609
|
||||
*/
|
||||
@Test
|
||||
public void addsSelfAndSingleResourceLinkToResourceByDefault() {
|
||||
|
||||
Projector projector = mock(Projector.class);
|
||||
|
||||
when(projector.projectExcerpt(anyObject())).thenAnswer(new ReturnsArgumentAt(0));
|
||||
|
||||
PersistentEntityResourceAssembler assembler = new PersistentEntityResourceAssembler(entities, entityLinks,
|
||||
projector, mappings);
|
||||
|
||||
User user = new User();
|
||||
user.id = BigInteger.valueOf(4711);
|
||||
|
||||
Links links = new Links(assembler.toResource(user).getLinks());
|
||||
|
||||
assertThat(links, is(Matchers.<Link> iterableWithSize(2)));
|
||||
assertThat(links.getLink("self").getVariables(), is(Matchers.empty()));
|
||||
assertThat(links.getLink("user").getVariableNames(), is(hasItem("projection")));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -220,4 +220,17 @@ public class RepositoryRestHandlerMappingUnitTests {
|
||||
|
||||
assertThat(method, is(nullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-609
|
||||
*/
|
||||
@Test
|
||||
public void rejectsUnexpandedUriTemplateWithNotFound() throws Exception {
|
||||
|
||||
when(mappings.exportsTopLevelResourceFor("/people")).thenReturn(true);
|
||||
|
||||
mockRequest = new MockHttpServletRequest("GET", "/people{?projection}");
|
||||
|
||||
assertThat(handlerMapping.getHandler(mockRequest), is(nullValue()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* 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.data.rest.webmvc.mongodb;
|
||||
|
||||
import org.springframework.data.rest.core.config.Projection;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Projection(types = User.class)
|
||||
public interface UserSummary {
|
||||
|
||||
String getFirstname();
|
||||
|
||||
String getLastname();
|
||||
}
|
||||
@@ -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.
|
||||
@@ -39,25 +39,11 @@ import org.springframework.web.context.request.ServletWebRequest;
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@ContextConfiguration(classes = JpaRepositoryConfig.class)
|
||||
public class BackendIdConverterHandlerMethodArgumentResolverIntegrationTests extends AbstractControllerIntegrationTests {
|
||||
public class BackendIdConverterHandlerMethodArgumentResolverIntegrationTests
|
||||
extends AbstractControllerIntegrationTests {
|
||||
|
||||
@Autowired BackendIdHandlerMethodArgumentResolver resolver;
|
||||
|
||||
/**
|
||||
* @see DATAREST-267, DATAREST-268
|
||||
*/
|
||||
@Test
|
||||
public void stripsUriTemplateVariablesFromUri() throws Exception {
|
||||
|
||||
Method method = ReflectionUtils.findMethod(SampleController.class, "resolveId", Serializable.class);
|
||||
MethodParameter parameter = new MethodParameter(method, 0);
|
||||
NativeWebRequest request = new ServletWebRequest(new MockHttpServletRequest("GET", "/orders/5{?projection}"));
|
||||
|
||||
Object resolvedId = resolver.resolveArgument(parameter, null, request, null);
|
||||
|
||||
assertThat(resolvedId, is((Object) "5"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-155
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user