2

I'm creating web application and i'm using java ee 7, deploying it using maven tomcat plugin creating war. I have servlets, ejb, some logic, jpa integration and etc. I use command pattern to process requests. My main servlet fetches parameters and redirects user to the next page according on command from hidden input as a parameter.

I have sign in form and classes that realize login logic. These classes are next

EDIT (I edited my code adding injection of beans. Also i created according qualifiers for every command)

My code

SigninCommand.java

@SigninCommandQualifier
public class SigninCommand implements Command {

    @Inject
    private UserEJB userEJB;

    public String execute(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String password = request.getParameter("password");
        String email = request.getParameter("email");
        User signinUser = new User(email, password);
        User foundUser = userEJB.findUser(signinUser);
        if (foundUser != null) {
            request.setAttribute("passedAuth", true);
            return PagesManager.getProperty("page.nameGeneration");
        } else {
            request.setAttribute("passedAuth", false);
            return PagesManager.getProperty("page.signin");
        }
    }
}

UserEJB.java

@Stateless
public class UserEJB implements UserEJBRemote{
    @Inject
    private EntityManager em;
    public List<User> findUsers() {
        TypedQuery<User> query = em.createNamedQuery(FIND_ALL, User.class);
        return query.getResultList();
    }

    public User findUser(@NotNull User user) {
        return em.find(User.class, user);
    }

    public
    @NotNull
    User createUser(@NotNull User user) {
        em.persist(user);
        return user;
    }

    public
    @NotNull
    User updateUser(@NotNull User user) {
        return em.merge(user);
    }

    public void deleteUser(@NotNull User user) {
        em.remove(em.merge(user));
    }
}

beans.xml

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       version="1.1" bean-discovery-mode="all">
</beans>

ProjectServlet.java

public class ProjectServlet extends HttpServlet {

    @Inject
    @EmptyCommandQualifier
    private Command command;

    @Inject
    private ActionFactory actionFactory;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processRequest(request, response);
    }

    private void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        String action = request.getParameter("command");
        try {
            command = actionFactory.defineCommand(action);
        } catch (IllegalArgumentException e) {
            request.setAttribute("msg", action + " " + MessageManager.getProperty("message.wrongaction"));
        }
        String page;
        try {
            page = command.execute(request, response);
        } catch (IOException e) {
            page = PagesManager.getProperty("page.error");
        }
        if (page != null) {
            if (page.equals("not redirecting")) {
                return;
            }
            RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(page);
            dispatcher.forward(request, response);
        } else {
            page = PagesManager.getProperty("page.index");
            request.getSession().setAttribute("nullPage",
                    MessageManager.getProperty("message.nullpage"));
            response.sendRedirect(request.getContextPath() + page);
        }
    }
}

Command.java

public interface Command {
    String execute(HttpServletRequest request, HttpServletResponse response) throws IOException;
}

CommandEnum.java

public enum CommandEnum {

    EMPTY_COMMAND {
        {
            this.command = emptyCommand;
        }
    },
    NAME_GENERATION {
        {
            this.command = nameGenerationCommand;
        }
    },
    NAME_GENERATION_SETTINGS {
        {
            this.command = nameGenerationSettingsCommand;
        }
    },
    SIGNIN {
        {
            this.command = signinCommand;
        }
    };

    Command command;

    @Inject
    EmptyCommand emptyCommand;
    @Inject
    NameGenerationCommand nameGenerationCommand;
    @Inject
    NameGenerationSettingsCommand nameGenerationSettingsCommand;
    @Inject
    SigninCommand signinCommand;

    public Command getCommand() {
        return command;
    }
}

ActionFactory.java

public class ActionFactory {

    @Inject
    @EmptyCommandQualifier
    private Command command;

    @Inject
    private CommandEnum commandEnum;

    public Command defineCommand(String action) throws IllegalArgumentException {
        if (action == null || action.isEmpty()) {
            return command;
        }
        commandEnum = CommandEnum.valueOf(action.toUpperCase());
        command = commandEnum.getCommand();
        return command;
    }

    @Produces
    public static CommandEnum getEmptyCommandEnum()
    {
        return CommandEnum.EMPTY_COMMAND;
    }
}

The problem

When i click sign in button on login page i catch next exception:

java.lang.NullPointerException: Cannot invoke "factory.ActionFactory.defineCommand(String)" because "this.actionFacto
ry" is null
        at servlet.ProjectServlet.processRequest(ProjectServlet.java:39)
        at servlet.ProjectServlet.doPost(ProjectServlet.java:33)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
        at java.base/java.lang.Thread.run(Thread.java:832)
        at org.apache.coyote.http11.AbstractHttp11Proces
sor.process(AbstractHttp11Processor.java:1041)
        at org.apache.coyote.AbstractProtocol$AbstractCo
nnectionHandler.process(AbstractProtocol.java:603)
        at org.apache.tomcat.util.net.JIoEndpoint$Socket
Processor.run(JIoEndpoint.java:310)
        at java.base/java.util.concurrent.ThreadPoolExec
utor.runWorker(ThreadPoolExecutor.java:1130)
        at java.base/java.util.concurrent.ThreadPoolExec
utor$Worker.run(ThreadPoolExecutor.java:630)
        at java.base/java.lang.Thread.run(Thread.java:83
2)

actionFactory is null and i don't know why.

What i've tried

  1. Adding @Stateless annotation to SigninCommand
  2. Adding bean.xml file to WEB-INF folder (before it was placed at META-INF)
  3. Clear IDEA cache
  4. Attach @Named annotation to UserEJB class

But i still get NPE.

Help, please.

tohhant
  • 103
  • 10
  • You need to add UserEjb to the command in another way. Inject will not work if the object is not instantiated by the container. Perhaps you can add it by getCommand(userEjb). ... That will not work as well. You create the ActionFactory also by new. Perhaps you should think of making each command a Bean and get them via @Inject Instance commands. – aschoerk Mar 16 '21 at 23:10
  • @aschoerk, thank you for replying, i edited my code upper, adding injection to classes to avoid `new` instantiation and added qualifiers to define type of created interface instance, but i'm now getting NPE of actionFactory – tohhant Mar 17 '21 at 00:22
  • Strange, so the @Inject into the Servlet does not work. Is anything injected into the Servlet? Do you create only one archive (war) or several (ear)? What is the container you are using? – aschoerk Mar 17 '21 at 04:35
  • @aschoerk, i,m creating war using tomcat – tohhant Mar 17 '21 at 13:01
  • Tomcat alone is no Container which handles CDI. Do you work according to https://tomcat.apache.org/tomcat-9.0-doc/cdi.html? Or do you include WELD-Standalone? btw @Stateless will not work either. For that you need an EJB-Container. – aschoerk Mar 17 '21 at 19:25
  • @aschoerk, thank you, i didn't mentioned that tomcat only servlet container :) I migrated to Wildfly and now have errors from JPA that weren't appeared in the tomcat case. Appreciate your help – tohhant Mar 18 '21 at 16:58

2 Answers2

2

The Problem was, besides the usage of new for CDI-beans, that tomcat was used as container without any additions like Weld-Standalone. Therefore neither Ejb-Annotations like @Ejb, @Standalone,... nor CDI-Annotations like @Inject had any effect during deployment of the war-file. The reasonable solution for that is to switch from a pure servlet-container to a microprofile-container like wildfly, kumuluzee ...

aschoerk
  • 3,333
  • 2
  • 15
  • 29
1

This is usually caused by some occurrence of instantiation by new somewhere in your call hierarchy. Make sure that any instance of your SigninCommand class is not being instantiated by new. Since we do not have your main servlet code, I apologize that is just a guess as I can't leave a comment asking to include your servlet code. Cheers.

DLynch
  • 166
  • 1
  • 8
  • Thank you, i included servlet code to post. Yes, i have enum that instantiate SigninCommand, the code is up too. What should i do? Should i inject SigninCommand? – tohhant Mar 16 '21 at 21:18
  • Should i convert method execute to static and call without instantiating? – tohhant Mar 16 '21 at 21:41