4

Edit: The comment section solved my problem! The problem was that I was using incorrect imports for the Scopes.

I have a simple JSF application (login, pull data from database, allow user to edit data). It works well, I want to update the code to use CDI (Weld), but I am having trouble. I am following / looking at: http://docs.jboss.org/weld/reference/latest/en-US/html/example.html Original stuff without Weld:

login.xhtml

<h:form id="inputForm">
    <h:panelGrid columns="2" cellpadding="5" cellspacing="1">
        <h:outputText id="nameDesc" value="Name"></h:outputText>
        <h:inputText id="nameInput" value="#{login.loginName}" binding="#{name}"></h:inputText>

        <h:outputText id="passwordDesc" value="Password"></h:outputText>
        <h:inputSecret id="passwordInput" value="#{login.password}" binding="#{password}"></h:inputSecret>

    </h:panelGrid>
    <h:commandButton value="Login" action="#{login.login(name.value, password.value)}"/>
</h:form>

LoginBean.java:

@ManagedBean(name="login")
@SessionScoped
public class LoginBean implements Serializable {
    private static final long serialVersionUID = 1L;
    @ManagedProperty(value="#{db}")
    private DatabaseBean db;
    private String password;
    private String loginName;
    // other stuff and functions

    public String getLoginName () {
       return loginName;
     }

    public void setLoginName (String name) {
       this.loginName = name;
    }

    public String getPassword () {
       return password;
    }

    public void setPassword (final String password) {
       this.password = password;
    }

    public void setDb(DatabaseBean db) {
        this.db = db;
    }

DatabaseBean.java:

@ManagedBean(name="db", eager=true)
@ApplicationScoped
public class DatabaseBean implements Serializable {
 @PostConstruct
    public void init() {
      //... connect to database etc
    }    

}

---------What I tried to get it running with Weld (only changes from above to make it a bit shorter): -------- LoginBean.java, changed to @Named from @ManagedBean, added @Inject for DatabaseBean

@Named("login")
@SessionScoped
public class LoginBean implements Serializable {
     // stuff 
         private @Inject DatabaseBean db;
}

DatabaseBean.java, changed to @Named from @ManagedBean:

@Named("db")
@ApplicationScoped
public class DatabaseBean implements Serializable {
}

LoginBean has a function:

public String login(String name, String password) {
    System.out.println("login called"+name);
    // other stuff

}

With my second implementation (the one where I try to use Weld), the print is called once: "login called", and the username is empty (I checked this with name.IsEmpty()).

I have also tried injecting it by constructor:

loginBean.java

@Inject
public LoginBean(DatabaseBean db) {
    System.out.println("constructor");
    this.db = db;
}

When I do this the I get lots of "constructor" prints, so it is called several times, but I don't see why - I guess this is the problem though, only one instance of LoginBean gets the input (username and password) and then lots of new ones are created for some reason. Why is that?

I use Eclipse and Tomcat8 to run it. Thank you for reading!

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Lomtrur
  • 1,703
  • 2
  • 19
  • 35
  • 1
    And which `@SessionScoped` you should use the correct one for that also. – M. Deinum Apr 01 '16 at 13:48
  • Hello, thanks for the replies! My sessionscoped: import javax.faces.bean.SessionScoped; – Lomtrur Apr 01 '16 at 13:54
  • 1
    When using CDI you have to use the CDI scopes **not** the JSF scopes. – M. Deinum Apr 01 '16 at 14:01
  • Hello, thank you everyone, this solved everything, I am stupid. I am using javax.enterprise.context.ApplicationScoped / javax.enterprise.context.SessionScoped and it works now! - Is there a way for me to accept "comment answers"? The only thing I found is the upvote – Lomtrur Apr 01 '16 at 14:03
  • 1
    As a tip, I make it a habit to actually put those annotations with full package in the code itself rather than have import statements for them. Then there can be no mixups with auto-generation of import statements. – Gimby Apr 01 '16 at 14:12

1 Answers1

2

managed bean constructor called multiple times

CDI may call constructor more often than expected while generating/creating enhanced subclasses/proxies. See also Field.get(obj) returns all nulls on injected CDI managed beans, while manually invoking getters return correct values. Just do not log constructor invocation, it would only confuse yourself. @PostConstruct is the only interesting method to hook on.


the print is called once: "login called", and the username is empty (I checked this with name.IsEmpty()).

As to the concrete problem of form input values being null when the action method is invoked, and thus the @SessionScoped CDI managed bean seemingly being recreated on every access, this matches the behavior of a @Dependent scoped bean. This is the default scope when no valid CDI managed bean scope can be found. See also What is the default Managed Bean Scope in a JSF 2 application?

This in turn suggests you imported @SessionScoped from the wrong package. Make sure it's from the javax.enterprise.context package and not from e.g. javax.faces.bean. JSF managed bean scopes are not recognizable as valid CDI managed bean scopes.

import javax.inject.Named;
import javax.enterprise.context.SessionScoped;

@Named("login")
@SessionScoped
public class LoginBean implements Serializable {
    // ...
}
Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555