Ссылка на метод производителя CDI приводит к h: selectOneMenu - PullRequest
1 голос
/ 19 сентября 2011

У меня есть именованный сессионный компонент CustomerRegistration, у которого есть именованный метод производителя getNewCustomer, который возвращает объект Customer.Существует также класс CustomerListProducer, который выдает всех клиентов в виде списка из базы данных.На странице selectCustomer.xhtml пользователь затем может выбрать одного из клиентов и отправить выбор в приложение, которое затем просто распечатывает фамилию выбранного клиента.

Теперь это работает только тогда, когда я ссылаюсьвыбранный клиент на странице лицевых линий через #{customerRegistration.newCustomer}.Когда я просто использую #{newCustomer}, то для фамилии выводится null всякий раз, когда я отправляю форму.

Что здесь происходит?Является ли это ожидаемым поведением в соответствии с главой 7.1 Ограничение на создание бина спецификации JSR-299?

В нем говорится:

... Однако, еслиприложение непосредственно создает экземпляр класса компонента, вместо того, чтобы позволить контейнеру выполнять создание экземпляра, результирующий экземпляр не управляется контейнером и не является контекстным экземпляром, как определено в разделе 6.5.2, «Контекстуальный экземпляр компонента».Кроме того, возможности, перечисленные в Разделе 2.1, «Функциональность, предоставляемая контейнером бобу», не будут доступны для этого конкретного экземпляра.В развернутом приложении именно контейнер отвечает за создание экземпляров bean-компонентов и инициализацию их зависимостей....

Вот код:

Customer.java:

@javax.persistence.Entity
@Veto
public class Customer implements Serializable, Entity {
    private static final long serialVersionUID = 122193054725297662L;
    @Column(name = "first_name")
    private String firstName;
    @Column(name = "last_name")
    private String lastName;
    @Id
    @GeneratedValue()
    private Long id;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return firstName + ", " + lastName;
    }

    @Override
    public Long getId() {
        return this.id;
    }
}

CustomerListProducer.java:

@SessionScoped
public class CustomerListProducer implements Serializable {

    @Inject
    private EntityManager em;

    private List<Customer> customers;

    @Inject
    @Category("helloworld_as7")
    Logger log;

    // @Named provides access the return value via the EL variable name
    // "members" in the UI (e.g.,
    // Facelets or JSP view)
    @Produces
    @Named
    public List<Customer> getCustomers() {
        return customers;
    }

    public void onCustomerListChanged(
            @Observes(notifyObserver = Reception.IF_EXISTS) final Customer customer) {
//      retrieveAllCustomersOrderedByName();
        log.info(customer.toString());
    }

    @PostConstruct
    public void retrieveAllCustomersOrderedByName() {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Customer> criteria = cb.createQuery(Customer.class);
        Root<Customer> customer = criteria.from(Customer.class);
        // Swap criteria statements if you would like to try out type-safe
        // criteria queries, a new
        // feature in JPA 2.0
        // criteria.select(member).orderBy(cb.asc(member.get(Member_.name)));
        criteria.select(customer).orderBy(cb.asc(customer.get("lastName")));
        customers = em.createQuery(criteria).getResultList();
    }
}

CustomerRegistration.Java:

@Named
@SessionScoped
public class CustomerRegistration implements Serializable {

    @Inject
    @Category("helloworld_as7")
    private Logger log;

    private Customer newCustomer;

    @Produces
    @Named
    public Customer getNewCustomer() {
        return newCustomer;
    }

    public void selected() {
        log.info("Customer " + newCustomer.getLastName() + " ausgewählt.");
    }

    @PostConstruct
    public void initNewCustomer() {
        newCustomer = new Customer();
    }

    public void setNewCustomer(Customer newCustomer) {
        this.newCustomer = newCustomer;
    }

}

не работает selectCustomer.xhtml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
    <title>Auswahl</title>
</h:head>
<h:body>
    <h:form>
        <h:selectOneMenu value="#{newCustomer}" converter="customerConverter">
            <f:selectItems value="#{customers}" var="current"
                itemLabel="#{current.firstName}, #{current.lastName}" />
        </h:selectOneMenu>
        <h:panelGroup id="auswahl">
            <h:outputText value="#{newCustomer.lastName}" />
        </h:panelGroup>
        <h:commandButton value="Klick"
            action="#{customerRegistration.selected}" />
    </h:form>
</h:body>
</html>

работает selectCustomer.xhtml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
    <title>Auswahl</title>
</h:head>
<h:body>
    <h:form>
        <h:selectOneMenu value="#{customerRegistration.newCustomer}" converter="customerConverter">
            <f:selectItems value="#{customers}" var="current"
                itemLabel="#{current.firstName}, #{current.lastName}" />
        </h:selectOneMenu>
        <h:panelGroup id="auswahl">
            <h:outputText value="#{newCustomer.lastName}" />
        </h:panelGroup>
        <h:commandButton value="Klick"
            action="#{customerRegistration.selected}" />
    </h:form>
</h:body>
</html>

CustomerConverter.java:

@SessionScoped
@FacesConverter("customerConverter")
public class CustomerConverter implements Converter, Serializable {
    private static final long serialVersionUID = -6093400626095413322L;

    @Inject
    EntityManager entityManager;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component,
            String value) {
        Long id = Long.valueOf(value);
        return entityManager.find(Customer.class, id);
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component,
            Object value) {
        return ((Customer) value).getId().toString();
    }

}

1 Ответ

3 голосов
/ 03 ноября 2012

Подумайте, как зарегистрированы @Producer s.Во время развертывания контейнер сканирует ваши классы на наличие аннотаций и тот факт, что ваш метод @Producer объявлен внутри компонента @SessionScoped @Named, не означает, что у вас будет столько производителей, сколько экземпляров этого компонента, и при этомозначает, что контейнер будет вызывать производителя из того экземпляра, который вы ожидаете, он будет вызван.

Что здесь происходит, - ваш метод производителя всегда возвращает один и тот же экземпляр Customer, тот, который был создан в вашем *Метод 1007 * во время развертывания, т. Е. При @Producer регистрации.

Это ожидаемое поведение.

Кажется, что вам нужно что-то, что даст вам новую сущность Customer за сеанс.В этом случае правильный способ сделать это будет:

public class CustomerProducer {

    @Produces @Named @SessionScoped
    public Customer getNewCustomer(@New Customer customer) {
        // do some custom init if need be
        return customer;
    }

}

Затем удалите @Producer связанных аннотаций из вашего сессионного компонента.Теперь вы можете использовать `# {newCustomer}, который всегда будет давать вам новый управляемый экземпляр контейнера для каждой сессии.

...