/*
* Copyright 2002-2015 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.context.event;
import org.junit.Test;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.ResolvableType;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
* @author Stephane Nicoll
*/
public class GenericApplicationListenerAdapterTests extends AbstractApplicationEventListenerTests {
@Test
public void supportsEventTypeWithSmartApplicationListener() {
SmartApplicationListener smartListener = mock(SmartApplicationListener.class);
GenericApplicationListenerAdapter listener = new GenericApplicationListenerAdapter(smartListener);
ResolvableType type = ResolvableType.forClass(ApplicationEvent.class);
listener.supportsEventType(type);
verify(smartListener, times(1)).supportsEventType(ApplicationEvent.class);
}
@Test
public void supportsSourceTypeWithSmartApplicationListener() {
SmartApplicationListener smartListener = mock(SmartApplicationListener.class);
GenericApplicationListenerAdapter listener = new GenericApplicationListenerAdapter(smartListener);
listener.supportsSourceType(Object.class);
verify(smartListener, times(1)).supportsSourceType(Object.class);
}
@Test
public void genericListenerStrictType() {
supportsEventType(true, StringEventListener.class, getGenericApplicationEventType("stringEvent"));
}
@Test // Demonstrates we can't inject that event because the generic type is lost
public void genericListenerStrictTypeTypeErasure() {
GenericTestEvent<String> stringEvent = createGenericTestEvent("test");
ResolvableType eventType = ResolvableType.forType(stringEvent.getClass());
supportsEventType(false, StringEventListener.class, eventType);
}
@Test // But it works if we specify the type properly
public void genericListenerStrictTypeAndResolvableType() {
ResolvableType eventType = ResolvableType
.forClassWithGenerics(GenericTestEvent.class, String.class);
supportsEventType(true, StringEventListener.class, eventType);
}
@Test // or if the event provides its precise type
public void genericListenerStrictTypeAndResolvableTypeProvider() {
ResolvableType eventType = new SmartGenericTestEvent<>(this, "foo").getResolvableType();
supportsEventType(true, StringEventListener.class, eventType);
}
@Test // Demonstrates it works if we actually use the subtype
public void genericListenerStrictTypeEventSubType() {
StringEvent stringEvent = new StringEvent(this, "test");
ResolvableType eventType = ResolvableType.forType(stringEvent.getClass());
supportsEventType(true, StringEventListener.class, eventType);
}
@Test
public void genericListenerStrictTypeNotMatching() {
supportsEventType(false, StringEventListener.class, getGenericApplicationEventType("longEvent"));
}
@Test
public void genericListenerStrictTypeEventSubTypeNotMatching() {
LongEvent stringEvent = new LongEvent(this, 123L);
ResolvableType eventType = ResolvableType.forType(stringEvent.getClass());
supportsEventType(false, StringEventListener.class, eventType);
}
@Test
public void genericListenerStrictTypeNotMatchTypeErasure() {
GenericTestEvent<Long> longEvent = createGenericTestEvent(123L);
ResolvableType eventType = ResolvableType.forType(longEvent.getClass());
supportsEventType(false, StringEventListener.class, eventType);
}
@Test
public void genericListenerStrictTypeSubClass() {
supportsEventType(false, ObjectEventListener.class,
getGenericApplicationEventType("longEvent"));
}
@Test
public void genericListenerUpperBoundType() {
supportsEventType(true, UpperBoundEventListener.class,
getGenericApplicationEventType("illegalStateExceptionEvent"));
}
@Test
public void genericListenerUpperBoundTypeNotMatching() throws NoSuchFieldException {
supportsEventType(false, UpperBoundEventListener.class,
getGenericApplicationEventType("ioExceptionEvent"));
}
@Test
public void genericListenerWildcardType() {
supportsEventType(true, GenericEventListener.class,
getGenericApplicationEventType("stringEvent"));
}
@Test // Demonstrates we cant inject that event because the listener has a wildcard
public void genericListenerWildcardTypeTypeErasure() {
GenericTestEvent<String> stringEvent = createGenericTestEvent("test");
ResolvableType eventType = ResolvableType.forType(stringEvent.getClass());
supportsEventType(true, GenericEventListener.class, eventType);
}
@Test
public void genericListenerRawType() {
supportsEventType(true, RawApplicationListener.class,
getGenericApplicationEventType("stringEvent"));
}
@Test // Demonstrates we cant inject that event because the listener has a raw type
public void genericListenerRawTypeTypeErasure() {
GenericTestEvent<String> stringEvent = createGenericTestEvent("test");
ResolvableType eventType = ResolvableType.forType(stringEvent.getClass());
supportsEventType(true, RawApplicationListener.class, eventType);
}
private void supportsEventType(boolean match, Class<? extends ApplicationListener> listenerType,
ResolvableType eventType) {
ApplicationListener<?> listener = mock(listenerType);
GenericApplicationListenerAdapter adapter = new GenericApplicationListenerAdapter(listener);
assertEquals("Wrong match for event '" + eventType + "' on " + listenerType.getClass().getName(),
match, adapter.supportsEventType(eventType));
}
}