5

I am developing some application, which consists of three layers:

  1. Database access layer (JPA + Hibernate as provider)
  2. Business logic layer
  3. Presentation layer (JSF 2.0)

Before I started I have read some chapters from the book Core JavaServer Faces (3rd Edition) by David Geary and Cay S. Horstmann. In this book, authors strongly recommend using @Named annotation instead of @ManagedBean. Ok, I thought I can try.

Then I proceeded to layers construction of my application by just implementing some basic functionality - users logging in.

I also read about some new annotation, namely @Inject. I thought that it can be very comfortable to just inject one layer into another basing only on interfaces. But I am afraid that I misunderstood something, so I came to you with my problem.

Let me present some parts of my code:

CredentialsBean.java:

@Named("userCredentials")
public class CredentialsBean {
    @Inject
    AccountService accountService;

    private String login;
    private String password;

    public String verify()
    {
        if (accountService.verifyCredentials(login, password))
            return "success";
        else
            return "failure";
    }
    // getters and setters
}

AccountService.java:

public interface AccountService {
    public Boolean verifyCredentials(String login, String password);
}

AccountServiceImpl.java:

public class AccountServiceImpl implements AccountService {
    @Inject
    AccountDAO dao;

    @Override
    public Boolean verifyCredentials(String login, String password) {
        // some logic
    }
}

AccountDAO.java:

public interface AccountDAO {
    public Account getAccount(String login);
}

AccountDAOImpl.java:

public class AccountDAOImpl implements AccountDAO {
    @PersistenceContext(unitName = "MyApp")
    protected EntityManager em;

    public EntityManager getEntityManager() {
        return em;
    }

    @Override
    public Account getAccount(String login) {
        // some data processing
    }
}

This last class operates on some Java class with @Entity annotation, nevermind.

I have a feeling that something is wrong with my solution.

Basic bug is fact, that even if I provide some data to the form created with <h:form>, <h:inputText> tag, when debugging verify() method I can see, that login and password are null, so something is wrong here, but I have no idea what.

I have also concerns if I understand @Inject well. Can I use it in such way like provided above to couple layers using interfaces?


Ok. I found reason why I get nulls on login and password fields, but I don't know the solution yet. It happens because during execution in some magic way, there are multiple (at least two) instances of CredentialsBean created. Checked in Eclipse debugger. First gets its fields set properly, but second one does not, and this second one's values are sent to service layer. I am wondering if it is not a question of scope. Shouldn't I put @SessionScoped in CredentialsBean?

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
rivasket
  • 377
  • 2
  • 6
  • 18
  • Your implementations classes do not have `@Named` annotation. Was this intentional or oversimplification of code snippets? – BalusC Nov 23 '11 at 11:33
  • Do they have to? I thought that it is needed only by bean used to transport information between JSF page and application logic. Am I wrong? – rivasket Nov 24 '11 at 19:59
  • `@Stateless` can also if it's supposed to be an EJB. How else should the container know which implementations you have and need to inject? – BalusC Nov 24 '11 at 20:01
  • I don't understand your reply. I think I don't need EJB. I create layers in order to allow different objects to use service layer, namely JSF bean to do some tasks, and HttpServlet to do some another tasks. I am not convinced that I need EJB components. – rivasket Nov 26 '11 at 10:46
  • It's just that the `AccountDAOImpl` is a typical `@Stateless` EJB implementation. If you want to make it `@Named`, fine, but you've got to manage the transactions yourself. But that wasn't where my comment was actually about. The point is, if you don't annotate the implementations, how should the container know which implementations you have and need to inject? – BalusC Nov 26 '11 at 14:30
  • Thank you. I think I understand it better now. I don't want to go into EJB. Could you give an example when my choice leads to some difficulties? Could you give me an example how to set injection properly? I know I have to put @Named to my interface implementations. How to indicate that exactly this implementation has to be injected to higher layer? – rivasket Nov 28 '11 at 13:38

2 Answers2

2

I believe the problem is with your CredintialsBean class. You didn't specify a scope for the bean so it's using the default scope (see What is the default scope of a Named CDI bean? for more info).

If you add something like @RequestScoped to your class it should work. Make sure you use javax.enterprise.context.RequestScoped and not the javax.faces version.

Community
  • 1
  • 1
Jon B
  • 471
  • 5
  • 8
1

Your understanding of @Inject is correct, that's exactly what it is there for. Chances are your injection points are null because you do not have a bean archive (you need a file named beans.xml in WEB-INF or META-INF if it's a jar, it can be empty). That's the common reason for having null in your injection points.

LightGuard
  • 5,298
  • 19
  • 19
  • Unfortunately it is not correct solution. I have beans.xml in WebContent/WEB-INF directory from beginning of eclipse project configuration. I still get nulls on login and password. Any ideas? – rivasket Nov 26 '11 at 17:17
  • I don't understand how you're getting nulls and not exceptions. – LightGuard Nov 29 '11 at 06:00