DATAREST-316 - UriStringDeserializer now guards against UriTemplate.
We now defensively guard against URI templates submitted for related resources and expand the incoming URI string source to avoid URI.create(…) to fail. Also, RepositoryPropertyReferenceController.loadPropertyValue(…) now also uses UriTemplate to guard against Uri templates provided for property references.
This commit is contained in:
@@ -319,7 +319,7 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
|
||||
// Add to the existing collection
|
||||
for (Link l : incoming.getLinks()) {
|
||||
Object propVal = loadPropertyValue(prop.propertyType, l.getHref());
|
||||
Object propVal = loadPropertyValue(prop.propertyType, l);
|
||||
coll.add(propVal);
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
|
||||
// Add to the existing collection
|
||||
for (Link l : incoming.getLinks()) {
|
||||
Object propVal = loadPropertyValue(prop.propertyType, l.getHref());
|
||||
Object propVal = loadPropertyValue(prop.propertyType, l);
|
||||
m.put(l.getRel(), propVal);
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
"Must send only 1 link to update a property reference that isn't a List or a Map.");
|
||||
}
|
||||
|
||||
Object propVal = loadPropertyValue(prop.propertyType, incoming.getLinks().get(0).getHref());
|
||||
Object propVal = loadPropertyValue(prop.propertyType, incoming.getLinks().get(0));
|
||||
prop.wrapper.setProperty(prop.property, propVal);
|
||||
}
|
||||
|
||||
@@ -431,8 +431,9 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
private Object loadPropertyValue(Class<?> type, String href) {
|
||||
private Object loadPropertyValue(Class<?> type, Link link) {
|
||||
|
||||
String href = link.expand().getHref();
|
||||
String id = href.substring(href.lastIndexOf('/') + 1);
|
||||
return conversionService.convert(id, type);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.springframework.data.rest.webmvc.PersistentEntityResource;
|
||||
import org.springframework.data.rest.webmvc.support.RepositoryLinkBuilder;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.UriTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerationException;
|
||||
@@ -355,7 +356,7 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class UriStringDeserializer extends StdDeserializer<Object> {
|
||||
static class UriStringDeserializer extends StdDeserializer<Object> {
|
||||
|
||||
private static final long serialVersionUID = -2175900204153350125L;
|
||||
|
||||
@@ -384,10 +385,10 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
@Override
|
||||
public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
|
||||
|
||||
String uriString = jp.getValueAsString();
|
||||
URI uri = new UriTemplate(jp.getValueAsString()).expand();
|
||||
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(property.getActualType());
|
||||
|
||||
return converter.convert(URI.create(uriString), URI_DESCRIPTOR, typeDescriptor);
|
||||
return converter.convert(uri, URI_DESCRIPTOR, typeDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* 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.json;
|
||||
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.rest.core.UriToEntityConverter;
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.UriStringDeserializer;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link UriStringDeserializer}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class UriStringDeserializerUnitTests {
|
||||
|
||||
@Mock UriToEntityConverter converter;
|
||||
@Mock PersistentProperty<?> property;
|
||||
|
||||
@Mock JsonParser parser;
|
||||
@Mock DeserializationContext context;
|
||||
|
||||
UriStringDeserializer deserializer;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.deserializer = new UriStringDeserializer(property, converter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-316
|
||||
*/
|
||||
@Test
|
||||
public void extractsUriToForwardToConverter() throws Exception {
|
||||
assertConverterInvokedWithUri("/foo/32", URI.create("/foo/32"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-316
|
||||
*/
|
||||
@Test
|
||||
public void extractsUriFromTemplateToForwardToConverter() throws Exception {
|
||||
assertConverterInvokedWithUri("/foo/32{?projection}", URI.create("/foo/32"));
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private void assertConverterInvokedWithUri(String source, URI expected) throws Exception {
|
||||
|
||||
when(property.getActualType()).thenReturn((Class) Object.class);
|
||||
when(parser.getValueAsString()).thenReturn(source);
|
||||
|
||||
deserializer.deserialize(parser, context);
|
||||
|
||||
verify(converter)
|
||||
.convert(eq(expected), Mockito.any(TypeDescriptor.class), eq(TypeDescriptor.valueOf(Object.class)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user