CDI 2.0, Java SE - метод условного наблюдателя, не вызываемый в сварном шве 3.0.5. Окончательный

У меня проблема с методом условного наблюдателя, который не вызывается. Вот код, начинающийся с теста junit:

    import static org.hamcrest.CoreMatchers.notNullValue;
    import static org.hamcrest.CoreMatchers.nullValue;
    import static org.junit.Assert.assertThat;

    import javax.enterprise.inject.Instance;
    import javax.enterprise.inject.se.SeContainer;
    import javax.enterprise.inject.se.SeContainerInitializer;

    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;

    public class CDIMinimalConditionalObserverTest
    {
        private final static Logger LOGGER = LogManager.getLogger(CDIMinimalConditionalObserverTest.class);

        private SeContainer container;

        @Before public void before()
        {
            LOGGER.debug("before");
        final SeContainerInitializer initialiser = SeContainerInitializer.newInstance();
        container = initialiser.initialize();
    }

    @After public void after()
    {
        container.close();
        LOGGER.debug("after");
    }

    @Test public void testObservation_observationInManagedNonExistentConditionalObservers()
    {
        CDIMinimalConditionalObserverEvent event = new CDIMinimalConditionalObserverEvent();
        container.getBeanManager().fireEvent(event);
        assertThat(event.msg, nullValue());
    }

    @Test public void testObservation_observationInManagedExistentConditionalObservers()
    {
        // create observer by selection
        Instance<CDIMinimalConditionalObserver> instance = container.select(CDIMinimalConditionalObserver.class);
        CDIMinimalConditionalObserver observer = instance.get();
        assertThat(observer, notNullValue());

        CDIMinimalConditionalObserverEvent event = new CDIMinimalConditionalObserverEvent();
        container.getBeanManager().fireEvent(event);
        observer.doSomething();
        assertThat(event.msg, notNullValue());
    }
}

Вот класс с методом условного наблюдателя:

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.event.Reception;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import de.jmda.sandbox.cdi.se.CDIMinimalTests.SimpleInnerEvent;

/**
 * {@link Model} annotation assigns non-dependent scope and thereby makes it possible to make {@link
 * #observation(SimpleInnerEvent)} conditional
 */
@ApplicationScoped public class CDIMinimalConditionalObserver
{
    private final static Logger LOGGER = LogManager.getLogger(SimpleConditionalObserver.class);

    public CDIMinimalConditionalObserver()
    {
        LOGGER.debug("constructor");
    }

    @PostConstruct public void postConstruct()
    {
        LOGGER.debug("post construct");
    }

    @PreDestroy public void preDestroy()
    {
        LOGGER.debug("pre destroy");
    }

    public void observation(@Observes(notifyObserver=Reception.IF_EXISTS) CDIMinimalConditionalObserverEvent event)
    {
        event.msg = "observation";
        LOGGER.debug(event.msg);
    }

    public void doSomething()
    {
        LOGGER.debug("doing something");
    }
}

И, наконец, вот класс события:

public class CDIMinimalConditionalObserverEvent { String msg; }

Тест не пройден, потому что event.msg имеет значение null, хотя это не должно быть. Выходные данные журналов не показывают никаких результатов "наблюдения". Тест проходит, если условие снято.

Есть идеи? Спасибо!

1 ответ

Решение

Когда ваш @ApplicationScoped Бин обнаруживается, он не создается сразу.
CDI достаточно умен, чтобы инициализировать реальный объект, находящийся за сценой, только при необходимости.

Вы можете видеть, что получение ApplicationScoped Бин через

final Instance<App> select = container.select(App.class);
final App app = select.get();

Действительно ли возвращает экземпляр прокси.
На данном этапе до сих пор нет App Бин присоединен к контексту приложения.

Теперь попробуйте взаимодействовать с этим объектом (даже просто вызывая toString) и только после запуска события.
Вы заметите, что он работает, потому что базовый объект был создан с помощью конструктора без аргументов.

Удаление Reception.IF_EXISTS просто сигнал CDI что он должен немедленно создать и присоединить к контексту базовый экземпляр, чтобы он мог принимать входящие события, несмотря ни на что.

Такое поведение проксирования задокументировано в спецификации (мне нужно найти страницу), и именно поэтому Бину требуется конструктор без аргументов.

Dependent Бины области действия не страдают от этой проблемы, так как они создаются каждый раз, когда это необходимо, с нуля и не отслеживаются платформой. Для одноэлементных, сеансовых или запрашиваемых объектов EJB требуется прокси-сервер для их правильного управления.


Dependent Bean, вы можете увидеть, что это "чистый" экземпляр

Другие вопросы по тегам