Polishing

This commit is contained in:
Juergen Hoeller 2015-10-07 13:25:41 +02:00
parent dbec2121a0
commit af213a09ee
4 changed files with 82 additions and 80 deletions

View File

@ -81,6 +81,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
private EventListener eventListener; private EventListener eventListener;
public ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method) { public ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method) {
this.beanName = beanName; this.beanName = beanName;
this.method = method; this.method = method;
@ -90,6 +91,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
this.methodKey = new AnnotatedElementKey(this.method, this.targetClass); this.methodKey = new AnnotatedElementKey(this.method, this.targetClass);
} }
/** /**
* Initialize this instance. * Initialize this instance.
*/ */
@ -98,11 +100,40 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
this.evaluator = evaluator; this.evaluator = evaluator;
} }
@Override @Override
public void onApplicationEvent(ApplicationEvent event) { public void onApplicationEvent(ApplicationEvent event) {
processEvent(event); processEvent(event);
} }
@Override
public boolean supportsEventType(ResolvableType eventType) {
for (ResolvableType declaredEventType : this.declaredEventTypes) {
if (declaredEventType.isAssignableFrom(eventType)) {
return true;
}
else if (PayloadApplicationEvent.class.isAssignableFrom(eventType.getRawClass())) {
ResolvableType payloadType = eventType.as(PayloadApplicationEvent.class).getGeneric();
if (declaredEventType.isAssignableFrom(payloadType)) {
return true;
}
}
}
return eventType.hasUnresolvableGenerics();
}
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return true;
}
@Override
public int getOrder() {
Order order = getMethodAnnotation(Order.class);
return (order != null ? order.value() : 0);
}
/** /**
* Process the specified {@link ApplicationEvent}, checking if the condition * Process the specified {@link ApplicationEvent}, checking if the condition
* match and handling non-null result, if any. * match and handling non-null result, if any.
@ -144,7 +175,6 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
} }
protected void handleResult(Object result) { protected void handleResult(Object result) {
Assert.notNull(this.applicationContext, "ApplicationContext must no be null.");
if (result.getClass().isArray()) { if (result.getClass().isArray()) {
Object[] events = ObjectUtils.toObjectArray(result); Object[] events = ObjectUtils.toObjectArray(result);
for (Object event : events) { for (Object event : events) {
@ -164,6 +194,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
private void publishEvent(Object event) { private void publishEvent(Object event) {
if (event != null) { if (event != null) {
Assert.notNull(this.applicationContext, "ApplicationContext must no be null");
this.applicationContext.publishEvent(event); this.applicationContext.publishEvent(event);
} }
} }
@ -174,41 +205,14 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
} }
String condition = getCondition(); String condition = getCondition();
if (StringUtils.hasText(condition)) { if (StringUtils.hasText(condition)) {
Assert.notNull(this.evaluator, "Evaluator must no be null."); Assert.notNull(this.evaluator, "EventExpressionEvaluator must no be null");
EvaluationContext evaluationContext = this.evaluator.createEvaluationContext(event, EvaluationContext evaluationContext = this.evaluator.createEvaluationContext(
this.targetClass, this.method, args); event, this.targetClass, this.method, args);
return this.evaluator.condition(condition, this.methodKey, evaluationContext); return this.evaluator.condition(condition, this.methodKey, evaluationContext);
} }
return true; return true;
} }
@Override
public boolean supportsEventType(ResolvableType eventType) {
for (ResolvableType declaredEventType : this.declaredEventTypes) {
if (declaredEventType.isAssignableFrom(eventType)) {
return true;
}
else if (PayloadApplicationEvent.class.isAssignableFrom(eventType.getRawClass())) {
ResolvableType payloadType = eventType.as(PayloadApplicationEvent.class).getGeneric();
if (declaredEventType.isAssignableFrom(payloadType)) {
return true;
}
}
}
return eventType.hasUnresolvableGenerics();
}
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return true;
}
@Override
public int getOrder() {
Order order = getMethodAnnotation(Order.class);
return (order != null ? order.value() : 0);
}
protected <A extends Annotation> A getMethodAnnotation(Class<A> annotationType) { protected <A extends Annotation> A getMethodAnnotation(Class<A> annotationType) {
return AnnotationUtils.findAnnotation(this.method, annotationType); return AnnotationUtils.findAnnotation(this.method, annotationType);
} }
@ -246,7 +250,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
* Return the target bean instance to use. * Return the target bean instance to use.
*/ */
protected Object getTargetBean() { protected Object getTargetBean() {
Assert.notNull(this.applicationContext, "ApplicationContext must no be null."); Assert.notNull(this.applicationContext, "ApplicationContext must no be null");
return this.applicationContext.getBean(this.beanName); return this.applicationContext.getBean(this.beanName);
} }
@ -346,8 +350,8 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
private List<ResolvableType> resolveDeclaredEventTypes() { private List<ResolvableType> resolveDeclaredEventTypes() {
int count = this.method.getParameterTypes().length; int count = this.method.getParameterTypes().length;
if (count > 1) { if (count > 1) {
throw new IllegalStateException("Maximum one parameter is allowed " + throw new IllegalStateException(
"for event listener method: " + method); "Maximum one parameter is allowed for event listener method: " + this.method);
} }
EventListener ann = getEventListener(); EventListener ann = getEventListener();
if (ann != null && ann.classes().length > 0) { if (ann != null && ann.classes().length > 0) {
@ -359,13 +363,14 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
} }
else { else {
if (count == 0) { if (count == 0) {
throw new IllegalStateException("Event parameter is mandatory " + throw new IllegalStateException(
"for event listener method: " + method); "Event parameter is mandatory for event listener method: " + this.method);
} }
return Collections.singletonList(ResolvableType.forMethodParameter(this.method, 0)); return Collections.singletonList(ResolvableType.forMethodParameter(this.method, 0));
} }
} }
@Override @Override
public String toString() { public String toString() {
return this.method.toGenericString(); return this.method.toGenericString();

View File

@ -29,8 +29,8 @@ import org.springframework.core.annotation.AliasFor;
* Annotation that marks a method as a listener for application events. * Annotation that marks a method as a listener for application events.
* *
* <p>If an annotated method supports a single event type, the method may * <p>If an annotated method supports a single event type, the method may
* declare a single parameter that reflects the event type to listen to. If * declare a single parameter that reflects the event type to listen to.
* an annotated method supports multiple event types, this annotation may * If an annotated method supports multiple event types, this annotation may
* refer to one or more supported event types using the {@code classes} * refer to one or more supported event types using the {@code classes}
* attribute. See {@link #classes} for further details. * attribute. See {@link #classes} for further details.
* *
@ -42,20 +42,19 @@ import org.springframework.core.annotation.AliasFor;
* when using Java config or manually via the {@code <context:annotation-driven/>} * when using Java config or manually via the {@code <context:annotation-driven/>}
* element when using XML config. * element when using XML config.
* *
* <p>Annotated methods may have a non-{@code void} return type. When they * <p>Annotated methods may have a non-{@code void} return type. When they do,
* do, the result of the method invocation is sent as a new event. If the * the result of the method invocation is sent as a new event. If the return type
* return type is either an array or a collection, each element is sent as * is either an array or a collection, each element is sent as a new event.
* a new event.
* *
* <p>It is also possible to define the order in which listeners for a * <p>It is also possible to define the order in which listeners for a certain
* certain event are invoked. To do so, add a regular * event are invoked. To do so, add Spring's common
* {@link org.springframework.core.annotation.Order @Order} annotation * {@link org.springframework.core.annotation.Order @Order} annotation
* alongside this annotation. * alongside this annotation.
* *
* <p>While it is possible for an event listener to declare that it throws * <p>While it is possible for an event listener to declare that it throws arbitrary
* arbitrary exception types, any checked exceptions thrown from an event * exception types, any checked exceptions thrown from an event listener will be
* listener will be wrapped in a {@link java.lang.reflect.UndeclaredThrowableException} * wrapped in an {@link java.lang.reflect.UndeclaredThrowableException} since
* since the caller can only handle runtime exceptions. * the caller can only handle runtime exceptions.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 4.2 * @since 4.2
@ -89,4 +88,4 @@ public @interface EventListener {
*/ */
String condition() default ""; String condition() default "";
} }

View File

@ -26,21 +26,20 @@ import java.lang.annotation.Target;
import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.MessageMapping;
/** /**
* Annotation that marks a method to be the target of a JMS message * Annotation that marks a method to be the target of a JMS message listener on the
* listener on the specified {@link #destination}. The {@link #containerFactory} * specified {@link #destination}. The {@link #containerFactory} identifies the
* identifies the {@link org.springframework.jms.config.JmsListenerContainerFactory * {@link org.springframework.jms.config.JmsListenerContainerFactory} to use to build
* JmsListenerContainerFactory} to use to build the JMS listener container. If not * the JMS listener container. If not set, a <em>default</em> container factory is
* set, a <em>default</em> container factory is assumed to be available with a bean * assumed to be available with a bean name of {@code jmsListenerContainerFactory}
* name of {@code jmsListenerContainerFactory} unless an explicit default has been * unless an explicit default has been provided through configuration.
* provided through configuration.
* *
* <p>Processing of {@code @JmsListener} annotations is performed by * <p>Processing of {@code @JmsListener} annotations is performed by registering a
* registering a {@link JmsListenerAnnotationBeanPostProcessor}. This can be * {@link JmsListenerAnnotationBeanPostProcessor}. This can be done manually or,
* done manually or, more conveniently, through the {@code <jms:annotation-driven/>} * more conveniently, through the {@code <jms:annotation-driven/>} element or
* element or {@link EnableJms @EnableJms} annotation. * {@link EnableJms @EnableJms} annotation.
* *
* <p>Annotated methods are allowed to have flexible signatures similar to what * <p>Annotated JMS listener methods are allowed to have flexible signatures similar
* {@link MessageMapping} provides: * to what {@link MessageMapping} provides:
* <ul> * <ul>
* <li>{@link javax.jms.Session} to get access to the JMS session</li> * <li>{@link javax.jms.Session} to get access to the JMS session</li>
* <li>{@link javax.jms.Message} or one of its subclasses to get access to the raw JMS message</li> * <li>{@link javax.jms.Message} or one of its subclasses to get access to the raw JMS message</li>
@ -49,15 +48,15 @@ import org.springframework.messaging.handler.annotation.MessageMapping;
* arguments, including support for validation</li> * arguments, including support for validation</li>
* <li>{@link org.springframework.messaging.handler.annotation.Header @Header}-annotated method * <li>{@link org.springframework.messaging.handler.annotation.Header @Header}-annotated method
* arguments to extract specific header values, including standard JMS headers defined by * arguments to extract specific header values, including standard JMS headers defined by
* {@link org.springframework.jms.support.JmsHeaders JmsHeaders}</li> * {@link org.springframework.jms.support.JmsHeaders}</li>
* <li>{@link org.springframework.messaging.handler.annotation.Headers @Headers}-annotated * <li>{@link org.springframework.messaging.handler.annotation.Headers @Headers}-annotated
* method argument that must also be assignable to {@link java.util.Map} for obtaining access to all * method argument that must also be assignable to {@link java.util.Map} for obtaining
* headers</li> * access to all headers</li>
* <li>{@link org.springframework.messaging.MessageHeaders MessageHeaders} arguments for * <li>{@link org.springframework.messaging.MessageHeaders} arguments for obtaining
* obtaining access to all headers</li> * access to all headers</li>
* <li>{@link org.springframework.messaging.support.MessageHeaderAccessor MessageHeaderAccessor} * <li>{@link org.springframework.messaging.support.MessageHeaderAccessor} or
* or {@link org.springframework.jms.support.JmsMessageHeaderAccessor JmsMessageHeaderAccessor} * {@link org.springframework.jms.support.JmsMessageHeaderAccessor} for convenient
* for convenient access to all method arguments</li> * access to all method arguments</li>
* </ul> * </ul>
* *
* <p>Annotated methods may have a non-{@code void} return type. When they do, * <p>Annotated methods may have a non-{@code void} return type. When they do,
@ -75,9 +74,9 @@ import org.springframework.messaging.handler.annotation.MessageMapping;
*/ */
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@MessageMapping
@Documented @Documented
@Repeatable(JmsListeners.class) @Repeatable(JmsListeners.class)
@MessageMapping
public @interface JmsListener { public @interface JmsListener {
/** /**
@ -88,7 +87,7 @@ public @interface JmsListener {
String id() default ""; String id() default "";
/** /**
* The bean name of the {@link org.springframework.jms.config.JmsListenerContainerFactory JmsListenerContainerFactory} * The bean name of the {@link org.springframework.jms.config.JmsListenerContainerFactory}
* to use to create the message listener container responsible for serving this endpoint. * to use to create the message listener container responsible for serving this endpoint.
* <p>If not specified, the default container factory is used, if any. * <p>If not specified, the default container factory is used, if any.
*/ */
@ -96,8 +95,7 @@ public @interface JmsListener {
/** /**
* The destination name for this listener, resolved through the container-wide * The destination name for this listener, resolved through the container-wide
* {@link org.springframework.jms.support.destination.DestinationResolver DestinationResolver} * {@link org.springframework.jms.support.destination.DestinationResolver} strategy.
* strategy.
*/ */
String destination(); String destination();

View File

@ -54,8 +54,8 @@ import org.springframework.util.StringUtils;
/** /**
* Bean post-processor that registers methods annotated with {@link JmsListener} * Bean post-processor that registers methods annotated with {@link JmsListener}
* to be invoked by a JMS message listener container created under the cover * to be invoked by a JMS message listener container created under the cover
* by a {@link org.springframework.jms.config.JmsListenerContainerFactory} according * by a {@link org.springframework.jms.config.JmsListenerContainerFactory}
* to the parameters of the annotation. * according to the attributes of the annotation.
* *
* <p>Annotated methods can use flexible arguments as defined by {@link JmsListener}. * <p>Annotated methods can use flexible arguments as defined by {@link JmsListener}.
* *
@ -63,10 +63,10 @@ import org.springframework.util.StringUtils;
* {@code <jms:annotation-driven>} XML element, and also by the {@link EnableJms} * {@code <jms:annotation-driven>} XML element, and also by the {@link EnableJms}
* annotation. * annotation.
* *
* <p>Auto-detect any {@link JmsListenerConfigurer} instances in the container, * <p>Autodetects any {@link JmsListenerConfigurer} instances in the container,
* allowing for customization of the registry to be used, the default container * allowing for customization of the registry to be used, the default container
* factory or for fine-grained control over endpoints registration. See * factory or for fine-grained control over endpoints registration. See the
* {@link EnableJms} Javadoc for complete usage details. * {@link EnableJms} javadocs for complete usage details.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Juergen Hoeller * @author Juergen Hoeller
@ -282,7 +282,7 @@ public class JmsListenerAnnotationBeanPostProcessor
return resolve(jmsListener.id()); return resolve(jmsListener.id());
} }
else { else {
return "org.springframework.jms.JmsListenerEndpointContainer#" + counter.getAndIncrement(); return "org.springframework.jms.JmsListenerEndpointContainer#" + this.counter.getAndIncrement();
} }
} }