DATACMNS-293 - Further refinements in soft delete support.

Improved the template methods in AbstractSoftDeleteQueryAugmentor to accommodate more complex scenarios (see DATAJPA-307). Added DirectFieldAccessFallbackBeanWrapper from SD JPA to use it for looking up property values.
This commit is contained in:
Oliver Gierke
2013-10-09 15:45:12 +02:00
committed by Oliver Gierke
parent 2550c15166
commit 9c9904686b
3 changed files with 28 additions and 35 deletions

View File

@@ -15,16 +15,14 @@
*/
package org.springframework.data.repository.augment;
import org.springframework.beans.ConfigurablePropertyAccessor;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyAccessor;
import org.springframework.beans.BeanWrapper;
import org.springframework.data.repository.SoftDelete;
import org.springframework.validation.DataBinder;
import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper;
/**
* Base class to implement a {@link QueryAugmentor} to soft-delete entities.
*
* @since 1.6
* @since 1.7
* @author Oliver Gierke
*/
public abstract class AbstractSoftDeleteQueryAugmentor<Q extends QueryContext<?>, N extends QueryContext<?>, U extends UpdateContext<?>>
@@ -48,26 +46,32 @@ public abstract class AbstractSoftDeleteQueryAugmentor<Q extends QueryContext<?>
return context;
}
CustomDataBinder binder = new CustomDataBinder(entity);
binder.initDirectFieldAccess();
BeanWrapper wrapper = createBeanWrapper(context);
Object currentValue = binder.getPropertyAccessor().getPropertyValue(property);
Object currentValue = wrapper.getPropertyValue(property);
Object nextValue = annotation.flagMode().toDeletedValue(currentValue);
if (nextValue == null) {
return context;
}
MutablePropertyValues values = new MutablePropertyValues();
values.add(property, nextValue);
binder.bind(values);
wrapper.setPropertyValue(property, nextValue);
updateDeletedState(entity, context);
return null;
}
/**
* Creates a new {@link BeanWrapper} for the given {@link UpdateContext}. Defaults to a
* {@link DirectFieldAccessFallbackBeanWrapper}.
*
* @param context will never be {@literal null}.
* @return
*/
protected BeanWrapper createBeanWrapper(U context) {
return new DirectFieldAccessFallbackBeanWrapper(context.getEntity());
}
/**
* Update the entity using the API exposed in the given {@link UpdateContext}.
*
@@ -75,21 +79,4 @@ public abstract class AbstractSoftDeleteQueryAugmentor<Q extends QueryContext<?>
* @param context will never be {@literal null}.
*/
public abstract void updateDeletedState(Object entity, U context);
/**
* Custom {@link DataBinder} to expose the {@link PropertyAccessor} used.
*
* @author Oliver Gierke
*/
private static class CustomDataBinder extends DataBinder {
public CustomDataBinder(Object target) {
super(target);
}
@Override
public ConfigurablePropertyAccessor getPropertyAccessor() {
return super.getPropertyAccessor();
}
}
}

View File

@@ -109,13 +109,17 @@ public abstract class AnnotationBasedQueryAugmentor<T extends Annotation, Q exte
return null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.augment.QueryAugmentor#augmentNativeQuery(org.springframework.data.repository.augment.QueryContext, org.springframework.data.repository.augment.MethodMetadata)
*/
public final N augmentNativeQuery(N context, MethodMetadata metadata) {
return null;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.JpaQueryAugmentor#augmentQuery(javax.persistence.criteria.CriteriaQuery, org.springframework.data.repository.core.support.MethodMetadata)
* @see org.springframework.data.repository.augment.QueryAugmentor#augmentQuery(org.springframework.data.repository.augment.QueryContext, org.springframework.data.repository.augment.MethodMetadata)
*/
public final Q augmentQuery(Q context, MethodMetadata metadata) {
@@ -129,9 +133,9 @@ public abstract class AnnotationBasedQueryAugmentor<T extends Annotation, Q exte
return expression == null ? context : prepareQuery(context, expression);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.QueryAugmentor#augmentUpdate(org.springframework.data.repository.core.support.UpdateContext, org.springframework.data.repository.core.support.MethodMetadata)
* @see org.springframework.data.repository.augment.QueryAugmentor#augmentUpdate(org.springframework.data.repository.augment.UpdateContext, org.springframework.data.repository.augment.MethodMetadata)
*/
public final U augmentUpdate(U update, MethodMetadata metadata) {

View File

@@ -28,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.ProxyMethodInvocation;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
@@ -636,6 +637,7 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryProxyPostProcessor#postProcess(org.springframework.aop.framework.ProxyFactory, org.springframework.data.repository.core.RepositoryInformation)
*/
@Override
public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) {
factory.addAdvice(ExposeInvocationInterceptor.INSTANCE);
}
@@ -664,7 +666,7 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
if (invocation instanceof ReflectiveMethodInvocation) {
Advised proxy = (Advised) ((ReflectiveMethodInvocation) invocation).getProxy();
return Arrays.asList((Class<?>[]) proxy.getProxiedInterfaces());
return Arrays.asList(proxy.getProxiedInterfaces());
}
return Collections.<Class<?>> singletonList(getMethodInvocation().getThis().getClass());