I have a form in my application for which I'm trying to validate that the userName and/or email is not already on the DB.
This is service class:
@Stateless
public class CustomerFacade extends AbstractFacade<Customer> {
@PersistenceContext(unitName = "OnlineStorePU")
private EntityManager em;
@Override
protected EntityManager getEntityManager() {
return em;
}
public CustomerFacade() {
super(Customer.class);
}
}
This is the entity class:
@Entity
@Table(name = "customer")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "Customer.findAll", query = "SELECT c FROM Customer c"),
@NamedQuery(name = "Customer.findById", query = "SELECT c FROM Customer c WHERE c.id = :id"),
@NamedQuery(name = "Customer.findByName", query = "SELECT c FROM Customer c WHERE c.name = :name"),
@NamedQuery(name = "Customer.findByMobile", query = "SELECT c FROM Customer c WHERE c.mobile = :mobile"),
@NamedQuery(name = "Customer.findByEmail", query = "SELECT c FROM Customer c WHERE c.email = :email"),
@NamedQuery(name = "Customer.findByAddress", query = "SELECT c FROM Customer c WHERE c.address = :address"),
@NamedQuery(name = "Customer.findByFax", query = "SELECT c FROM Customer c WHERE c.fax = :fax"),
@NamedQuery(name = "Customer.findByTelephone", query = "SELECT c FROM Customer c WHERE c.telephone = :telephone"),
@NamedQuery(name = "Customer.findByUsername", query = "SELECT c FROM Customer c WHERE c.username = :username")})
public class Customer implements Serializable {
//ALL GETTERS AND SETTERS + CONSTRUCTOR
}
This is the class checking the form:
public class ErrorUtils {
@EJB
private CustomerFacade customerFacade;
//**the arg String uName is the username input from the form**
private boolean isUserNameInDBOK(String uName) {
boolean OKBD = true;
// Checking UserName is not in the DB
for (Customer customer : customerFacade.findAll()) {
if (customer.getUsername().equals(uName)) {
OKBD = false;
break;
}
}
return OKBD;
}
}
The error I'm getting is that the customerFacade
is null
:
Warning: StandardWrapperValve[ControllerServlet]: Servlet.service()
for servlet ControllerServlet threw exception java.lang.NullPointerException
How is this caused and how can I solve it?
Injection via @EJB
works only in container managed artifacts. I.e. instances of classes which are created by the container itself and thus not by you via the new
operator.
E.g. a servlet:
@WebServlet("/your-servlet")
public class YourServlet extends HttpServlet {
@EJB
private YourService yourService;
}
The container does new YourServlet()
all by itself. The container takes care of performing dependency injection. The container takes care of calling init()
. The container takes care of calling appropriate doXxx()
method. Etc. It's a container managed artifact.
However, you attempted to inject it in some utility class:
public class ErrorUtils {
@EJB
private CustomerFacade customerFacade;
}
This does not look like a container managed artifact. Given the complete absence of any container management related annotations on the class such as @Stateless
, @ApplicationScoped
, @WebServlet
, etc, it's very much likely that you was just manually creating an instance of it yourself like below:
ErrorUtils errorUtils = new ErrorUtils();
And then you expected that @EJB
magically gets injected.
Wrong.
You manually created an instance of ErrorUtils
class using new
keyword. You're manually managing it. So you basically also need to manually grab and set that EJB. Usually, you use JNDI for that, see also Inject EJB bean from JSF managed bean programmatically.
errorUtils.customerFacade = (CustomerFacade) new InitialContext().lookup("java:/.../CustomerFacade");
But, much better is to just turn that class into an container managed artifact. E.g. a CDI managed bean:
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class ErrorUtils {
And then inject it in your servlet instead of manually crafting it:
@WebServlet("/your-servlet")
public class YourServlet extends HttpServlet {
@Inject
private ErrorUtils errorUtils;
}
It will take care that all of its dependencies like @EJB
are also properly injected.
Unrelated to the concrete problem, the below doesn't make sense:
private boolean isUserNameInDBOK(String uName) {
boolean OKBD = true;
// Checking UserName is not in the DB
for (Customer customer : customerFacade.findAll()) {
if (customer.getUsername().equals(uName)) {
OKBD = false;
break;
}
}
return OKBD;
}
You're basically defeating the purpose of a relational database system and underestimating the powers of the structured query language SQL. You're basically copying the entire database table fully into Java's memory and then manually exploring every single record if it matches a given condition.
This is plain inefficient. You should be interacting with the database in such way that it returns exactly the information you need and nothing more. You can use among others the WHERE
clause for this. It appears that your IDE was smart enough to autogenerate such a named query for you: Customer.findByName
. Make use of it.
private boolean isUserNameInDBOK(String uName) {
return customerFacade.findByName(name) != null;
}
This way the DB will return 1 or 0 records matching the given condition. You just have to check if it returned a record or not. Yet more efficient is to add a named query which does a COUNT(*)
returning a long
or perhaps boolean
instead of a whole Customer
. Even then, the whole ErrorUtils
class is pretty superfluous in this construct. Just invoke the service method directly.