diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/annotation/HandleAfterCreate.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/annotation/HandleAfterCreate.java new file mode 100644 index 000000000..ec9ec9683 --- /dev/null +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/annotation/HandleAfterCreate.java @@ -0,0 +1,22 @@ +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; + +/** + * @author Jon Brisbin + */ +@Target({ + ElementType.TYPE, + ElementType.METHOD + }) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface HandleAfterCreate { + + Class[] value() default {}; + +} diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/annotation/HandleBeforeCreate.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/annotation/HandleBeforeCreate.java new file mode 100644 index 000000000..06cd5850d --- /dev/null +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/annotation/HandleBeforeCreate.java @@ -0,0 +1,22 @@ +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; + +/** + * @author Jon Brisbin + */ +@Target({ + ElementType.TYPE, + ElementType.METHOD + }) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface HandleBeforeCreate { + + Class[] value() default {}; + +} diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/AbstractRepositoryEventListener.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/AbstractRepositoryEventListener.java index 6b91786c4..31c333eeb 100644 --- a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/AbstractRepositoryEventListener.java +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/AbstractRepositoryEventListener.java @@ -16,117 +16,139 @@ import org.springframework.context.ApplicationListener; public abstract class AbstractRepositoryEventListener implements ApplicationListener, ApplicationContextAware { - private final Class INTERESTED_TYPE = resolveTypeArgument(getClass(), AbstractRepositoryEventListener.class); - protected ApplicationContext applicationContext; + private final Class INTERESTED_TYPE = resolveTypeArgument(getClass(), AbstractRepositoryEventListener.class); + protected ApplicationContext applicationContext; - @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } + @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } - @SuppressWarnings({"unchecked"}) - @Override public final void onApplicationEvent(RepositoryEvent event) { - Class srcType = event.getSource().getClass(); - if(null != INTERESTED_TYPE && !INTERESTED_TYPE.isAssignableFrom(srcType)) { - return; - } + @SuppressWarnings({"unchecked"}) + @Override public final void onApplicationEvent(RepositoryEvent event) { + Class srcType = event.getSource().getClass(); + if(null != INTERESTED_TYPE && !INTERESTED_TYPE.isAssignableFrom(srcType)) { + return; + } - if(event instanceof BeforeSaveEvent) { - onBeforeSave((T)event.getSource()); - } else if(event instanceof AfterSaveEvent) { - onAfterSave((T)event.getSource()); - } else if(event instanceof BeforeLinkSaveEvent) { - onBeforeLinkSave((T)event.getSource(), ((BeforeLinkSaveEvent)event).getLinked()); - } else if(event instanceof AfterLinkSaveEvent) { - onAfterLinkSave((T)event.getSource(), ((AfterLinkSaveEvent)event).getLinked()); - } else if(event instanceof BeforeLinkDeleteEvent) { - onBeforeLinkDelete((T)event.getSource(), ((BeforeLinkDeleteEvent)event).getLinked()); - } else if(event instanceof AfterLinkDeleteEvent) { - onAfterLinkDelete((T)event.getSource(), ((AfterLinkDeleteEvent)event).getLinked()); - } else if(event instanceof BeforeDeleteEvent) { - onBeforeDelete((T)event.getSource()); - } else if(event instanceof AfterDeleteEvent) { - onAfterDelete((T)event.getSource()); - } - } + if(event instanceof BeforeSaveEvent) { + onBeforeSave((T)event.getSource()); + } else if(event instanceof BeforeCreateEvent) { + onBeforeCreate((T)event.getSource()); + } else if(event instanceof AfterCreateEvent) { + onAfterCreate((T)event.getSource()); + } else if(event instanceof AfterSaveEvent) { + onAfterSave((T)event.getSource()); + } else if(event instanceof BeforeLinkSaveEvent) { + onBeforeLinkSave((T)event.getSource(), ((BeforeLinkSaveEvent)event).getLinked()); + } else if(event instanceof AfterLinkSaveEvent) { + onAfterLinkSave((T)event.getSource(), ((AfterLinkSaveEvent)event).getLinked()); + } else if(event instanceof BeforeLinkDeleteEvent) { + onBeforeLinkDelete((T)event.getSource(), ((BeforeLinkDeleteEvent)event).getLinked()); + } else if(event instanceof AfterLinkDeleteEvent) { + onAfterLinkDelete((T)event.getSource(), ((AfterLinkDeleteEvent)event).getLinked()); + } else if(event instanceof BeforeDeleteEvent) { + onBeforeDelete((T)event.getSource()); + } else if(event instanceof AfterDeleteEvent) { + onAfterDelete((T)event.getSource()); + } + } - /** - * Override this method if you are interested in {@literal beforeSave} events. - * - * @param entity - * The entity being saved. - */ - protected void onBeforeSave(T entity) { - } + /** + * Override this method if you are interested in {@literal beforeCreate} events. + * + * @param entity + * The entity being created. + */ + protected void onBeforeCreate(T entity) { + } - /** - * Override this method if you are interested in {@literal afterSave} events. - * - * @param entity - * The entity that was just saved. - */ - protected void onAfterSave(T entity) { - } + /** + * Override this method if you are interested in {@literal afterCreate} events. + * + * @param entity + * The entity that was created. + */ + protected void onAfterCreate(T entity) { + } - /** - * Override this method if you are interested in {@literal beforeLinkSave} events. - * - * @param parent - * The parent entity to which the child object is linked. - * @param linked - * The linked, child entity. - */ - protected void onBeforeLinkSave(T parent, Object linked) { - } + /** + * Override this method if you are interested in {@literal beforeSave} events. + * + * @param entity + * The entity being saved. + */ + protected void onBeforeSave(T entity) { + } - /** - * Override this method if you are interested in {@literal afterLinkSave} events. - * - * @param parent - * The parent entity to which the child object is linked. - * @param linked - * The linked, child entity. - */ - protected void onAfterLinkSave(T parent, Object linked) { - } + /** + * Override this method if you are interested in {@literal afterSave} events. + * + * @param entity + * The entity that was just saved. + */ + protected void onAfterSave(T entity) { + } - /** - * Override this method if you are interested in {@literal beforeLinkDelete} events. - * - * @param parent - * The parent entity to which the child object is linked. - * @param linked - * The linked, child entity. - */ - protected void onBeforeLinkDelete(T parent, Object linked) { - } + /** + * Override this method if you are interested in {@literal beforeLinkSave} events. + * + * @param parent + * The parent entity to which the child object is linked. + * @param linked + * The linked, child entity. + */ + protected void onBeforeLinkSave(T parent, Object linked) { + } - /** - * Override this method if you are interested in {@literal afterLinkDelete} events. - * - * @param parent - * The parent entity to which the child object is linked. - * @param linked - * The linked, child entity. - */ - protected void onAfterLinkDelete(T parent, Object linked) { - } + /** + * Override this method if you are interested in {@literal afterLinkSave} events. + * + * @param parent + * The parent entity to which the child object is linked. + * @param linked + * The linked, child entity. + */ + protected void onAfterLinkSave(T parent, Object linked) { + } - /** - * Override this method if you are interested in {@literal beforeDelete} events. - * - * @param entity - * The entity that is being deleted. - */ - protected void onBeforeDelete(T entity) { - } + /** + * Override this method if you are interested in {@literal beforeLinkDelete} events. + * + * @param parent + * The parent entity to which the child object is linked. + * @param linked + * The linked, child entity. + */ + protected void onBeforeLinkDelete(T parent, Object linked) { + } - /** - * Override this method if you are interested in {@literal afterDelete} events. - * - * @param entity - * The entity that was just deleted. - */ - protected void onAfterDelete(T entity) { - } + /** + * Override this method if you are interested in {@literal afterLinkDelete} events. + * + * @param parent + * The parent entity to which the child object is linked. + * @param linked + * The linked, child entity. + */ + protected void onAfterLinkDelete(T parent, Object linked) { + } + + /** + * Override this method if you are interested in {@literal beforeDelete} events. + * + * @param entity + * The entity that is being deleted. + */ + protected void onBeforeDelete(T entity) { + } + + /** + * Override this method if you are interested in {@literal afterDelete} events. + * + * @param entity + * The entity that was just deleted. + */ + protected void onAfterDelete(T entity) { + } } diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/AfterCreateEvent.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/AfterCreateEvent.java new file mode 100644 index 000000000..38e3bc4e3 --- /dev/null +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/AfterCreateEvent.java @@ -0,0 +1,12 @@ +package org.springframework.data.rest.repository.context; + +/** + * Event that is emitted after a new entity is saved. + * + * @author Jon Brisbin + */ +public class AfterCreateEvent extends RepositoryEvent { + public AfterCreateEvent(Object source) { + super(source); + } +} diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/AnnotatedHandlerBeanPostProcessor.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/AnnotatedHandlerBeanPostProcessor.java index c0280165e..db1a682f2 100644 --- a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/AnnotatedHandlerBeanPostProcessor.java +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/AnnotatedHandlerBeanPostProcessor.java @@ -14,10 +14,12 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ApplicationListener; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.data.rest.repository.annotation.HandleAfterCreate; import org.springframework.data.rest.repository.annotation.HandleAfterDelete; import org.springframework.data.rest.repository.annotation.HandleAfterLinkDelete; import org.springframework.data.rest.repository.annotation.HandleAfterLinkSave; import org.springframework.data.rest.repository.annotation.HandleAfterSave; +import org.springframework.data.rest.repository.annotation.HandleBeforeCreate; import org.springframework.data.rest.repository.annotation.HandleBeforeDelete; import org.springframework.data.rest.repository.annotation.HandleBeforeLinkDelete; import org.springframework.data.rest.repository.annotation.HandleBeforeLinkSave; @@ -32,146 +34,148 @@ import org.springframework.util.ReflectionUtils; public class AnnotatedHandlerBeanPostProcessor implements ApplicationListener, BeanPostProcessor { - private static final Logger LOG = LoggerFactory.getLogger(AnnotatedHandlerBeanPostProcessor.class); + private static final Logger LOG = LoggerFactory.getLogger( + AnnotatedHandlerBeanPostProcessor.class); + private Multimap, EventHandlerMethod> handlerMethods = ArrayListMultimap + .create(); - private Multimap, EventHandlerMethod> handlerMethods = ArrayListMultimap.create(); + @Override public void onApplicationEvent(RepositoryEvent event) { + Class eventType = event.getClass(); + if(!handlerMethods.containsKey(eventType)) { + return; + } - @Override public void onApplicationEvent(RepositoryEvent event) { - Class eventType = event.getClass(); - if(!handlerMethods.containsKey(eventType)) { - return; - } + for(EventHandlerMethod handlerMethod : handlerMethods.get(eventType)) { + try { + Object src = event.getSource(); - for(EventHandlerMethod handlerMethod : handlerMethods.get(eventType)) { - try { - Object src = event.getSource(); + if(!ClassUtils.isAssignable(handlerMethod.targetType, src.getClass())) { + continue; + } - if(!ClassUtils.isAssignable(handlerMethod.targetType, src.getClass())) { - continue; - } + List params = new ArrayList(); + params.add(src); + if(event instanceof BeforeLinkSaveEvent) { + params.add(((BeforeLinkSaveEvent)event).getLinked()); + } else if(event instanceof AfterLinkSaveEvent) { + params.add(((AfterLinkSaveEvent)event).getLinked()); + } - List params = new ArrayList(); - params.add(src); - if(event instanceof BeforeLinkSaveEvent) { - params.add(((BeforeLinkSaveEvent)event).getLinked()); - } else if(event instanceof AfterLinkSaveEvent) { - params.add(((AfterLinkSaveEvent)event).getLinked()); - } + if(LOG.isDebugEnabled()) { + LOG.debug("Invoking " + event.getClass().getSimpleName() + " handler for " + event.getSource()); + } + handlerMethod.method.invoke(handlerMethod.handler, params.toArray()); - if(LOG.isDebugEnabled()) { - LOG.debug("Invoking " + event.getClass().getSimpleName() + " handler for " + event.getSource()); - } - handlerMethod.method.invoke(handlerMethod.handler, params.toArray()); + } catch(Exception e) { + throw new IllegalStateException(e); + } + } + } - } catch(Exception e) { - throw new IllegalStateException(e); - } - } - } + @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + return bean; + } - @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - return bean; - } + @Override public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException { + final Class beanType = bean.getClass(); - @Override public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException { - final Class beanType = bean.getClass(); + RepositoryEventHandler typeAnno = AnnotationUtils.findAnnotation(beanType, RepositoryEventHandler.class); + if(null == typeAnno) { + return bean; + } - RepositoryEventHandler typeAnno = AnnotationUtils.findAnnotation(beanType, RepositoryEventHandler.class); - if(null == typeAnno) { - return bean; - } + Class[] targetTypes = typeAnno.value(); + if(targetTypes.length == 0) { + targetTypes = new Class[]{null}; + } - Class[] targetTypes = typeAnno.value(); - if(targetTypes.length == 0) { - targetTypes = new Class[]{null}; - } + for(final Class targetType : targetTypes) { + ReflectionUtils.doWithMethods( + beanType, + new ReflectionUtils.MethodCallback() { + @Override public void doWith(Method method) + throws IllegalArgumentException, IllegalAccessException { + inspect(targetType, bean, method, HandleBeforeCreate.class, BeforeCreateEvent.class); + inspect(targetType, bean, method, HandleAfterCreate.class, AfterCreateEvent.class); + inspect(targetType, bean, method, HandleBeforeSave.class, BeforeSaveEvent.class); + inspect(targetType, bean, method, HandleAfterSave.class, AfterSaveEvent.class); + inspect(targetType, bean, method, HandleBeforeLinkSave.class, BeforeLinkSaveEvent.class); + inspect(targetType, bean, method, HandleAfterLinkSave.class, AfterLinkSaveEvent.class); + inspect(targetType, bean, method, HandleBeforeDelete.class, BeforeDeleteEvent.class); + inspect(targetType, bean, method, HandleAfterDelete.class, AfterDeleteEvent.class); + inspect(targetType, bean, method, HandleBeforeLinkDelete.class, BeforeLinkDeleteEvent.class); + inspect(targetType, bean, method, HandleAfterLinkDelete.class, AfterLinkDeleteEvent.class); + } + }, + new ReflectionUtils.MethodFilter() { + @Override public boolean matches(Method method) { + return (!method.isSynthetic() + && !method.isBridge() + && method.getDeclaringClass() != Object.class + && !method.getName().contains("$")); + } + } + ); + } - for(final Class targetType : targetTypes) { - ReflectionUtils.doWithMethods( - beanType, - new ReflectionUtils.MethodCallback() { - @Override public void doWith(Method method) - throws IllegalArgumentException, IllegalAccessException { - inspect(targetType, bean, method, HandleBeforeSave.class, BeforeSaveEvent.class); - inspect(targetType, bean, method, HandleAfterSave.class, AfterSaveEvent.class); - inspect(targetType, bean, method, HandleBeforeLinkSave.class, BeforeLinkSaveEvent.class); - inspect(targetType, bean, method, HandleAfterLinkSave.class, AfterLinkSaveEvent.class); - inspect(targetType, bean, method, HandleBeforeDelete.class, BeforeDeleteEvent.class); - inspect(targetType, bean, method, HandleAfterDelete.class, AfterDeleteEvent.class); - inspect(targetType, bean, method, HandleBeforeLinkDelete.class, BeforeLinkDeleteEvent.class); - inspect(targetType, bean, method, HandleAfterLinkDelete.class, AfterLinkDeleteEvent.class); - } - }, - new ReflectionUtils.MethodFilter() { - @Override public boolean matches(Method method) { - return (!method.isSynthetic() - && !method.isBridge() - && method.getDeclaringClass() != Object.class - && !method.getName().contains("$")); - } - } - ); - } + return bean; + } - return bean; - } + private void inspect(Class targetType, + Object handler, + Method method, + Class annoType, + Class eventType) { + T anno = method.getAnnotation(annoType); + if(null != anno) { + try { + Class[] targetTypes; + if(null == targetType) { + targetTypes = (Class[])anno.getClass().getMethod("value", new Class[0]).invoke(anno); + } else { + targetTypes = new Class[]{targetType}; + } + for(Class type : targetTypes) { + EventHandlerMethod m = new EventHandlerMethod(type, handler, method); + if(LOG.isDebugEnabled()) { + LOG.debug("Annotated handler method found: " + m); + } + handlerMethods.put(eventType, m); + } + } catch(NoSuchMethodException e) { + if(LOG.isDebugEnabled()) { + LOG.debug(e.getMessage(), e); + } + } catch(InvocationTargetException e) { + if(LOG.isDebugEnabled()) { + LOG.debug(e.getMessage(), e); + } + } catch(IllegalAccessException e) { + if(LOG.isDebugEnabled()) { + LOG.debug(e.getMessage(), e); + } + } + } + } + private class EventHandlerMethod { + final Class targetType; + final Method method; + final Object handler; - private void inspect(Class targetType, - Object handler, - Method method, - Class annoType, - Class eventType) { - T anno = method.getAnnotation(annoType); - if(null != anno) { - try { - Class[] targetTypes; - if(null == targetType) { - targetTypes = (Class[])anno.getClass().getMethod("value", new Class[0]).invoke(anno); - } else { - targetTypes = new Class[]{targetType}; - } - for(Class type : targetTypes) { - EventHandlerMethod m = new EventHandlerMethod(type, handler, method); - if(LOG.isDebugEnabled()) { - LOG.debug("Annotated handler method found: " + m); - } - handlerMethods.put(eventType, m); - } - } catch(NoSuchMethodException e) { - if(LOG.isDebugEnabled()) { - LOG.debug(e.getMessage(), e); - } - } catch(InvocationTargetException e) { - if(LOG.isDebugEnabled()) { - LOG.debug(e.getMessage(), e); - } - } catch(IllegalAccessException e) { - if(LOG.isDebugEnabled()) { - LOG.debug(e.getMessage(), e); - } - } - } - } + private EventHandlerMethod(Class targetType, Object handler, Method method) { + this.targetType = targetType; + this.method = method; + this.handler = handler; + } - private class EventHandlerMethod { - final Class targetType; - final Method method; - final Object handler; - - private EventHandlerMethod(Class targetType, Object handler, Method method) { - this.targetType = targetType; - this.method = method; - this.handler = handler; - } - - @Override public String toString() { - return "EventHandlerMethod{" + - "targetType=" + targetType + - ", method=" + method + - ", handler=" + handler + - '}'; - } - } + @Override public String toString() { + return "EventHandlerMethod{" + + "targetType=" + targetType + + ", method=" + method + + ", handler=" + handler + + '}'; + } + } } diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/BeforeCreateEvent.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/BeforeCreateEvent.java new file mode 100644 index 000000000..3b9046466 --- /dev/null +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/BeforeCreateEvent.java @@ -0,0 +1,12 @@ +package org.springframework.data.rest.repository.context; + +/** + * Event emitted before an entity is saved for the first time. + * + * @author Jon Brisbin + */ +public class BeforeCreateEvent extends RepositoryEvent { + public BeforeCreateEvent(Object source) { + super(source); + } +} diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/BeforeSaveEvent.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/BeforeSaveEvent.java index ddcfa2408..2845d1715 100644 --- a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/BeforeSaveEvent.java +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/BeforeSaveEvent.java @@ -2,11 +2,9 @@ package org.springframework.data.rest.repository.context; /** * Emitted before an entity is saved into the repository. - * - * @author Jon Brisbin */ public class BeforeSaveEvent extends RepositoryEvent { - public BeforeSaveEvent(Object source) { - super(source); - } + public BeforeSaveEvent(Object source) { + super(source); + } } diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/ValidatingRepositoryEventListener.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/ValidatingRepositoryEventListener.java index 3b4fb1af3..495ae378e 100644 --- a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/ValidatingRepositoryEventListener.java +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/ValidatingRepositoryEventListener.java @@ -38,141 +38,150 @@ import org.springframework.validation.Validator; * @author Jon Brisbin */ public class ValidatingRepositoryEventListener - extends AbstractRepositoryEventListener - implements InitializingBean { + extends AbstractRepositoryEventListener + implements InitializingBean { - private static final Logger LOG = LoggerFactory.getLogger(ValidatingRepositoryEventListener.class); + private static final Logger LOG = LoggerFactory.getLogger( + ValidatingRepositoryEventListener.class); + @SuppressWarnings({"unchecked"}) + private static final List> ANNOTATIONS_TO_FIND = Arrays.asList( + HandleBeforeSave.class, + HandleAfterSave.class, + HandleBeforeDelete.class, + HandleAfterDelete.class, + HandleBeforeLinkSave.class, + HandleAfterLinkSave.class, + HandleBeforeLinkDelete.class, + HandleAfterLinkDelete.class + ); + @Autowired + private Repositories repositories; + private Multimap validators = ArrayListMultimap.create(); - @SuppressWarnings({"unchecked"}) - private static final List> ANNOTATIONS_TO_FIND = Arrays.asList( - HandleBeforeSave.class, - HandleAfterSave.class, - HandleBeforeDelete.class, - HandleAfterDelete.class, - HandleBeforeLinkSave.class, - HandleAfterLinkSave.class, - HandleBeforeLinkDelete.class, - HandleAfterLinkDelete.class - ); + @Override public void afterPropertiesSet() throws Exception { + if(validators.size() == 0) { + for(Map.Entry entry : beansOfTypeIncludingAncestors(applicationContext, + Validator.class).entrySet()) { + String name = null; + Validator v = entry.getValue(); - @Autowired - private Repositories repositories; - private Multimap validators = ArrayListMultimap.create(); + if(entry.getKey().contains("Save")) { + name = entry.getKey().substring(0, entry.getKey().indexOf("Save") + 4); + } else if(entry.getKey().contains("Create")) { + name = entry.getKey().substring(0, entry.getKey().indexOf("Create") + 6); + } else if(entry.getKey().contains("Delete")) { + name = entry.getKey().substring(0, entry.getKey().indexOf("Delete") + 6); + } else { + Annotation anno; + for(Class annoType : ANNOTATIONS_TO_FIND) { + if(null != (anno = findAnnotation(v.getClass(), annoType))) { + name = uncapitalize(annoType.getSimpleName().substring(6)); + } + } + } - @Override public void afterPropertiesSet() throws Exception { - if(validators.size() == 0) { - for(Map.Entry entry : beansOfTypeIncludingAncestors(applicationContext, - Validator.class).entrySet()) { - String name = null; - Validator v = entry.getValue(); + if(null != name) { + this.validators.put(name, v); + } + } + } + } - if(entry.getKey().contains("Save")) { - name = entry.getKey().substring(0, entry.getKey().indexOf("Save") + 4); - } else if(entry.getKey().contains("Delete")) { - name = entry.getKey().substring(0, entry.getKey().indexOf("Delete") + 6); - } else { - Annotation anno; - for(Class annoType : ANNOTATIONS_TO_FIND) { - if(null != (anno = findAnnotation(v.getClass(), annoType))) { - name = uncapitalize(annoType.getSimpleName().substring(6)); - } - } - } + /** + * Get a Map of {@link Validator}s that are assigned to the various {@link RepositoryEvent}s. + * + * @return Validators assigned to events. + */ + public Map> getValidators() { + return validators.asMap(); + } - if(null != name) { - this.validators.put(name, v); - } - } - } - } + /** + * Assign a Map of {@link Validator}s that are assigned to the various {@link RepositoryEvent}s. + * + * @param validators + * A Map of Validators to wire. + * + * @return @this + */ + public ValidatingRepositoryEventListener setValidators(Map> validators) { + for(Map.Entry> entry : validators.entrySet()) { + this.validators.replaceValues(entry.getKey(), entry.getValue()); + } + return this; + } - /** - * Get a Map of {@link Validator}s that are assigned to the various {@link RepositoryEvent}s. - * - * @return Validators assigned to events. - */ - public Map> getValidators() { - return validators.asMap(); - } + /** + * Add a {@link Validator} that will be triggered on the given event. + * + * @param event + * The event to listen for. + * @param validator + * The Validator to execute when that event fires. + * + * @return @this + */ + public ValidatingRepositoryEventListener addValidator(String event, Validator validator) { + validators.put(event, validator); + return this; + } - /** - * Assign a Map of {@link Validator}s that are assigned to the various {@link RepositoryEvent}s. - * - * @param validators - * A Map of Validators to wire. - * - * @return @this - */ - public ValidatingRepositoryEventListener setValidators(Map> validators) { - for(Map.Entry> entry : validators.entrySet()) { - this.validators.replaceValues(entry.getKey(), entry.getValue()); - } - return this; - } + @Override protected void onBeforeCreate(Object entity) { + validate("beforeCreate", entity); + } - /** - * Add a {@link Validator} that will be triggered on the given event. - * - * @param event - * The event to listen for. - * @param validator - * The Validator to execute when that event fires. - * - * @return @this - */ - public ValidatingRepositoryEventListener addValidator(String event, Validator validator) { - validators.put(event, validator); - return this; - } + @Override protected void onAfterCreate(Object entity) { + validate("afterCreate", entity); + } - @Override protected void onBeforeSave(Object entity) { - validate("beforeSave", entity); - } + @Override protected void onBeforeSave(Object entity) { + validate("beforeSave", entity); + } - @Override protected void onAfterSave(Object entity) { - validate("afterSave", entity); - } + @Override protected void onAfterSave(Object entity) { + validate("afterSave", entity); + } - @Override protected void onBeforeLinkSave(Object parent, Object linked) { - validate("beforeLinkSave", parent); - } + @Override protected void onBeforeLinkSave(Object parent, Object linked) { + validate("beforeLinkSave", parent); + } - @Override protected void onAfterLinkSave(Object parent, Object linked) { - validate("afterLinkSave", parent); - } + @Override protected void onAfterLinkSave(Object parent, Object linked) { + validate("afterLinkSave", parent); + } - @Override protected void onBeforeDelete(Object entity) { - validate("beforeDelete", entity); - } + @Override protected void onBeforeDelete(Object entity) { + validate("beforeDelete", entity); + } - @Override protected void onAfterDelete(Object entity) { - validate("afterDelete", entity); - } + @Override protected void onAfterDelete(Object entity) { + validate("afterDelete", entity); + } - private Errors validate(String event, Object o) { - Errors errors = null; - if(null != o) { - Class domainType = o.getClass(); - errors = new ValidationErrors(domainType.getSimpleName(), - o, - repositories.getPersistentEntity(domainType)); + private Errors validate(String event, Object o) { + Errors errors = null; + if(null != o) { + Class domainType = o.getClass(); + errors = new ValidationErrors(domainType.getSimpleName(), + o, + repositories.getPersistentEntity(domainType)); - Collection validators = this.validators.get(event); - if(null != validators) { - for(Validator v : validators) { - if(v.supports(o.getClass())) { - LOG.debug(event + ": " + o + " with " + v); - ValidationUtils.invokeValidator(v, o, errors); - } - } - } + Collection validators = this.validators.get(event); + if(null != validators) { + for(Validator v : validators) { + if(v.supports(o.getClass())) { + LOG.debug(event + ": " + o + " with " + v); + ValidationUtils.invokeValidator(v, o, errors); + } + } + } - if(errors.getErrorCount() > 0) { - throw new RepositoryConstraintViolationException(errors); - } - } + if(errors.getErrorCount() > 0) { + throw new RepositoryConstraintViolationException(errors); + } + } - return errors; - } + return errors; + } } diff --git a/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/context/RepositoryEventIntegrationTests.java b/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/context/RepositoryEventIntegrationTests.java index f3506e815..bba736f13 100644 --- a/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/context/RepositoryEventIntegrationTests.java +++ b/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/context/RepositoryEventIntegrationTests.java @@ -19,55 +19,65 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @ContextConfiguration(classes = RepositoryEventTestsConfig.class) public class RepositoryEventIntegrationTests { - @Autowired - ApplicationContext appCtx; - @Autowired - PersonRepository people; - Person person; + @Autowired + ApplicationContext appCtx; + @Autowired + PersonRepository people; + Person person; - @Before - public void setup() { - person = people.save(new Person("Jane", "Doe")); - } + @Before + public void setup() { + person = people.save(new Person("Jane", "Doe")); + } - @Test(expected = RuntimeException.class) - public void shouldDispatchBeforeSave() throws Exception { - appCtx.publishEvent(new BeforeSaveEvent(person)); - } + @Test(expected = RuntimeException.class) + public void shouldDispatchBeforeCreate() throws Exception { + appCtx.publishEvent(new BeforeCreateEvent(person)); + } - @Test(expected = RuntimeException.class) - public void shouldDispatchAfterSave() throws Exception { - appCtx.publishEvent(new AfterSaveEvent(person)); - } + @Test(expected = RuntimeException.class) + public void shouldDispatchAfterCreate() throws Exception { + appCtx.publishEvent(new AfterCreateEvent(person)); + } - @Test(expected = RuntimeException.class) - public void shouldDispatchBeforeDelete() throws Exception { - appCtx.publishEvent(new BeforeDeleteEvent(person)); - } + @Test(expected = RuntimeException.class) + public void shouldDispatchBeforeSave() throws Exception { + appCtx.publishEvent(new BeforeSaveEvent(person)); + } - @Test(expected = RuntimeException.class) - public void shouldDispatchAfterDelete() throws Exception { - appCtx.publishEvent(new AfterDeleteEvent(person)); - } + @Test(expected = RuntimeException.class) + public void shouldDispatchAfterSave() throws Exception { + appCtx.publishEvent(new AfterSaveEvent(person)); + } - @Test(expected = RuntimeException.class) - public void shouldDispatchBeforeLinkSave() throws Exception { - appCtx.publishEvent(new BeforeLinkSaveEvent(person, new Object())); - } + @Test(expected = RuntimeException.class) + public void shouldDispatchBeforeDelete() throws Exception { + appCtx.publishEvent(new BeforeDeleteEvent(person)); + } - @Test(expected = RuntimeException.class) - public void shouldDispatchAfterLinkSave() throws Exception { - appCtx.publishEvent(new AfterLinkSaveEvent(person, new Object())); - } + @Test(expected = RuntimeException.class) + public void shouldDispatchAfterDelete() throws Exception { + appCtx.publishEvent(new AfterDeleteEvent(person)); + } - @Test(expected = RuntimeException.class) - public void shouldDispatchBeforeLinkDelete() throws Exception { - appCtx.publishEvent(new BeforeLinkDeleteEvent(person, new Object())); - } + @Test(expected = RuntimeException.class) + public void shouldDispatchBeforeLinkSave() throws Exception { + appCtx.publishEvent(new BeforeLinkSaveEvent(person, new Object())); + } - @Test(expected = RuntimeException.class) - public void shouldDispatchAfterLinkDelete() throws Exception { - appCtx.publishEvent(new AfterLinkDeleteEvent(person, new Object())); - } + @Test(expected = RuntimeException.class) + public void shouldDispatchAfterLinkSave() throws Exception { + appCtx.publishEvent(new AfterLinkSaveEvent(person, new Object())); + } + + @Test(expected = RuntimeException.class) + public void shouldDispatchBeforeLinkDelete() throws Exception { + appCtx.publishEvent(new BeforeLinkDeleteEvent(person, new Object())); + } + + @Test(expected = RuntimeException.class) + public void shouldDispatchAfterLinkDelete() throws Exception { + appCtx.publishEvent(new AfterLinkDeleteEvent(person, new Object())); + } } diff --git a/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/domain/jpa/AnnotatedPersonEventHandler.java b/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/domain/jpa/AnnotatedPersonEventHandler.java index 465750175..5eb0d21a6 100644 --- a/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/domain/jpa/AnnotatedPersonEventHandler.java +++ b/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/domain/jpa/AnnotatedPersonEventHandler.java @@ -1,9 +1,11 @@ package org.springframework.data.rest.repository.domain.jpa; +import org.springframework.data.rest.repository.annotation.HandleAfterCreate; import org.springframework.data.rest.repository.annotation.HandleAfterDelete; import org.springframework.data.rest.repository.annotation.HandleAfterLinkDelete; import org.springframework.data.rest.repository.annotation.HandleAfterLinkSave; import org.springframework.data.rest.repository.annotation.HandleAfterSave; +import org.springframework.data.rest.repository.annotation.HandleBeforeCreate; import org.springframework.data.rest.repository.annotation.HandleBeforeDelete; import org.springframework.data.rest.repository.annotation.HandleBeforeLinkDelete; import org.springframework.data.rest.repository.annotation.HandleBeforeLinkSave; @@ -15,27 +17,29 @@ import org.springframework.data.rest.repository.annotation.RepositoryEventHandle */ @RepositoryEventHandler(Person.class) public class AnnotatedPersonEventHandler { - @HandleAfterDelete - @HandleAfterSave - public void handleAfter(Person p) { - throw new RuntimeException(); - } + @HandleAfterCreate + @HandleAfterDelete + @HandleAfterSave + public void handleAfter(Person p) { + throw new RuntimeException(); + } - @HandleAfterLinkDelete - @HandleAfterLinkSave - public void handleAfterLink(Person p, Object o) { - throw new RuntimeException(); - } + @HandleAfterLinkDelete + @HandleAfterLinkSave + public void handleAfterLink(Person p, Object o) { + throw new RuntimeException(); + } - @HandleBeforeDelete - @HandleBeforeSave - public void handleBefore(Person p) { - throw new RuntimeException(); - } + @HandleBeforeCreate + @HandleBeforeDelete + @HandleBeforeSave + public void handleBefore(Person p) { + throw new RuntimeException(); + } - @HandleBeforeLinkDelete - @HandleBeforeLinkSave - public void handleBeforeLink(Person p, Object o) { - throw new RuntimeException(); - } + @HandleBeforeLinkDelete + @HandleBeforeLinkSave + public void handleBeforeLink(Person p, Object o) { + throw new RuntimeException(); + } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java index b59704ad2..29ce318f3 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java @@ -124,8 +124,6 @@ public class AbstractRepositoryRestController implements ApplicationContextAware * @param t * * @return - * - * @throws java.io.IOException */ @ExceptionHandler({ InvocationTargetException.class, @@ -145,7 +143,7 @@ public class AbstractRepositoryRestController implements ApplicationContextAware public ResponseEntity handleConstraintViolationException(ConstraintViolationException cve) { return response(null, new ConstraintViolationExceptionMessage(cve, applicationContext), - HttpStatus.CONFLICT); + HttpStatus.BAD_REQUEST); } @ExceptionHandler({ @@ -155,7 +153,7 @@ public class AbstractRepositoryRestController implements ApplicationContextAware public ResponseEntity handleRepositoryConstraintViolationException(RepositoryConstraintViolationException rcve) { return response(null, new RepositoryConstraintViolationExceptionMessage(rcve, applicationContext), - HttpStatus.CONFLICT); + HttpStatus.BAD_REQUEST); } /** diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java index cff5abe48..35ccdbb30 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java @@ -18,8 +18,10 @@ 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.PersistentEntityResource; +import org.springframework.data.rest.repository.context.AfterCreateEvent; import org.springframework.data.rest.repository.context.AfterDeleteEvent; import org.springframework.data.rest.repository.context.AfterSaveEvent; +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; @@ -179,9 +181,9 @@ public class RepositoryEntityController extends AbstractRepositoryRestController throw new NoSuchMethodError(); } - applicationContext.publishEvent(new BeforeSaveEvent(incoming.getContent())); + applicationContext.publishEvent(new BeforeCreateEvent(incoming.getContent())); Object obj = repoMethodInvoker.save(incoming.getContent()); - applicationContext.publishEvent(new AfterSaveEvent(obj)); + applicationContext.publishEvent(new AfterCreateEvent(obj)); Link selfLink = repoRequest.buildEntitySelfLink(obj, conversionService); HttpHeaders headers = new HttpHeaders();