DATAREST-93 - More cleanups in code structure.
Removed the need for RepositoryInformationSupport. Refactored Converter implementations to get dependencies injected directly and use constructor injection. Added new RepositoryInvoker abstraction to avoid reflection for known CrudRepository or PagingAndSortingRepository. Refactored existing RepositoryMethodInvoker to implement the new abstraction. Refactored AbstractRepositoryRestController and RepositoryEntityContoller to use new mapping API.
This commit is contained in:
@@ -1,59 +1,104 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.repository;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.repository.support.DomainClassConverter;
|
||||
import org.springframework.data.rest.repository.support.RepositoryInformationSupport;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link ConditionalGenericConverter} that can convert a {@link URI} domain entity.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class UriDomainClassConverter extends RepositoryInformationSupport implements ConditionalGenericConverter,
|
||||
InitializingBean {
|
||||
public class UriDomainClassConverter implements ConditionalGenericConverter {
|
||||
|
||||
private static TypeDescriptor STRING_TYPE = TypeDescriptor.valueOf(String.class);
|
||||
private static final TypeDescriptor STRING_TYPE = TypeDescriptor.valueOf(String.class);
|
||||
|
||||
@Autowired private DomainClassConverter<?> domainClassConverter;
|
||||
private Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>();
|
||||
private final Repositories repositories;
|
||||
private final DomainClassConverter<?> domainClassConverter;
|
||||
private final Set<ConvertiblePair> convertiblePairs;
|
||||
|
||||
/**
|
||||
* Creates a new {@link UriDomainClassConverter} using the given {@link Repositories} and {@link DomainClassConverter}
|
||||
* .
|
||||
*
|
||||
* @param repositories must not be {@literal null}.
|
||||
* @param domainClassConverter must not be {@literal null}.
|
||||
*/
|
||||
public UriDomainClassConverter(Repositories repositories, DomainClassConverter<?> domainClassConverter) {
|
||||
|
||||
Assert.notNull(repositories, "Repositories must not be null!");
|
||||
Assert.notNull(domainClassConverter, "DomainClassConverter must not be null!");
|
||||
|
||||
this.repositories = repositories;
|
||||
this.domainClassConverter = domainClassConverter;
|
||||
this.convertiblePairs = new HashSet<ConvertiblePair>();
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
for (Class<?> domainType : repositories) {
|
||||
convertiblePairs.add(new ConvertiblePair(URI.class, domainType));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.ConditionalConverter#matches(org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
|
||||
return URI.class.isAssignableFrom(sourceType.getType())
|
||||
&& (null != repositories.getPersistentEntity(targetType.getType()));
|
||||
&& repositories.getPersistentEntity(targetType.getType()) != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.GenericConverter#getConvertibleTypes()
|
||||
*/
|
||||
@Override
|
||||
public Set<ConvertiblePair> getConvertibleTypes() {
|
||||
return convertiblePairs;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.GenericConverter#convert(java.lang.Object, org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)
|
||||
*/
|
||||
@Override
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
|
||||
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(targetType.getType());
|
||||
if (null == entity || !domainClassConverter.matches(STRING_TYPE, targetType)) {
|
||||
|
||||
if (entity != null || !domainClassConverter.matches(STRING_TYPE, targetType)) {
|
||||
throw new ConversionFailedException(sourceType, targetType, source, new IllegalArgumentException(
|
||||
"No PersistentEntity information available for " + targetType.getType()));
|
||||
}
|
||||
|
||||
URI uri = (URI) source;
|
||||
String[] parts = uri.getPath().split("/");
|
||||
|
||||
if (parts.length < 2) {
|
||||
throw new ConversionFailedException(sourceType, targetType, source, new IllegalArgumentException(
|
||||
"Cannot resolve URI " + uri + ". Is it local or remote? Only local URIs are resolvable."));
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2013 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.repository.invoke;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class CrudRepositoryInvoker implements RepositoryInvoker {
|
||||
|
||||
private final CrudRepository<Object, Serializable> repository;
|
||||
|
||||
/**
|
||||
* @param repository must not be {@literal null}.
|
||||
*/
|
||||
public CrudRepositoryInvoker(CrudRepository<Object, Serializable> repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort)
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Object> findAll(Sort sort) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Pageable)
|
||||
*/
|
||||
@Override
|
||||
public Page<Object> findAll(Pageable pageable) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#save(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public <S> S save(S entity) {
|
||||
return repository.save(entity);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable)
|
||||
*/
|
||||
@Override
|
||||
public <S> Iterable<S> save(Iterable<S> entities) {
|
||||
return repository.save(entities);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#findOne(java.io.Serializable)
|
||||
*/
|
||||
@Override
|
||||
public Object findOne(Serializable id) {
|
||||
return repository.findOne(id);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#exists(java.io.Serializable)
|
||||
*/
|
||||
@Override
|
||||
public boolean exists(Serializable id) {
|
||||
return repository.exists(id);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#findAll()
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Object> findAll() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#findAll(java.lang.Iterable)
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Object> findAll(Iterable<Serializable> ids) {
|
||||
return repository.findAll(ids);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#count()
|
||||
*/
|
||||
@Override
|
||||
public long count() {
|
||||
return repository.count();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#delete(java.io.Serializable)
|
||||
*/
|
||||
@Override
|
||||
public void delete(Serializable id) {
|
||||
repository.delete(id);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#delete(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void delete(Object entity) {
|
||||
repository.delete(entity);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#delete(java.lang.Iterable)
|
||||
*/
|
||||
@Override
|
||||
public void delete(Iterable<? extends Object> entities) {
|
||||
repository.delete(entities);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#deleteAll()
|
||||
*/
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
repository.deleteAll();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.invoke.RepositoryInvocationInformation#hasFindOne()
|
||||
*/
|
||||
@Override
|
||||
public boolean hasFindOne() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.invoke.RepositoryInvocationInformation#hasFindAll()
|
||||
*/
|
||||
@Override
|
||||
public boolean hasFindAll() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2013 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.repository.invoke;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class PagingAndSortingRepositoryInvoker extends CrudRepositoryInvoker {
|
||||
|
||||
private final PagingAndSortingRepository<Object, Serializable> repository;
|
||||
|
||||
/**
|
||||
* @param repository must not be {@literal null}.
|
||||
*/
|
||||
public PagingAndSortingRepositoryInvoker(PagingAndSortingRepository<Object, Serializable> repository) {
|
||||
super(repository);
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.invoke.CrudRepositoryInvoker#findAll(org.springframework.data.domain.Pageable)
|
||||
*/
|
||||
@Override
|
||||
public Page<Object> findAll(Pageable pageable) {
|
||||
return repository.findAll(pageable);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.invoke.CrudRepositoryInvoker#findAll(org.springframework.data.domain.Sort)
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Object> findAll(Sort sort) {
|
||||
return repository.findAll(sort);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2013 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.repository.invoke;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface RepositoryInvocationInformation {
|
||||
|
||||
boolean hasFindOne();
|
||||
|
||||
boolean hasFindAll();
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2013 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.repository.invoke;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface RepositoryInvoker extends PagingAndSortingRepository<Object, Serializable>,
|
||||
RepositoryInvocationInformation {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2013 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.repository.invoke;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RepositoryInvokerFactory {
|
||||
|
||||
private final Repositories repositories;
|
||||
private final Map<Class<?>, RepositoryInvoker> invokers;
|
||||
|
||||
/**
|
||||
* @param repositories
|
||||
* @param invokers
|
||||
*/
|
||||
public RepositoryInvokerFactory(Repositories repositories) {
|
||||
|
||||
this.repositories = repositories;
|
||||
this.invokers = new HashMap<Class<?>, RepositoryInvoker>();
|
||||
prepareInvokers(repositories);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private final void prepareInvokers(Repositories repositories) {
|
||||
|
||||
for (Class<?> domainType : repositories) {
|
||||
|
||||
Object repository = repositories.getRepositoryFor(domainType);
|
||||
RepositoryInvoker invoker = null;
|
||||
|
||||
if (repository instanceof PagingAndSortingRepository) {
|
||||
invoker = new PagingAndSortingRepositoryInvoker((PagingAndSortingRepository<Object, Serializable>) repository);
|
||||
} else if (repository instanceof CrudRepository) {
|
||||
invoker = new CrudRepositoryInvoker((CrudRepository<Object, Serializable>) repository);
|
||||
} else {
|
||||
invoker = new RepositoryMethodInvoker(repository, null, null);
|
||||
}
|
||||
|
||||
invokers.put(domainType, invoker);
|
||||
}
|
||||
}
|
||||
|
||||
public RepositoryInvoker getInvokerFor(Class<?> domainType) {
|
||||
return invokers.get(domainType);
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.rest.repository.support.ResourceMappingUtils;
|
||||
import org.springframework.util.ReflectionUtils.MethodCallback;
|
||||
@@ -22,7 +21,7 @@ import org.springframework.util.ReflectionUtils.MethodCallback;
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class RepositoryMethodInvoker implements PagingAndSortingRepository<Object, Serializable> {
|
||||
public class RepositoryMethodInvoker implements RepositoryInvoker {
|
||||
|
||||
private final Object repository;
|
||||
private final Map<String, RepositoryMethod> queryMethods = new HashMap<String, RepositoryMethod>();
|
||||
@@ -57,11 +56,11 @@ public class RepositoryMethodInvoker implements PagingAndSortingRepository<Objec
|
||||
}
|
||||
String name = method.getName();
|
||||
int cardinality = method.getParameterTypes().length;
|
||||
Class<?> paramType = (cardinality == 1 ? method.getParameterTypes()[0] : null);
|
||||
boolean someMethod = (null != paramType && Iterable.class.isAssignableFrom(paramType));
|
||||
boolean byIdMethod = (null != paramType && paramType == Serializable.class);
|
||||
boolean sortable = (null != paramType && Sort.class.isAssignableFrom(paramType));
|
||||
boolean pageable = (null != paramType && Pageable.class.isAssignableFrom(paramType));
|
||||
Class<?> paramType = cardinality == 1 ? method.getParameterTypes()[0] : null;
|
||||
boolean someMethod = null != paramType && Iterable.class.isAssignableFrom(paramType);
|
||||
boolean byIdMethod = null != paramType && paramType == Serializable.class;
|
||||
boolean sortable = null != paramType && Sort.class.isAssignableFrom(paramType);
|
||||
boolean pageable = null != paramType && Pageable.class.isAssignableFrom(paramType);
|
||||
RepositoryMethod repoMethod = new RepositoryMethod(method);
|
||||
|
||||
if ("save".equals(name) && someMethod) {
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
package org.springframework.data.rest.repository.support;
|
||||
|
||||
import static org.springframework.data.rest.repository.support.ResourceMappingUtils.*;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.config.ResourceMapping;
|
||||
import org.springframework.data.rest.repository.invoke.RepositoryMethod;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class RepositoryInformationSupport {
|
||||
|
||||
protected Repositories repositories;
|
||||
protected RepositoryRestConfiguration config;
|
||||
protected MultiValueMap<Class<?>, RepositoryMethod> repositoryMethods = new LinkedMultiValueMap<Class<?>, RepositoryMethod>();
|
||||
|
||||
public Repositories getRepositories() {
|
||||
return repositories;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setRepositories(Repositories repositories) {
|
||||
this.repositories = repositories;
|
||||
for (Class<?> domainType : repositories) {
|
||||
final RepositoryInformation repoInfo = repositories.getRepositoryInformationFor(domainType);
|
||||
doWithMethods(repoInfo.getRepositoryInterface(), new MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
repositoryMethods.add(repoInfo.getRepositoryInterface(), new RepositoryMethod(method));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public RepositoryRestConfiguration getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setConfig(RepositoryRestConfiguration config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
protected RepositoryInformation findRepositoryInfoFor(String pathSegment) {
|
||||
if (!hasText(pathSegment)) {
|
||||
return null;
|
||||
}
|
||||
for (Class<?> domainType : repositories) {
|
||||
RepositoryInformation repoInfo = findRepositoryInfoFor(domainType);
|
||||
ResourceMapping mapping = getResourceMapping(config, repoInfo);
|
||||
if (pathSegment.equals(mapping.getPath()) && mapping.isExported()) {
|
||||
return repoInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected RepositoryInformation findRepositoryInfoFor(Class<?> domainType) {
|
||||
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(domainType);
|
||||
if (null != entity) {
|
||||
return repositories.getRepositoryInformationFor(domainType);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,12 +25,8 @@ import org.junit.Test;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
import org.springframework.data.rest.repository.domain.jpa.AnnotatedPersonRepository;
|
||||
import org.springframework.data.rest.repository.domain.jpa.Person;
|
||||
import org.springframework.data.rest.repository.domain.jpa.PlainPersonRepository;
|
||||
import org.springframework.data.rest.repository.mapping.RepositoryCollectionResourceMapping;
|
||||
import org.springframework.data.rest.repository.mapping.ResourceMapping;
|
||||
import org.springframework.hateoas.RelProvider;
|
||||
import org.springframework.hateoas.core.EvoInflectorRelProvider;
|
||||
@@ -44,27 +40,6 @@ import org.springframework.hateoas.core.EvoInflectorRelProvider;
|
||||
public class ResourceMappingUnitTests {
|
||||
|
||||
RelProvider relProvider = new EvoInflectorRelProvider();
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldDetectDefaultRelAndPath() throws Exception {
|
||||
|
||||
ResourceMapping newMapping = new RepositoryCollectionResourceMapping(PlainPersonRepository.class, relProvider);
|
||||
|
||||
assertThat(newMapping.getRel(), is("persons"));
|
||||
assertThat(newMapping.getPath(), is(new Path("person")));
|
||||
assertThat(newMapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDetectAnnotatedRelAndPath() throws Exception {
|
||||
|
||||
ResourceMapping newMapping = new RepositoryCollectionResourceMapping(AnnotatedPersonRepository.class, relProvider);
|
||||
|
||||
assertThat(newMapping.getRel(), is("people"));
|
||||
assertThat(newMapping.getPath(), is(new Path("person")));
|
||||
assertThat(newMapping.isExported(), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDetectPathAndRemoveLeadingSlashIfAny() {
|
||||
|
||||
@@ -56,6 +56,6 @@ public class RepositoryTestsConfig {
|
||||
|
||||
@Bean
|
||||
public UriDomainClassConverter uriDomainClassConverter() {
|
||||
return new UriDomainClassConverter();
|
||||
return new UriDomainClassConverter(repositories(), domainClassConverter());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.rest.config.ResourceMapping;
|
||||
import org.springframework.data.rest.repository.RepositoryConstraintViolationException;
|
||||
import org.springframework.data.rest.repository.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.webmvc.support.ExceptionMessage;
|
||||
import org.springframework.data.rest.webmvc.support.RepositoryConstraintViolationExceptionMessage;
|
||||
import org.springframework.data.rest.webmvc.support.ValidationExceptionHandler;
|
||||
@@ -196,8 +196,8 @@ class AbstractRepositoryRestController implements MessageSourceAware, Initializi
|
||||
}
|
||||
|
||||
protected Link resourceLink(RepositoryRestRequest repoRequest, Resource resource) {
|
||||
ResourceMapping repoMapping = repoRequest.getRepositoryResourceMapping();
|
||||
ResourceMapping entityMapping = repoRequest.getPersistentEntityResourceMapping();
|
||||
ResourceMetadata repoMapping = repoRequest.getRepositoryResourceMapping();
|
||||
ResourceMetadata entityMapping = repoRequest.getPersistentEntityResourceMapping();
|
||||
|
||||
Link selfLink = resource.getLink("self");
|
||||
String rel = repoMapping.getRel() + "." + entityMapping.getRel();
|
||||
@@ -205,11 +205,11 @@ class AbstractRepositoryRestController implements MessageSourceAware, Initializi
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
protected Resources resultToResources(Object result, Link baseLink) {
|
||||
protected Resources resultToResources(Object result) {
|
||||
|
||||
if (result instanceof Page) {
|
||||
Page<Object> page = (Page<Object>) result;
|
||||
return entitiesToResources(page, baseLink, assembler);
|
||||
return entitiesToResources(page, assembler);
|
||||
} else if (result instanceof Iterable) {
|
||||
return entitiesToResources((Iterable<Object>) result);
|
||||
} else if (null == result) {
|
||||
@@ -220,10 +220,10 @@ class AbstractRepositoryRestController implements MessageSourceAware, Initializi
|
||||
}
|
||||
}
|
||||
|
||||
protected Resources<? extends Resource<Object>> entitiesToResources(Page<Object> page, Link baseLink,
|
||||
final PagedResourcesAssembler<Object> assembler) {
|
||||
protected Resources<? extends Resource<Object>> entitiesToResources(Page<Object> page,
|
||||
PagedResourcesAssembler<Object> assembler) {
|
||||
|
||||
return assembler.toResource(page, perAssembler, baseLink);
|
||||
return assembler.toResource(page, perAssembler);
|
||||
}
|
||||
|
||||
protected Resources<Resource<Object>> entitiesToResources(Iterable<Object> entities) {
|
||||
|
||||
@@ -44,6 +44,7 @@ import org.springframework.data.rest.repository.context.BeforeCreateEvent;
|
||||
import org.springframework.data.rest.repository.context.BeforeDeleteEvent;
|
||||
import org.springframework.data.rest.repository.context.BeforeSaveEvent;
|
||||
import org.springframework.data.rest.repository.invoke.RepositoryMethodInvoker;
|
||||
import org.springframework.data.rest.repository.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.repository.support.DomainObjectMerger;
|
||||
import org.springframework.data.web.PagedResourcesAssembler;
|
||||
import org.springframework.hateoas.EntityLinks;
|
||||
@@ -134,14 +135,13 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
|
||||
ResourceMapping repoMapping = request.getRepositoryResourceMapping();
|
||||
ResourceMetadata repoMapping = request.getRepositoryResourceMapping();
|
||||
if (!repoMethodInvoker.getQueryMethods().isEmpty()) {
|
||||
links.add(entityLinks.linkForSingleResource(request.getPersistentEntity().getType(), "search").withRel(
|
||||
repoMapping.getRel() + ".search"));
|
||||
}
|
||||
|
||||
Link baseLink = request.getRepositoryLink();
|
||||
Resources<?> resources = resultToResources(results, baseLink);
|
||||
Resources<?> resources = resultToResources(results);
|
||||
resources.add(links);
|
||||
return resources;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2013 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 org.springframework.core.MethodParameter;
|
||||
import org.springframework.data.rest.repository.invoke.RepositoryInvoker;
|
||||
import org.springframework.data.rest.repository.invoke.RepositoryInvokerFactory;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RepositoryInvokerHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
private final RepositoryRestRequestHandlerMethodArgumentResolver requestResolver;
|
||||
private final RepositoryInvokerFactory invokerFactory;
|
||||
|
||||
/**
|
||||
* @param requestResolver
|
||||
* @param invokerFactory
|
||||
*/
|
||||
private RepositoryInvokerHandlerMethodArgumentResolver(
|
||||
RepositoryRestRequestHandlerMethodArgumentResolver requestResolver, RepositoryInvokerFactory invokerFactory) {
|
||||
this.requestResolver = requestResolver;
|
||||
this.invokerFactory = invokerFactory;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter(org.springframework.core.MethodParameter)
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
return RepositoryInvoker.class.isAssignableFrom(parameter.getParameterType());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory)
|
||||
*/
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
RepositoryRestRequest request = requestResolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
|
||||
return invokerFactory.getInvokerFor(request.getPersistentEntity().getType());
|
||||
}
|
||||
}
|
||||
@@ -15,19 +15,16 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.springframework.data.rest.core.util.UriUtils.*;
|
||||
import static org.springframework.data.rest.repository.support.ResourceMappingUtils.*;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.config.ResourceMapping;
|
||||
import org.springframework.data.rest.repository.invoke.RepositoryMethodInvoker;
|
||||
import org.springframework.data.rest.repository.mapping.ResourceMetadata;
|
||||
import org.springframework.hateoas.Link;
|
||||
|
||||
/**
|
||||
@@ -39,30 +36,22 @@ class RepositoryRestRequest {
|
||||
|
||||
private final HttpServletRequest request;
|
||||
private final URI baseUri;
|
||||
private final ResourceMapping repoMapping;
|
||||
private final ResourceMetadata resourceMetadata;
|
||||
private final Link repoLink;
|
||||
private final Object repository;
|
||||
private final RepositoryMethodInvoker repoMethodInvoker;
|
||||
private final PersistentEntity<?, ?> persistentEntity;
|
||||
private final ResourceMapping entityMapping;
|
||||
|
||||
public RepositoryRestRequest(RepositoryRestConfiguration config, Repositories repositories,
|
||||
HttpServletRequest request, URI baseUri, RepositoryInformation repoInfo, ConversionService conversionService) {
|
||||
HttpServletRequest request, URI baseUri, ResourceMetadata repoInfo, ConversionService conversionService) {
|
||||
this.request = request;
|
||||
this.baseUri = baseUri;
|
||||
this.repoMapping = getResourceMapping(config, repoInfo);
|
||||
if (null == repoMapping || !repoMapping.isExported()) {
|
||||
this.resourceMetadata = repoInfo;
|
||||
if (resourceMetadata == null || !resourceMetadata.isExported()) {
|
||||
this.repoLink = null;
|
||||
this.repository = null;
|
||||
this.repoMethodInvoker = null;
|
||||
this.persistentEntity = null;
|
||||
this.entityMapping = null;
|
||||
} else {
|
||||
this.repoLink = new Link(buildUri(baseUri, repoMapping.getPath()).toString(), repoMapping.getRel());
|
||||
this.repository = repositories.getRepositoryFor(repoInfo.getDomainType());
|
||||
this.persistentEntity = repositories.getPersistentEntity(repoInfo.getDomainType());
|
||||
this.repoMethodInvoker = new RepositoryMethodInvoker(repository, repoInfo, conversionService);
|
||||
this.entityMapping = getResourceMapping(config, persistentEntity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,12 +63,8 @@ class RepositoryRestRequest {
|
||||
return baseUri;
|
||||
}
|
||||
|
||||
ResourceMapping getRepositoryResourceMapping() {
|
||||
return repoMapping;
|
||||
}
|
||||
|
||||
Link getRepositoryLink() {
|
||||
return repoLink;
|
||||
ResourceMetadata getRepositoryResourceMapping() {
|
||||
return resourceMetadata;
|
||||
}
|
||||
|
||||
RepositoryMethodInvoker getRepositoryMethodInvoker() {
|
||||
@@ -89,8 +74,4 @@ class RepositoryRestRequest {
|
||||
PersistentEntity<?, ?> getPersistentEntity() {
|
||||
return persistentEntity;
|
||||
}
|
||||
|
||||
ResourceMapping getPersistentEntityResourceMapping() {
|
||||
return entityMapping;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,15 @@
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.repository.mapping.ResourceMetadata;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
@@ -39,25 +40,32 @@ public class RepositoryRestRequestHandlerMethodArgumentResolver implements Handl
|
||||
|
||||
@Autowired private RepositoryRestConfiguration config;
|
||||
@Autowired private Repositories repositories;
|
||||
@Autowired private RepositoryInformationHandlerMethodArgumentResolver repoInfoResolver;
|
||||
@Autowired private ResourceMetadataHandlerMethodArgumentResolver repoInfoResolver;
|
||||
@Autowired private BaseUriMethodArgumentResolver baseUriResolver;
|
||||
|
||||
public RepositoryRestRequestHandlerMethodArgumentResolver(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter(org.springframework.core.MethodParameter)
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
return RepositoryRestRequest.class.isAssignableFrom(parameter.getParameterType());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory)
|
||||
*/
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
public RepositoryRestRequest resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
URI baseUri = (URI) baseUriResolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
|
||||
RepositoryInformation repoInfo = repoInfoResolver.resolveArgument(parameter, mavContainer, webRequest,
|
||||
binderFactory);
|
||||
URI baseUri = baseUriResolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
|
||||
ResourceMetadata repoInfo = repoInfoResolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
|
||||
|
||||
return new RepositoryRestRequest(config, repositories, webRequest.getNativeRequest(HttpServletRequest.class),
|
||||
baseUri, repoInfo, conversionService);
|
||||
|
||||
@@ -16,12 +16,16 @@
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.springframework.util.ClassUtils.*;
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.rest.repository.support.RepositoryInformationSupport;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.repository.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.repository.mapping.ResourceMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
@@ -32,16 +36,39 @@ import org.springframework.web.util.UrlPathHelper;
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RepositoryInformationHandlerMethodArgumentResolver extends RepositoryInformationSupport implements
|
||||
HandlerMethodArgumentResolver {
|
||||
public class ResourceMetadataHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
private final Repositories repositories;
|
||||
private final ResourceMappings mappings;
|
||||
|
||||
/**
|
||||
* @param repositories must not be {@literal null}.
|
||||
* @param mappings must not be {@literal null}.
|
||||
*/
|
||||
public ResourceMetadataHandlerMethodArgumentResolver(Repositories repositories, ResourceMappings mappings) {
|
||||
|
||||
Assert.notNull(repositories, "Repositories must not be null!");
|
||||
Assert.notNull(mappings, "ResourceMappings must not be null!");
|
||||
|
||||
this.repositories = repositories;
|
||||
this.mappings = mappings;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter(org.springframework.core.MethodParameter)
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
return isAssignable(parameter.getParameterType(), RepositoryInformation.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory)
|
||||
*/
|
||||
@Override
|
||||
public RepositoryInformation resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
public ResourceMetadata resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
@@ -60,4 +87,20 @@ public class RepositoryInformationHandlerMethodArgumentResolver extends Reposito
|
||||
|
||||
return findRepositoryInfoFor(parts[0]);
|
||||
}
|
||||
|
||||
private ResourceMetadata findRepositoryInfoFor(String pathSegment) {
|
||||
|
||||
if (!hasText(pathSegment)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Class<?> domainType : repositories) {
|
||||
ResourceMetadata mapping = mappings.getMappingFor(domainType);
|
||||
if (pathSegment.equals(mapping.getPath()) && mapping.isExported()) {
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package org.springframework.data.rest.webmvc.json;
|
||||
import static org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.*;
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -11,7 +12,6 @@ import java.util.Set;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.data.mapping.Association;
|
||||
@@ -19,40 +19,53 @@ import org.springframework.data.mapping.AssociationHandler;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.repository.annotation.Description;
|
||||
import org.springframework.data.rest.repository.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.repository.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.repository.support.RepositoryInformationSupport;
|
||||
import org.springframework.data.rest.webmvc.support.RepositoryLinkBuilder;
|
||||
import org.springframework.hateoas.Link;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class PersistentEntityToJsonSchemaConverter extends RepositoryInformationSupport implements
|
||||
ConditionalGenericConverter, InitializingBean {
|
||||
public class PersistentEntityToJsonSchemaConverter implements ConditionalGenericConverter {
|
||||
|
||||
private static final TypeDescriptor STRING_TYPE = TypeDescriptor.valueOf(String.class);
|
||||
private static final TypeDescriptor SCHEMA_TYPE = TypeDescriptor.valueOf(JsonSchema.class);
|
||||
private Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>();
|
||||
private ResourceMappings mappings;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
private final Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>();
|
||||
private final ResourceMappings mappings;
|
||||
private final Repositories repositories;
|
||||
|
||||
/**
|
||||
* @param repositories must not be {@literal null}.
|
||||
* @param mappings must not be {@literal null}.
|
||||
*/
|
||||
public PersistentEntityToJsonSchemaConverter(Repositories repositories, ResourceMappings mappings) {
|
||||
|
||||
this.repositories = repositories;
|
||||
this.mappings = mappings;
|
||||
|
||||
for (Class<?> domainType : repositories) {
|
||||
convertiblePairs.add(new ConvertiblePair(domainType, JsonSchema.class));
|
||||
}
|
||||
|
||||
this.mappings = new ResourceMappings(config, repositories);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.ConditionalConverter#matches(org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return (Class.class.isAssignableFrom(sourceType.getType()) && JsonSchema.class.isAssignableFrom(targetType
|
||||
.getType()));
|
||||
return Class.class.isAssignableFrom(sourceType.getType())
|
||||
&& JsonSchema.class.isAssignableFrom(targetType.getType());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.GenericConverter#getConvertibleTypes()
|
||||
*/
|
||||
@Override
|
||||
public Set<ConvertiblePair> getConvertibleTypes() {
|
||||
return convertiblePairs;
|
||||
@@ -68,8 +81,8 @@ public class PersistentEntityToJsonSchemaConverter extends RepositoryInformation
|
||||
|
||||
PersistentEntity<?, ?> persistentEntity = repositories.getPersistentEntity((Class<?>) source);
|
||||
final ResourceMetadata metadata = mappings.getMappingFor(persistentEntity.getClass());
|
||||
String entityDesc = persistentEntity.getType().isAnnotationPresent(Description.class) ? ((Description) persistentEntity
|
||||
.getType().getAnnotation(Description.class)).value() : null;
|
||||
String entityDesc = persistentEntity.getType().isAnnotationPresent(Description.class) ? persistentEntity.getType()
|
||||
.getAnnotation(Description.class).value() : null;
|
||||
|
||||
final JsonSchema jsonSchema = new JsonSchema(persistentEntity.getName(), entityDesc);
|
||||
persistentEntity.doWithProperties(new PropertyHandler() {
|
||||
@@ -77,10 +90,10 @@ public class PersistentEntityToJsonSchemaConverter extends RepositoryInformation
|
||||
public void doWithPersistentProperty(PersistentProperty persistentProperty) {
|
||||
Class<?> propertyType = persistentProperty.getType();
|
||||
String type = uncapitalize(propertyType.getSimpleName());
|
||||
boolean notNull = (persistentProperty.getField().isAnnotationPresent(Nonnull.class) || persistentProperty
|
||||
.getGetter().isAnnotationPresent(Nonnull.class))
|
||||
|| (persistentProperty.getField().isAnnotationPresent(NotNull.class) || persistentProperty.getGetter()
|
||||
.isAnnotationPresent(NotNull.class));
|
||||
boolean notNull = persistentProperty.getField().isAnnotationPresent(Nonnull.class)
|
||||
|| persistentProperty.getGetter().isAnnotationPresent(Nonnull.class)
|
||||
|| persistentProperty.getField().isAnnotationPresent(NotNull.class)
|
||||
|| persistentProperty.getGetter().isAnnotationPresent(NotNull.class);
|
||||
String desc = persistentProperty.getField().isAnnotationPresent(Description.class) ? persistentProperty
|
||||
.getField().getAnnotation(Description.class).value() : persistentProperty.getGetter().isAnnotationPresent(
|
||||
Description.class) ? persistentProperty.getGetter().getAnnotation(Description.class).value() : null;
|
||||
@@ -98,14 +111,21 @@ public class PersistentEntityToJsonSchemaConverter extends RepositoryInformation
|
||||
final List<Link> links = new ArrayList<Link>();
|
||||
|
||||
persistentEntity.doWithAssociations(new AssociationHandler() {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.AssociationHandler#doWithAssociation(org.springframework.data.mapping.Association)
|
||||
*/
|
||||
@Override
|
||||
public void doWithAssociation(Association association) {
|
||||
|
||||
PersistentProperty persistentProperty = association.getInverse();
|
||||
|
||||
if (!metadata.isMapped(persistentProperty)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RepositoryLinkBuilder builder = new RepositoryLinkBuilder(metadata, config.getBaseUri()).slash("{id}");
|
||||
RepositoryLinkBuilder builder = new RepositoryLinkBuilder(metadata, URI.create("{id}"));
|
||||
maybeAddAssociationLink(builder, mappings, persistentProperty, links);
|
||||
}
|
||||
});
|
||||
@@ -114,5 +134,4 @@ public class PersistentEntityToJsonSchemaConverter extends RepositoryInformation
|
||||
|
||||
return jsonSchema;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user