'Bean does not have a public constructor that does not take parameters' error despite clearly having one?

后端 未结 4 1984
小蘑菇
小蘑菇 2021-01-24 07:21

I have an EmailService EJB that has a very simple \'send_email\' method. I\'m receving the error in the title despite clearly having a public constructor that does not take para

相关标签:
4条回答
  • 2021-01-24 07:35

    The injection has not yet happened.

    In short:

    1. container calls the constructor
    2. then the injected fields get injected
    3. then the postconstruct stuff happens

    Thus extract the lookups, as suggested, into a postconstruct method

    0 讨论(0)
  • 2021-01-24 07:37

    I would prefer to annotate your constructor with @Inject instead:

    @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);
        }
    
    ...
    }
    

    >> Using @PostConstruct is not exactly the same as you had. init() method will not work outside the container like in JUnit test.

    You still need to provide the default not parametrized constructor (part of the The EJB 3.1 spec, section 4.9.2 Bean Classes).

    0 讨论(0)
  • 2021-01-24 07:45

    Just in case you are arriving here several years late as I did, it also turns out this error message may be misleading. I got the error,

    [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
    

    I don't think the error message is trying to say that such a method does not exist. Rather it's saying that the loader couldn't find one that does exist that can be successfully loaded. The actual error (caused by) is the NoClassDefFoundError on the class commonj.work.Work. It turns out that there is also a warning earlier in the log:

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

    So the Application EJB didn't get its resources injected either because commonj.work.WorkManager could not be found. Why that's a warning and not an error is a good question. I'm sure the app will do just fine without those resources, right? Basically, the jar with the APIs for commonj.work just didn't get included with the deployment. In our case, that's because the old application server provided it whereas the new application server did not. A little adjustment to the POM file and we got past that issue. Very misleading error message in my opinion.

    0 讨论(0)
  • 2021-01-24 07:57

    Why you don't remove initialization from constructor into a @PostConstruct method?

    @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
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题