@Test
  public void listenersInApplicationContextWithNestedChild() {
    StaticApplicationContext context = new StaticApplicationContext();
    RootBeanDefinition nestedChild = new RootBeanDefinition(StaticApplicationContext.class);
    nestedChild.getPropertyValues().add("parent", context);
    nestedChild.setInitMethodName("refresh");
    context.registerBeanDefinition("nestedChild", nestedChild);
    RootBeanDefinition listener1Def = new RootBeanDefinition(MyOrderedListener1.class);
    listener1Def.setDependsOn(new String[] {"nestedChild"});
    context.registerBeanDefinition("listener1", listener1Def);
    context.refresh();

    MyOrderedListener1 listener1 = context.getBean("listener1", MyOrderedListener1.class);
    MyEvent event1 = new MyEvent(context);
    context.publishEvent(event1);
    assertTrue(listener1.seenEvents.contains(event1));

    SimpleApplicationEventMulticaster multicaster =
        context.getBean(
            AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
            SimpleApplicationEventMulticaster.class);
    assertFalse(multicaster.getApplicationListeners().isEmpty());

    context.close();
    assertTrue(multicaster.getApplicationListeners().isEmpty());
  }
  @Test
  public void orderedListenersWithAnnotation() {
    MyOrderedListener3 listener1 = new MyOrderedListener3();
    MyOrderedListener4 listener2 = new MyOrderedListener4(listener1);

    SimpleApplicationEventMulticaster smc = new SimpleApplicationEventMulticaster();
    smc.addApplicationListener(listener2);
    smc.addApplicationListener(listener1);

    smc.multicastEvent(new MyEvent(this));
    smc.multicastEvent(new MyOtherEvent(this));
  }
  @Test
  public void orderedListeners() {
    MyOrderedListener1 listener1 = new MyOrderedListener1();
    MyOrderedListener2 listener2 = new MyOrderedListener2(listener1);

    SimpleApplicationEventMulticaster smc = new SimpleApplicationEventMulticaster();
    smc.addApplicationListener(listener2);
    smc.addApplicationListener(listener1);

    smc.multicastEvent(new MyEvent(this));
    smc.multicastEvent(new MyOtherEvent(this));
  }
  @Test
  public void simpleApplicationEventMulticasterWithErrorHandler() {
    @SuppressWarnings("unchecked")
    ApplicationListener<ApplicationEvent> listener = mock(ApplicationListener.class);
    ApplicationEvent evt = new ContextClosedEvent(new StaticApplicationContext());

    SimpleApplicationEventMulticaster smc = new SimpleApplicationEventMulticaster();
    smc.setErrorHandler(TaskUtils.LOG_AND_SUPPRESS_ERROR_HANDLER);
    smc.addApplicationListener(listener);

    willThrow(new RuntimeException()).given(listener).onApplicationEvent(evt);
    smc.multicastEvent(evt);
  }
  private void multicastEvent(
      boolean match, Class<?> listenerType, ApplicationEvent event, ResolvableType eventType) {
    @SuppressWarnings("unchecked")
    ApplicationListener<ApplicationEvent> listener =
        (ApplicationListener<ApplicationEvent>) mock(listenerType);
    SimpleApplicationEventMulticaster smc = new SimpleApplicationEventMulticaster();
    smc.addApplicationListener(listener);

    if (eventType != null) {
      smc.multicastEvent(event, eventType);
    } else {
      smc.multicastEvent(event);
    }
    int invocation = match ? 1 : 0;
    verify(listener, times(invocation)).onApplicationEvent(event);
  }
  @Test
  @SuppressWarnings("unchecked")
  public void proxiedListeners() {
    MyOrderedListener1 listener1 = new MyOrderedListener1();
    MyOrderedListener2 listener2 = new MyOrderedListener2(listener1);
    ApplicationListener<ApplicationEvent> proxy1 =
        (ApplicationListener<ApplicationEvent>) new ProxyFactory(listener1).getProxy();
    ApplicationListener<ApplicationEvent> proxy2 =
        (ApplicationListener<ApplicationEvent>) new ProxyFactory(listener2).getProxy();

    SimpleApplicationEventMulticaster smc = new SimpleApplicationEventMulticaster();
    smc.addApplicationListener(proxy1);
    smc.addApplicationListener(proxy2);

    smc.multicastEvent(new MyEvent(this));
    smc.multicastEvent(new MyOtherEvent(this));
  }
  @Test
  public void simpleApplicationEventMulticasterWithException() {
    @SuppressWarnings("unchecked")
    ApplicationListener<ApplicationEvent> listener = mock(ApplicationListener.class);
    ApplicationEvent evt = new ContextClosedEvent(new StaticApplicationContext());

    SimpleApplicationEventMulticaster smc = new SimpleApplicationEventMulticaster();
    smc.addApplicationListener(listener);

    RuntimeException thrown = new RuntimeException();
    willThrow(thrown).given(listener).onApplicationEvent(evt);
    try {
      smc.multicastEvent(evt);
      fail("Should have thrown RuntimeException");
    } catch (RuntimeException ex) {
      assertSame(thrown, ex);
    }
  }
  @Test
  public void simpleApplicationEventMulticasterWithTaskExecutor() {
    @SuppressWarnings("unchecked")
    ApplicationListener<ApplicationEvent> listener = mock(ApplicationListener.class);
    ApplicationEvent evt = new ContextClosedEvent(new StaticApplicationContext());

    SimpleApplicationEventMulticaster smc = new SimpleApplicationEventMulticaster();
    smc.setTaskExecutor(
        new Executor() {
          @Override
          public void execute(Runnable command) {
            command.run();
            command.run();
          }
        });
    smc.addApplicationListener(listener);

    smc.multicastEvent(evt);
    verify(listener, times(2)).onApplicationEvent(evt);
  }