Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Application exceptions should not be wrapped in EJBException #6573

Closed
andregs opened this issue Feb 17, 2019 · 6 comments · Fixed by #6875
Closed

Application exceptions should not be wrapped in EJBException #6573

andregs opened this issue Feb 17, 2019 · 6 comments · Fixed by #6875
Assignees
Labels

Comments

@andregs
Copy link

andregs commented Feb 17, 2019

Hi! I think I found an issue in OpenLiberty handling of EJBException. I have this rule in my ejb-jar.xml:

  <assembly-descriptor>
    <application-exception>
      <exception-class>java.lang.RuntimeException</exception-class>
      <rollback>true</rollback>
    </application-exception>
  </assembly-descriptor>

With that, I expect all runtime exceptions thrown by EJBs not being wrapped in javax.ejb.EJBException.

I have also a @Stateless bean throwing such exception:

  public <T extends Serializable> T findById(long id, Class<T> type) {
    T entity = em.find(type, id);
    if (entity == null) {
      throw new javax.ws.rs.NotFoundException(); // extends RuntimeException
    }
    return entity;
  }

My JAX-RS resource @Injects this EJB and, when the exception is thrown, I expect to see a 404 response (due to jax-rs handling of NotFoundException). That works fine in Payara 5, but in OpenLiberty 18.0.0.4 it gives me HTTP 500 because the rule in ejb-jar.xml is ignored:

[ERROR   ] CNTR0020E: EJB threw an unexpected (non-declared) exception during invocation of method "findById" on bean "BeanId(3827612f-ddec-4eda-b700-2ace3f209102#3827612f-ddec-4eda-b700-2ace3f209102.war#ServiceFunctions, null)". Exception data: javax.ws.rs.NotFoundException: HTTP 404 Not Found
        at com.andregs.icecream.ServiceFunctions.findById(ServiceFunctions.java:42)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.ibm.ejs.container.EJSContainer.invokeProceed(EJSContainer.java:4886)
        at [internal classes]
        at com.andregs.icecream.EJSLocalNSLServiceFunctions_c418c817.findById(EJSLocalNSLServiceFunctions_c418c817.java)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.jboss.weld.util.reflection.Reflections.invokeAndUnwrap(Reflections.java:410)
        at [internal classes]
        at com.andregs.icecream.ServiceFunctions$Proxy$_$$_Weld$EnterpriseProxy$.findById(Unknown Source)
        at com.andregs.icecream.product.FlavorService.findById(FlavorService.java:48)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.ibm.ejs.container.EJSContainer.invokeProceed(EJSContainer.java:4886)
        at [internal classes]
        at com.andregs.icecream.product.EJSLocalNSLFlavorService_2b23ac18.findById(EJSLocalNSLFlavorService_2b23ac18.java)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.jboss.weld.util.reflection.Reflections.invokeAndUnwrap(Reflections.java:410)
        at [internal classes]
        at com.andregs.icecream.product.FlavorService$Proxy$_$$_Weld$EnterpriseProxy$.findById(Unknown Source)
        at com.andregs.icecream.product.FlavorResource.lambda$findFlavorById$3(FlavorResource.java:70)
        at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
        at com.ibm.ws.threading.internal.PolicyTaskFutureImpl.run(PolicyTaskFutureImpl.java:689)
        at [internal classes]

[ERROR   ] WLTC0017E: Resources rolled back due to setRollbackOnly() being called.
[err] javax.ejb.EJBException: See nested exception; nested exception is: javax.ws.rs.NotFoundException: HTTP 404 Not Found
[err]   at com.ibm.ejs.container.util.ExceptionUtil.EJBException(ExceptionUtil.java:399)
[err]   at [internal classes]
[err]   at com.andregs.icecream.EJSLocalNSLServiceFunctions_c418c817.findById(EJSLocalNSLServiceFunctions_c418c817.java)
[err]   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[err]   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[err]   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[err]   at java.lang.reflect.Method.invoke(Method.java:498)
[err]   at org.jboss.weld.util.reflection.Reflections.invokeAndUnwrap(Reflections.java:410)
[err]   at [internal classes]
[err]   at com.andregs.icecream.ServiceFunctions$Proxy$_$$_Weld$EnterpriseProxy$.findById(Unknown Source)
[err]   at com.andregs.icecream.product.FlavorService.findById(FlavorService.java:48)
[err]   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[err]   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[err]   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[err]   at java.lang.reflect.Method.invoke(Method.java:498)
[err]   at com.ibm.ejs.container.EJSContainer.invokeProceed(EJSContainer.java:4886)
[err]   at [internal classes]
[err]   at sun.reflect.GeneratedMethodAccessor53.invoke(Unknown Source)
[err]   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[err]   at java.lang.reflect.Method.invoke(Method.java:498)
[err]   at com.ibm.ejs.container.interceptors.InterceptorProxy.invokeInterceptor(InterceptorProxy.java:200)
[err]   at [internal classes]
[err]   at sun.reflect.GeneratedMethodAccessor52.invoke(Unknown Source)
[err]   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[err]   at java.lang.reflect.Method.invoke(Method.java:498)
[err]   at com.ibm.ejs.container.interceptors.InterceptorProxy.invokeInterceptor(InterceptorProxy.java:200)
[err]   at [internal classes]
[err]   at com.andregs.icecream.product.EJSLocalNSLFlavorService_2b23ac18.findById(EJSLocalNSLFlavorService_2b23ac18.java)
[err]   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[err]   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[err]   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[err]   at java.lang.reflect.Method.invoke(Method.java:498)
[err]   at org.jboss.weld.util.reflection.Reflections.invokeAndUnwrap(Reflections.java:410)
[err]   at [internal classes]
[err]   at com.andregs.icecream.product.FlavorService$Proxy$_$$_Weld$EnterpriseProxy$.findById(Unknown Source)
[err]   at com.andregs.icecream.product.FlavorResource.lambda$findFlavorById$3(FlavorResource.java:70)
[err]   at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
[err]   at com.ibm.ws.threading.internal.PolicyTaskFutureImpl.run(PolicyTaskFutureImpl.java:689)
[err]   at [internal classes]
[err]   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[err]   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[err]   at java.lang.Thread.run(Thread.java:748)
[err] Caused by: javax.ws.rs.NotFoundException: HTTP 404 Not Found
[err]   at com.andregs.icecream.ServiceFunctions.findById(ServiceFunctions.java:42)
[err]   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[err]   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[err]   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[err]   at java.lang.reflect.Method.invoke(Method.java:498)
[err]   at com.ibm.ejs.container.EJSContainer.invokeProceed(EJSContainer.java:4886)
[err]   at [internal classes]
[err]   at sun.reflect.GeneratedMethodAccessor53.invoke(Unknown Source)
[err]   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[err]   at java.lang.reflect.Method.invoke(Method.java:498)
[err]   at com.ibm.ejs.container.interceptors.InterceptorProxy.invokeInterceptor(InterceptorProxy.java:200)
[err]   at [internal classes]
[err]   at sun.reflect.GeneratedMethodAccessor52.invoke(Unknown Source)
[err]   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[err]   at java.lang.reflect.Method.invoke(Method.java:498)
[err]   at com.ibm.ejs.container.interceptors.InterceptorProxy.invokeInterceptor(InterceptorProxy.java:200)
[err]   at [internal classes]
[err]   ... 55 more
@tkburroughs
Copy link
Member

Where is your ejb-jar.xml located in the application? From the exception, it appears your EJB is packaged in a WAR module. For open-liberty, when an EJB is packaged in a WAR module, the ejb-jar.xml file must be placed in the WEB-INF directory. If the ejb-jar.xml is packaged in a JAR in the WAR, then it will be ignored. The EJB specification only requires the WEB-INF packaging, though vendors may support packaging in a JAR within the WAR as well. Unfortunately, the specification does not define how multiple ejb-jar.xml are combined if multiple JAR modules are packaged in a WAR module, so open-liberty only supports a single ejb-jar.xml packaged in WEB-INF.

If your ejb-jar.xml is located in the WEB-INF directory of your WAR module, then turning on EJBContainer=all trace and looking for the string "Application Exception map contents:" should help us understand if it is still not reading the information from ejb-jar.xml or if that information is not being handled properly.

Thanks,

@andregs
Copy link
Author

andregs commented Feb 19, 2019

This is the structure:

2019-02-18 21:06:18 .....          131          109  META-INF\MANIFEST.MF
2019-02-18 21:06:18 D....            0            0  WEB-INF\classes\com\andregs <- java code (ejbs, jax-rs etc.)
2019-02-18 21:06:20 D....            0            0  WEB-INF\classes\META-INF <- sql files, microprofile-config.properties, persistence.xml etc.
2019-02-17 00:06:30 .....          565          286  WEB-INF\ejb-jar.xml

I attached the trace requested, and there's no "Application Exception map contents:" in it.

Thank you!

@tkburroughs
Copy link
Member

Unfortunately the trace point for the application exception map isn't currently called (we'll have to get that fixed), but I can tell that liberty is locating the ejb-jar.xml, I just cannot tell what is being read from it.

Also I haven't been able to recreate this problem, so I must be missing something that is important to your scenario. Here is how I'd like to proceed:

  1. Perhaps there is some minor syntax error in your ejb-jar.xml file such that it trips up reading the application exception information. Could you provide the full contents of the ejb-jar.xml file?

  2. The EJB spec does have some tricky rules with exceptions around transaction boundaries, perhaps something unique is happening related to transactions. If you could collect another trace of the actual exception being thrown, I should be able to tell why it is being wrapped in EJBException. The current trace provided just shows the app starting, not the error occurring.

Thanks,

@andregs
Copy link
Author

andregs commented Feb 20, 2019

Here's ejb-jar.xml and the trace with the exception being thrown:
ejb-jar and trace.zip

Thanks,

@tkburroughs tkburroughs added the release bug This bug is present in a released version of Open Liberty label Feb 20, 2019
@tkburroughs
Copy link
Member

The problem you are seeing is with the inherited element of application-exception. It seems the value is not defaulting properly. If you set the value to true, then you should see the behavior you want:

  <assembly-descriptor>
    <application-exception>
      <exception-class>java.lang.RuntimeException</exception-class>
      <rollback>true</rollback>
      <inherited>true</inherited>
    </application-exception>
  </assembly-descriptor>

This will at least allow you to work around the issue. In my recreate attempt I had not thrown a subclass of RuntimeException, but RuntimeException itself. Switching to a subclass, I am able to recreate the problem, and verify setting inherited prevented the exception from being wrapped in an EJBException.

I'm marking this with release bug as my first read through the EJB specification suggests the default for this setting should be true. There is a bit of history behind this behavior though. When application-exception was introduced in EJB 3.0, it did not specify this behavior; some vendors inherited the application-exception setting, others did not.... so in EJB 3.1, the specification was clarified and the inherited element was added to allow the behavior to be configured. The liberty code base originally chose to not inherit application-exception. For backward compatibility, there may be some scenarios where open-liberty may need to default the setting to false, however, this does not appear to be such a scenario. For EJB 3.2 applications with an ejb-jar.xml at version 3.2, the specification default should be honored.

@andregs
Copy link
Author

andregs commented Feb 21, 2019

Thank you for this great support and the great app server!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants