' Bean没有不带参数的公共构造函数'尽管明显有一个错误?

时间:2014-07-21 15:10:46

标签: ejb websphere ejb-3.1 java-ee-7

我有一个EmailService EJB,它有一个非常简单的'send_email'方法。尽管显然有一个不带参数的公共构造函数,但我正在接收标题中的错误。下面是确切的错误和类代码。这非常令人困惑。

错误:

  

[ERROR] CNTR5007E:websphere.jaxrs.service.EmailService bean   WebApiConsole的类#WebApiConsole.war#EmailService bean   没有不带参数的公共构造函数。

请点击此处查看错误详情(不多见):http://pic.dhe.ibm.com/infocenter/wxdinfo/v6r1/index.jsp?topic=%2Fcom.ibm.websphere.messages.doc%2Fcom.ibm.ejs.container.container.html

代码:

package websphere.jaxrs.service;

import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;

import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;

import websphere.jaxrs.helpers.ContextFinder;

    /**
     * This class provides an interface for emailing messages. It uses server environment variables to configure SMTP server and port and authentication.
     * 
     * @author me
     *
     */
    @Stateless
    @LocalBean
    public class EmailService {

        @EJB ContextFinder ctf;

        private static final String EMAIL_PASSWORD_JNDI_NAME = "EMAIL_PASSWORD";
        private static final String EMAIL_USERNAME_JNDI_NAME = "EMAIL_USERNAME";
        private static final String SMTP_SERVER_JNDI_NAME = "SMTP_SERVER";
        private static final String SMTP_PORT_JNDI_NAME = "SMTP_PORT";

        private String username;
        private String password;
        private String server;
        private Integer port;


        public EmailService() { 
            username = (String) ctf.lookup(EMAIL_USERNAME_JNDI_NAME);
            password = (String) ctf.lookup(EMAIL_PASSWORD_JNDI_NAME);
            server = (String) ctf.lookup(SMTP_SERVER_JNDI_NAME);
            port = (Integer) ctf.lookup(SMTP_PORT_JNDI_NAME);
        }

        /**
         * Sends an email to a specific user.
         * 
         * @param sendTo
         * @param subject
         * @param message
         */
        public void sendMail(String sendTo, String subject, String message) {

            try {
                Email email = new SimpleEmail();
                email.setHostName(server);
                email.setSmtpPort(port);
                email.setAuthentication(username, password);
                email.setSSLOnConnect(true);
                email.setFrom(username);
                email.setSubject(subject);
                email.setMsg(message);
                email.addTo(sendTo);
                email.send();
            } catch (EmailException e) {
                System.err.println("Failed to email");
                e.printStackTrace();
            }

        }

    }

我倾向于认为这是一个错误。我可能错了,但是上面的类中一切都是非常自包含的(没有我知道的其他配置)并且我一直收到这个错误。我试着重建这个项目。

[编辑]我做了一些实验,非常具体,删除sendMail()会导致它没有错误。

4 个答案:

答案 0 :(得分:3)

注射尚未发生。

简而言之:

  1. 容器调用构造函数
  2. 然后注入的区域被注入
  3. 然后发生postconstruct的事情
  4. 因此,如建议的那样,将查找提取到postconstruct方法

答案 1 :(得分:2)

为什么不删除构造函数中的初始化为@PostConstruct方法?

@Stateless
public class EmailService {
    @EJB ContextFinder ctf;

    private static final String EMAIL_PASSWORD_JNDI_NAME = "EMAIL_PASSWORD";
    private static final String EMAIL_USERNAME_JNDI_NAME = "EMAIL_USERNAME";
    private static final String SMTP_SERVER_JNDI_NAME = "SMTP_SERVER";
    private static final String SMTP_PORT_JNDI_NAME = "SMTP_PORT";

    private String username;
    private String password;
    private String server;
    private Integer port;

    @PostConstruct
    public void init() { 
        username = (String) ctf.lookup(EMAIL_USERNAME_JNDI_NAME);
        password = (String) ctf.lookup(EMAIL_PASSWORD_JNDI_NAME);
        server = (String) ctf.lookup(SMTP_SERVER_JNDI_NAME);
        port = (Integer) ctf.lookup(SMTP_PORT_JNDI_NAME);
    }

    public void sendMail(String sendTo, String subject, String message) {
        // send mail
    }

}

答案 2 :(得分:1)

我更愿意使用@Inject注释您的构造函数:

@Stateless
@LocalBean
public class EmailService {

    ....
    @Deprecated
    public EmailService(){}       

    @Inject 
    public EmailService(ContextFinder ctf) { 
        username = (String) ctf.lookup(EMAIL_USERNAME_JNDI_NAME);
        password = (String) ctf.lookup(EMAIL_PASSWORD_JNDI_NAME);
        server = (String) ctf.lookup(SMTP_SERVER_JNDI_NAME);
        port = (Integer) ctf.lookup(SMTP_PORT_JNDI_NAME);
    }

...
}

>>使用@PostConstruct并不完全一样。 {J}符号中的init()方法无法在容器外工作。

您仍然需要提供默认的非参数化构造函数(The EJB 3.1 spec, section 4.9.2 Bean Classes的一部分)。

答案 3 :(得分:1)

以防万一您像我一样迟到了几年,这也证明此错误消息可能会误导您。我得到了错误,

[ERROR   ] CNTR4006E: The EVENT_MANAGER_BEAN enterprise bean in the MySpecialEJB.jar module of the some-ear-DEVELOPMENT-SNAPSHOT application failed to start. Exception: com.ibm.ejs.container.EJBConfigurationException: EJB class com.notarealcompany.event.EventManagerEJB must have a public constructor that takes no parameters : some-ear-DEVELOPMENT-SNAPSHOT#MySpecialEJB.jar#EVENT_MANAGER_BEAN
    at com.ibm.ws.ejbcontainer.jitdeploy.EJBUtils.validateEjbClass(EJBUtils.java:346)
    at [internal classes]
Caused by: java.lang.NoClassDefFoundError: commonj/work/Work
    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
    at java.lang.Class.getConstructor0(Class.java:3075)
    at java.lang.Class.getConstructor(Class.java:1825)
    at com.ibm.ws.ejbcontainer.jitdeploy.EJBUtils.validateEjbClass(EJBUtils.java:337)
    ... 1 more

我不认为该错误消息试图说明这种方法不存在。而是说,加载程序找不到能够成功加载的确实存在的加载程序。 (由)引起的实际错误是类commonj.work.Work上的NoClassDefFoundError。事实证明,在日志的前面还有一个警告:

[WARNING ] CWNEN0047W: Resource annotations on the fields of the com.notarealcompany.app.ApplicationEJB class will be ignored. The annotations could not be obtained because of the exception : java.lang.NoClassDefFoundError: Lcommonj/work/WorkManager;

因此,由于找不到commonj.work.WorkManager,因此Application EJB也没有注入其资源。为什么这是警告而不是错误是一个好问题。我敢肯定,没有这些资源,该应用就可以正常运行,对吗?基本上,带有commonj.work API的jar并未包含在部署中。在我们的案例中,这是因为旧的应用程序服务器提供了它,而新的应用程序服务器没有提供它。对POM文件进行一点调整,我们就克服了这个问题。我认为这是非常令人误解的错误消息。