Инъекция одного вида области видимости bean в другом представлении с охватом bean заставляет его воссоздавать

Мне нужно использовать некоторые данные, сохраненные в области с видимым охватом bean в другом представлении с охватом bean.

@ManagedBean
@ViewScoped
public class Attivita implements Serializable {
    //
}

и

@ManagedBean
@ViewScoped
public class Nota implements Serializable {

    @ManagedProperty("#{attivita}")
    private Attivita attivita;

    // Getter and setter.
}

Теперь, может быть, моя теория об этом по-прежнему довольно бедна, я заметил, что когда #{attivita} вводится, конструктор Attivita вызывается и тем самым создает другой экземпляр. Это правильное поведение? А если я хочу ссылаться на один и тот же экземпляр, а не на новый?

Ответ 1

Это произойдет, если вы перейдете от одного к другому в обратном порядке. Область просмотра bean не привязана к запросу, а к представлению. Поэтому, когда вы переходите к новому представлению, он получит совершенно новый экземпляр области с охватом bean. Он не будет повторно использовать тот же экземпляр bean, который связан с предыдущим представлением.

Я понимаю, что attivita bean создается в исходном представлении и повторно используется при обратной передаче. Я понимаю, что nota bean связано с новым представлением, в которое вы переходите. При вводе attivita в нем он просто получит новый и отдельный экземпляр, даже если в одном запросе есть еще один экземпляр. Это все ожидаемое (и, по общему признанию, немного неинтуитивное) поведение.

Для этого нет стандартного решения JSF. CDI решает это с помощью @ConversationScoped (bean живет до тех пор, пока вы явно указываете, что он живет), а расширение CDI. MyFaces CODI немного отличается от @ViewAccessScoped (bean живет до тех пор, пока ссылки навигации она).

Однако вы можете обойти это, сохранив bean как атрибут в области запроса.

@ManagedBean
@ViewScoped
public class Attivita implements Serializable {

    public String submit() {
        FacesContext.getCurrentInstance().getExternalContext()
            .getRequestMap().put("attivita", this);
        return "nota";
    }

}

и

@ManagedBean
@ViewScoped
public class Nota implements Serializable {

    private Attivita attivita;

    @PostConstruct
    public void init() {
        attivita = (Attivita) FacesContext.getCurrentInstance().getExternalContext()
            .getRequestMap().get("attivita");
    }

}

Обратите внимание, что это довольно хаки. В зависимости от конкретного функционального требования могут быть лучшие решения. Также обратите внимание, что в представлении nota следует указать желаемый экземпляр attivita bean как #{nota.attivita}, а не как #{attivita}, потому что он предоставит вам новый и другой экземпляр по причинам, которые уже были объяснены ранее.

Ответ 2

Ваш attivita bean - @ViewScoped, и это не гарантирует, что ваш экземпляр будет удерживаться в сеансе. Вам нужен @SessionScoped bean. Однако, если вам нужно attivita по какой-то причине быть @ViewScoped, тогда вы можете передавать параметры через них другими способами, например. используя viewParam или используя другие @SessionScoped bean между ними.

Параметр страницы

http://mkblog.exadel.com/2010/07/learning-jsf2-page-params-and-page-actions/

JSF 2 Управляемые bean Области

http://balusc.blogspot.com.es/2011/09/communication-in-jsf-20.html#ManagedBeanScopes