2011-09-19 1 views
1

객체를 반환하는 명명 된 생산자 메소드 getNewCustomer을 가진 명명 된 세션 범위 콩인 CustomerRegistration가 있습니다. 데이터베이스에서 모든 고객을 목록으로 생성하는 CustomerListProducer 클래스도 있습니다. selectCustomer.xhtml 페이지에서 사용자는 고객 중 한 명을 선택하고 선택을 응용 프로그램에 제출할 수 있습니다. 그런 다음 선택한 고객의 성을 간단히 인쇄합니다.CDI 프로듀서 메쏘드 h : selectOneMenu를 참조하십시오.

이제 facelet 페이지에서 선택한 고객을 #{customerRegistration.newCustomer}을 통해 참조 할 때만 작동합니다. #{newCustomer}을 단순히 사용하면 양식을 제출할 때마다 성의 출력은 null입니다.

여기 무슨 일 이니? 이것은 7.1 장에 따라 예상되는 동작입니까? JSR-299 사양의 빈 인스턴스에 대한 제한 사항입니까?

은 말한다 :

... 그러나, 응용 프로그램이 직접 결과 인스턴스가 컨테이너에 의해 관리되지 않고, 컨테이너 인스턴스를 실행시키는 대신 빈 클래스, 를 인스턴스화하는 경우가 아니다 contextual 6.5.2 "빈의 문맥 인스턴스"에 정의 된 인스턴스. 또한 2.1.3 절, "빈에 컨테이너가 제공 한 기능 "에 나열된 기능을 해당 인스턴스 에서 사용할 수 없습니다. 배포 된 응용 프로그램에서 콩을 인스턴스화하고 해당 종속성을 초기화하는 것은 컨테이너 입니다.

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 : @Producer의 등록 방법의

@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(); 
    } 

} 

답변

2

생각합니다. 배포하는 동안 컨테이너가 주석을 찾기 위해 클래스를 검색하고 @SessionScoped @Named 빈 내에 선언 된 @Producer 메서드를 사용한다는 사실은 해당 빈의 인스턴스만큼 많은 제작자를 보유한다는 것을 의미하지 않으며 컨테이너를 의미하지 않습니다. 예상 한 인스턴스에서 제작자를 호출 할 것입니다.

여기에서 발생하는 것은 제작자 메소드가 항상 Customer이라는 동일한 인스턴스를 반환합니다.이 인스턴스는 배포 중에 @PostConstruct 메소드에서 생성 된 인스턴스, 즉동안 @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} '를 사용할 수 있습니다. 이것은 세션 당 항상 새로운 컨테이너 관리 인스턴스를 제공합니다.