JSF 2.0: What happens to object references of a managed bean across multiple ajax requests?

StackOverflow https://stackoverflow.com/questions/3842361

  •  27-09-2019
  •  | 
  •  

문제

Assume I have a session scoped bean with object references in it, where the bean extends from an abstract generic base class. Example:

public abstract class AbstractCrudController<K, E> implements Serializable {
  private Class<E> entityClass;
  private E user;

  public E getUser() {
      if (user == null) {
          try {
              user = entityClass.newInstance();
          } catch (Exception ex) {
              JsfUtil.addErrorMessage(ex, JsfUtil.getStringResource("fatalError"));
              return null;
          }
      }
      return user;
  }

  public AbstractCrudController(Class<E> entityClass) {
    this.entityClass = entityClass;
  }
}

@ManagedBean
@SessionScoped
public class UserController extends AbstractCrudController<String, User> implements Serializable {
  public UserController() {
      super(User.class);
  }
}

And I'm accessing the properties of user in JSF via EL, like so:

<h:inputText id="firstName" title="#{str.firstName}"
              value="#{userController.user.firstName}" >
    <f:ajax render="outputText"/>
</h:inputText>

<h:outputText id="outputText" value="Hello World" rendered="#{not empty userController.user.firstName}" />

What I observed is in the debugger is that the user object does not remain alive across the ajax request. I.e. when the outputText is rendered, the user is null. I found out that this is because the user is a generic type. When I make the user instance variable of type User in the base class, everything works. But I have no explanation for this.

Any idea? Thank, Theo

도움이 되었습니까?

해결책 2

The problem was in my code. On my JSF page, I additionally registered the following event listener for preRenderView:

<f:metadata>
    <f:event type="preRenderView" listener="#{userController.prepareCreate}" />
</f:metadata>

The method that listens to this event resets the user object, which is why the user object was null afterwards. I did not know that this event is called between ajax requests. Is there any way to prevent this?

다른 팁

This is not normal behaviour. I am not sure about that @Named thing and which of the various @SessionScoped annotations you used, but normally, in "plain" JSF 2.0 you'd like to annotate it with javax.faces.bean.ManagedBean in combination with javax.faces.bean.SessionScoped to get it to work as you'd intuitively expect.

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class UserController {}

Update as per your updated question. Your backing bean code is all fine. The problem is however in the view side. The rendered attribute will evaluate false in the initial request and hence the HTML output won't end up in the HTML DOM tree in the client side. When Ajax is attempting to replace/refresh the HTML element in question in the HTML DOM tree, it simply cannot locate it and hence you won't see anything to happen.

During the occurrences when it seemed to work, you probably hit Enter which would cause a synchronous request instead of an asynchronous request and thus force JSF to send a brand new full response back, with the element present.

You'd like to avoid using rendered attribute directly in JSF components whose direct HTML output is to be located in the HTML DOM tree during partial updates. If you change the h:outputText as follows, it will work as intented:

<h:panelGroup id="outputText">
    <h:outputText value="Hello World" rendered="#{not empty userController.user.firstName}" />
</h:panelGroup>

Note that User was never been null as you initially mentioned in your question. I am not sure how you came to this conclusion, but this is certainly not the normal behaviour and that was where my initial answer was all about.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top