«У Bean нет общедоступного конструктора, который не принимает параметры», несмотря на то, что он явно есть?

У меня есть EJB-компонент EmailService с очень простым методом send_email. Я получаю сообщение об ошибке в заголовке, несмотря на то, что у меня явно есть общедоступный конструктор, который не принимает параметров. Ниже указаны точная ошибка и код класса. Это очень сбивает с толку.

Ошибка:

[ОШИБКА] CNTR5007E: Класс bean-компонента websphere.jaxrs.service.EmailService для bean-компонента WebApiConsole # WebApiConsole.war # EmailService не имеет общедоступного конструктора, который не принимает параметры.

Подробности об ошибках см. Здесь (особо не на что): 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 () без ошибок.


person user2316667    schedule 21.07.2014    source источник


Ответы (4)


Почему вы не убираете инициализацию из конструктора в метод @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
    }

}
person Magic Wand    schedule 21.07.2014
comment
Потому что я никогда об этом не знал. Редактировать Woops, слишком рано нажмите "Enter". И это сработало! Могу я спросить, почему? - person user2316667; 21.07.2014
comment
Пробовал это решение. У меня не работает. Я все еще получаю сообщение об ошибке. Я ввожу entityManager (т.е. @PersistenceContext) и другой bean-компонент без сохранения состояния, используя @Inject. Никакой другой инициализации не требуется. - person Prachi; 16.05.2018

Укола еще не произошло.

Суммируя:

  1. контейнер вызывает конструктор
  2. тогда введенные поля вводятся
  3. тогда происходит постконструирование

Таким образом извлеките поисковые запросы, как предлагается, в метод постконструкции

person Koenighotze    schedule 21.07.2014

На случай, если вы приедете сюда с опозданием на несколько лет, как и я, оказывается, что это сообщение об ошибке может вводить в заблуждение. Я получил ошибку

[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

Я не думаю, что сообщение об ошибке пытается сказать, что такого метода не существует. Скорее это говорит о том, что загрузчик не смог найти тот, который существует, который можно было бы успешно загрузить. Фактическая ошибка (вызванная) - это NoClassDefFoundError в классе commonj.work.Work. Оказывается, в журнале тоже есть предупреждение:

[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;

Таким образом, EJB-компонент приложения не получил внедренных ресурсов, потому что не удалось найти commonj.work.WorkManager. Почему это предупреждение, а не ошибка - хороший вопрос. Я уверен, что приложение прекрасно справится и без этих ресурсов, верно? По сути, jar с API для commonj.work просто не был включен в развертывание. В нашем случае это потому, что старый сервер приложений предоставил его, а новый сервер приложений - нет. Небольшая корректировка файла POM, и мы решили эту проблему. На мой взгляд, очень вводящее в заблуждение сообщение об ошибке.

person Capricorn1    schedule 11.01.2019

Я бы предпочел вместо этого аннотировать ваш конструктор @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 не совсем то же самое, что было у вас. init() не будет работать вне контейнера, как в тесте JUnit.

Вам по-прежнему необходимо предоставить непараметризованный конструктор по умолчанию (часть Спецификация EJB 3.1 , раздел 4.9.2 Классы компонентов).

person Petr Hunka    schedule 02.03.2017
comment
У меня очень похожая проблема, но это решение мне не подходит. Сервер приложений (Websphere Liberty Base) не может инициализировать компонент. - person Joko; 12.09.2017
comment
Привет, @Joko, нет причин, по которым @Inject на consructor не работает для вас. Это очень распространенное использование и часть стандарта. Какой у вас вариант использования? - person Petr Hunka; 12.09.2017