Added an annotation for doing parameter conversion @ConvertWith. You can now specify a Spring Core Converter class to use to convert the query parameter String[] values coming in on the query string to the type needed in the query method parameter.
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
package org.springframework.data.rest.repository.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Target({ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface ConvertWith {
|
||||
|
||||
Class<? extends Converter<String[], ?>> value();
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
@@ -32,6 +33,7 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -57,6 +59,7 @@ import org.springframework.data.rest.repository.RepositoryExporter;
|
||||
import org.springframework.data.rest.repository.RepositoryExporterSupport;
|
||||
import org.springframework.data.rest.repository.RepositoryMetadata;
|
||||
import org.springframework.data.rest.repository.RepositoryNotFoundException;
|
||||
import org.springframework.data.rest.repository.annotation.ConvertWith;
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
import org.springframework.data.rest.repository.context.AfterDeleteEvent;
|
||||
import org.springframework.data.rest.repository.context.AfterLinkDeleteEvent;
|
||||
@@ -538,6 +541,8 @@ public class RepositoryRestController
|
||||
return notFoundResponse(request);
|
||||
}
|
||||
|
||||
Annotation[][] annotations = queryMethod.method().getParameterAnnotations();
|
||||
|
||||
Class<?>[] paramTypes = queryMethod.paramTypes();
|
||||
String[] paramNames = queryMethod.paramNames();
|
||||
Object[] paramVals = new Object[paramTypes.length];
|
||||
@@ -552,18 +557,24 @@ public class RepositoryRestController
|
||||
continue;
|
||||
}
|
||||
|
||||
String queryVal;
|
||||
if(null == (queryVal = request.getServletRequest().getParameter(paramNames[i]))) {
|
||||
String[] queryVals;
|
||||
if(null == (queryVals = request.getServletRequest().getParameterValues(paramNames[i]))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(String.class.isAssignableFrom(paramTypes[i])) {
|
||||
// Param type is a String
|
||||
paramVals[i] = queryVal;
|
||||
} else if(hasRepositoryMetadataFor(paramTypes[i])) {
|
||||
Class<? extends Converter<String[], ?>> converter = null;
|
||||
for(Annotation anno : annotations[i]) {
|
||||
if(ConvertWith.class.isAssignableFrom(anno.getClass())) {
|
||||
converter = ((ConvertWith)anno).value();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String firstVal = (queryVals.length > 0 ? queryVals[0] : null);
|
||||
if(hasRepositoryMetadataFor(paramTypes[i])) {
|
||||
RepositoryMetadata paramRepoMeta = repositoryMetadataFor(paramTypes[i]);
|
||||
// Complex parameter is a managed type
|
||||
Serializable id = stringToSerializable(queryVal,
|
||||
Serializable id = stringToSerializable(firstVal,
|
||||
(Class<Serializable>)paramRepoMeta.entityMetadata()
|
||||
.idAttribute()
|
||||
.type());
|
||||
@@ -573,13 +584,22 @@ public class RepositoryRestController
|
||||
}
|
||||
|
||||
paramVals[i] = o;
|
||||
} else if(null != converter) {
|
||||
try {
|
||||
paramVals[i] = converter.newInstance().convert(queryVals);
|
||||
} catch(InstantiationException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
} else if(String.class.isAssignableFrom(paramTypes[i])) {
|
||||
// Param type is a String
|
||||
paramVals[i] = firstVal;
|
||||
} else if(conversionService.canConvert(String.class, paramTypes[i])) {
|
||||
// There's a converter from String -> param type
|
||||
paramVals[i] = conversionService.convert(queryVal, paramTypes[i]);
|
||||
paramVals[i] = conversionService.convert(firstVal, paramTypes[i]);
|
||||
} else {
|
||||
// Param type isn't a "simple" type or no converter exists, try JSON
|
||||
try {
|
||||
paramVals[i] = objectMapper.readValue(queryVal, paramTypes[i]);
|
||||
paramVals[i] = objectMapper.readValue(firstVal, paramTypes[i]);
|
||||
} catch(IOException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ class QueryMethodsSpec extends BaseSpec {
|
||||
|
||||
then:
|
||||
response.statusCode == HttpStatus.OK
|
||||
body.links.size() == 2
|
||||
body.links.size() == 3
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,17 @@ import java.util.List;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.rest.repository.annotation.ConvertWith;
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
* Example {@link org.springframework.data.repository.CrudRepository} for dealing with a {@link Person}. Also uses the
|
||||
* {@link RestResource} annotation to turn off the delete methods.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@RestResource(path = "people", rel = "peeps")
|
||||
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
|
||||
@@ -25,4 +30,8 @@ public interface PersonRepository extends PagingAndSortingRepository<Person, Lon
|
||||
@RestResource(path = "nameStartsWith", rel = "nameStartsWith")
|
||||
Page findByNameStartsWith(@Param("name") String name, Pageable p);
|
||||
|
||||
@Query("select p from Person p where p.id in(:id)")
|
||||
@RestResource(path = "id")
|
||||
Page<Person> findById(@Param("id") @ConvertWith(StringToListOfLongsConverter.class) List<Long> ids, Pageable pageable);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.springframework.data.rest.test.webmvc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class StringToListOfLongsConverter implements Converter<String[], List<Long>> {
|
||||
|
||||
@Override public List<Long> convert(String[] source) {
|
||||
List<Long> longs = new ArrayList<Long>();
|
||||
for(String s : source) {
|
||||
longs.add(Long.parseLong(s));
|
||||
}
|
||||
return longs;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user