Add explicit transactional semantics to the deleteEntity method because of problems with Neo4J support.

This commit is contained in:
Jon Brisbin
2013-03-13 11:14:48 -05:00
committed by Jon Brisbin
parent 8d89cc2ffe
commit 94328592f4
5 changed files with 47 additions and 55 deletions

View File

@@ -1,37 +0,0 @@
package org.springframework.data.rest.repository;
import org.springframework.data.domain.Pageable;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Resources;
/**
* @author Jon Brisbin
*/
public class PageableResources<T> extends Resources<T> {
private Pageable page;
protected PageableResources() {
super();
}
public PageableResources(Iterable<T> content, Pageable page, Link... links) {
super(content, links);
this.page = page;
}
public PageableResources(Iterable<T> content, Pageable page, Iterable<Link> links) {
super(content, links);
this.page = page;
}
public Pageable getPage() {
return page;
}
public PageableResources<T> setPage(Pageable page) {
this.page = page;
return this;
}
}

View File

@@ -1,5 +1,6 @@
package org.springframework.data.rest.repository.invoke;
import static org.springframework.data.rest.repository.support.ResourceMappingUtils.getResourceMapping;
import static org.springframework.util.ReflectionUtils.*;
import java.io.Serializable;
@@ -13,6 +14,8 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.rest.config.RepositoryRestConfiguration;
import org.springframework.data.rest.config.ResourceMapping;
/**
* @author Jon Brisbin
@@ -38,14 +41,14 @@ public class RepositoryMethodInvoker implements PagingAndSortingRepository<Objec
@SuppressWarnings({"unchecked"})
public RepositoryMethodInvoker(Object repository,
RepositoryInformation repoInfo,
final PersistentEntity persistentEntity) {
RepositoryRestConfiguration config) {
this.repository = repository;
Class<?> repoType = repoInfo.getRepositoryInterface();
doWithMethods(repoType, new MethodCallback() {
@Override public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
String name = method.getName();
int cardinality = method.getParameterTypes().length;
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);

View File

@@ -49,6 +49,7 @@ public class PersistentEntityToJsonSchemaConverter
return (Class.class.isAssignableFrom(sourceType.getType()) && JsonSchema.class.isAssignableFrom(targetType.getType()));
}
@Override public Set<ConvertiblePair> getConvertibleTypes() {
return convertiblePairs;
}

View File

@@ -15,6 +15,7 @@ import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@@ -53,6 +54,8 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@@ -61,7 +64,8 @@ import org.springframework.web.util.UriComponentsBuilder;
/**
* @author Jon Brisbin
*/
public class AbstractRepositoryRestController implements ApplicationContextAware {
public class AbstractRepositoryRestController implements ApplicationContextAware,
InitializingBean {
static final Resource<?> EMPTY_RESOURCE = new Resource<Object>(Collections.emptyList());
static final Resources<Resource<?>> EMPTY_RESOURCES = new Resources<Resource<?>>(Collections.<Resource<?>>emptyList());
@@ -77,6 +81,9 @@ public class AbstractRepositoryRestController implements ApplicationContextAware
protected ApplicationContext applicationContext;
@Autowired(required = false)
protected ValidationExceptionHandler handler;
@Autowired(required = false)
protected PlatformTransactionManager txMgr;
protected TransactionTemplate txTmpl;
@Autowired
public AbstractRepositoryRestController(Repositories repositories,
@@ -96,6 +103,13 @@ public class AbstractRepositoryRestController implements ApplicationContextAware
this.applicationContext = applicationContext;
}
@Override public void afterPropertiesSet() throws Exception {
if(null != txMgr) {
txTmpl = new TransactionTemplate(txMgr);
txTmpl.afterPropertiesSet();
}
}
@ExceptionHandler({
NullPointerException.class
})

View File

@@ -39,6 +39,8 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@@ -311,32 +313,41 @@ public class RepositoryEntityController extends AbstractRepositoryRestController
method = RequestMethod.DELETE
)
@ResponseBody
public ResponseEntity<?> deleteEntity(RepositoryRestRequest repoRequest,
@PathVariable String id)
public ResponseEntity<?> deleteEntity(final RepositoryRestRequest repoRequest,
@PathVariable final String id)
throws ResourceNotFoundException {
RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker();
final RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker();
if(null == repoMethodInvoker || (!repoMethodInvoker.hasFindOne()
&& !(repoMethodInvoker.hasDeleteOne() || repoMethodInvoker.hasDeleteOneById()))) {
throw new NoSuchMethodError();
}
Object domainObj = domainClassConverter.convert(id,
STRING_TYPE,
TypeDescriptor.valueOf(repoRequest.getPersistentEntity()
.getType()));
final Object domainObj = domainClassConverter.convert(id,
STRING_TYPE,
TypeDescriptor.valueOf(repoRequest.getPersistentEntity()
.getType()));
if(null == domainObj) {
throw new ResourceNotFoundException();
}
applicationContext.publishEvent(new BeforeDeleteEvent(domainObj));
if(repoMethodInvoker.hasDeleteOneById()) {
Class<? extends Serializable> idType = (Class<? extends Serializable>)repoRequest.getPersistentEntity()
.getIdProperty()
.getType();
Object idVal = conversionService.convert(id, idType);
repoMethodInvoker.delete((Serializable)idVal);
} else if(repoMethodInvoker.hasDeleteOne()) {
repoMethodInvoker.delete(domainObj);
TransactionCallbackWithoutResult callback = new TransactionCallbackWithoutResult() {
@Override protected void doInTransactionWithoutResult(TransactionStatus status) {
if(repoMethodInvoker.hasDeleteOneById()) {
Class<? extends Serializable> idType = (Class<? extends Serializable>)repoRequest.getPersistentEntity()
.getIdProperty()
.getType();
final Serializable idVal = conversionService.convert(id, idType);
repoMethodInvoker.delete(idVal);
} else if(repoMethodInvoker.hasDeleteOne()) {
repoMethodInvoker.delete(domainObj);
}
}
};
if(null != txTmpl) {
txTmpl.execute(callback);
} else {
callback.doInTransaction(null);
}
applicationContext.publishEvent(new AfterDeleteEvent(domainObj));