17

I'm using EclipseLink on GlassFish 3.1.1 and I'm trying to understand this exception:

javax.ejb.EJBException: Illegal non-business method access on no-interface view
    at org.mycompany.myproject.session.__EJB31_Generated__MyBeanFacade__Intf____Bean__.getEntityManager(Unknown Source)
    at org.mycompany.myproject.session.AbstractFacade.edit(AbstractFacade.java:28)
    at org.mycompany.myproject.controller.EditMyBeanServlet.doPost(EditMyBeanServlet.java:199)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)

Notice that the stack trace indicates that the problem is triggered in the Netbeans generated AbstractFacade.getEntityManager method.

Any idea what the heck is going on or any tips to troubleshoot? I'm guessing that either the transaction or caching state in the EJB is weird when this happens because sometimes calling the edit method works fine. I'm calling the EJB methods from a Servlet. The exception occurs when trying to save changes to an entity.

Ryan
  • 7,499
  • 9
  • 52
  • 61

3 Answers3

38

The error you get most likely indicates that your code is trying to call the protected method anyway. This is not allowed for no-interface views on an EJB. You are only allowed to call public methods.

There's a small mismatch here between the normal Java class rules and the EJB rules. For a no-interface view, a proxy is created based on the original class type (typically a dynamic sub-class of it). This thus means that protected and package private methods are visible for code in the same package, and as far as the Java compiler is concerned, your code is allowed to call those.

But as mentioned, this is not allowed by the EJB rules, and thus an exception is thrown.

You can reproduce this easily by injection a bean like the following:

@Stateless
public class FooBean {

    public void callMe() {
    }

    protected void doNotCallMe() {
    }
}

Inject this somewhere (e.g. Servlet in same package) and try to call doNotCallMe(). You'll see the same exception. Call callMe() and everything will be fine.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
  • Yes, I understand that only public methods are part of the EJB interface. However I'm actually calling a public method named edit from the servlet (code provided in my answer). It seems there is a bug with certain overloaded methods. – Ryan Jan 03 '12 at 17:29
  • 1
    Ok, that could well be the case. Without the actual servlet code that does the call this was hard to say. My answer thus doesn't really apply to your problem, although I hope people searching for the exception in your title find the explanation useful anyway. I'll upvote your answer ;) – Arjan Tijms Jan 03 '12 at 23:36
  • thanks for taking the time to answer my question. I think your answer is helpful (upvoted it yesterday). I should have provided the more code. I think your answer does cover what the exception usually means. – Ryan Jan 04 '12 at 14:50
  • 2
    @ArjanTijms, not only solved my problem but provided information about why public access modifer is needed – sarahTheButterFly Jan 15 '12 at 23:55
4

I think I may have found a solution and possibly a bug in third party software. It seems like GlassFish 3.1.1 / EJB 3.1 / EclipseLink can't handle method overloading correctly. I've got a method defined in my EJB named edit that overloads (not overrides) the method from the parent abstract class. There is a method named edit in the abstract parent of the EJB that takes a generic type and then I've got a method named edit in the EJB which takes a List. If I rename the method to something else so that it is no longer overloading then the exception goes away!

Code:

public abstract class AbstractFacade<T> {
protected abstract EntityManager getEntityManager();
public void edit(T entity) {
...

and

@Stateless
public class MyEntityFacade extends AbstractFacade<MyEntity> {
protected EntityManager getEntityManager() { return em; )
public void edit(List<MyEntity> entities) {
...

Note: I noticed if I make the getEntityManager method public instead of protected I'll get a TransactionRequiredException instead of an EJBException.

Ryan
  • 7,499
  • 9
  • 52
  • 61
  • In other words: it appears EclipseLink cannot handle overloading inherited methods in an EJB – Ryan Jan 02 '12 at 20:47
  • @piotr-nowicki - Bingo, I think you found an issue report of the problem. Thanks. Funny that someone downvoted this answer! – Ryan Jan 03 '12 at 17:33
  • I've bumped into the same bug, so I reported it to GlassFish JIRA. Waiting until it's fixed :-) – Piotr Nowicki Jan 03 '12 at 17:38
  • It seems the referenced JIRA was already fixed some time ago, but that version hasn't been released yet. So the problem is that the overload with the generic parameter isn't invoked as an EJB method. This method thus runs in a non-EJB context (inside the proxy, which is weird, but that's what bugs are). From this context the protected method is called which IS registered as an EJB method, just not one clients can call and hence the exception. I'm only a bit puzzled about the TransactionRequiredException... – Arjan Tijms Jan 03 '12 at 23:46
  • p.s. > it appears EclipseLink cannot handle overloading inherited methods in an EJB - I think EclipseLink has nothing to do with this. This seems to be purely about the dynamic proxy generation code in the GlassFish EJB implementation. – Arjan Tijms Jan 03 '12 at 23:48
  • You're probably right that this issue is with GlassFish, not EclipseLink. I didn't really know what was going on at the time. I'm fairly new to injection, managed transactions, and managed database entities with caching. I'm not exactly sure about the TransactionRequiredException either, but renaming my method to avoid overloading is a simple fix and I'm moving forward. My guess is that the transaction isn't injected into the method call like it should due to the bug. Thanks again for answering my question. – Ryan Jan 04 '12 at 15:06
0

What is weird is i had same problme with on inner class of my EJB. While trying to call private method of parent or accessing on injected EJB, i faced some problems. I had visibility on most of things but finally a runtie, things goes wrong.

Finally, i decided to retrieve my parent class throught JNDI, thus i could call public method without troubles. Meanwhile i could call still private methods on my parents class, i still have to remember that it will fail.

Benjamin Fuentes
  • 674
  • 9
  • 22