ejb@glassfish.java.net

Re: Application Exception being wrapped into EJBException

From: Kenneth Saks <Kenneth.Saks_at_Sun.COM>
Date: Mon, 02 Oct 2006 10:59:09 -0400

Cheng Fang wrote:

> Our tests for the similar scenario passed. The only difference
> between our tests and your is, your ValidationException is from Entity
> lifecycle callback methods, and our unchecked ApplicationException is
> from a regular slsb business methods.
> JPA spec says entity lifecycle callback methods may throw
> runtime/uncheckec exception, which causes the current transaction to
> be rolled back. So your unchecked ApplicationException behaves more
> like a system exception. EJB interceptor methods are more restrictive
> in that it does not allow any application exception.

That's true of callbacks defined in an interceptor class, but not true
of AroundInvoke methods.
The signature of an AroundInvoke method is defined to throw
java.lang.Exception so that it may
propagate any application-defined exceptions that appear in the
corresponding business
method's signature.

>
>
> Throwing such runtime exception from @PrePersist seems a pretty common
> use case. The JPA spec has such an example. Can someone clarify?

I'm not aware of any requirements in the persistence spec that guarantee
that an exception thrown
by the entity code will propagate *as is* back to the caller of an
EntityManager API. The EntityManager
API is typed to throw certain specific runtime exceptions. The
@ApplicationException behavior
is EJB-container specific, so the persistence manager doesn't know
anything about it. The persistence
manager is probably just wrapping the ValidationException into one of
the exceptions defined in
the persist() API method signature. The ejb container then sees a
runtime exception, not an
Application Exception.

Also note that even if the ValidationException were to be propagated as
is, the persistence
manager still would not know it is an EJB "Application Exception" so any
required behavior
such as marking the transaction for rollback would still be performed by
the persistence
manager regardless of the attributes of the @ApplicationException
definition.

 --ken

>
>
> Cheng
>
>
>
>
> Antonio Goncalves wrote:
>
>> Hi,
>>
>> I've got a JSF back bean trying to catch my application exception but
>> ends up with an EJBException. Here is my model :
>>
>> * A Customer entity bean throws an Application Exception in a call
>> back method to validate its data
>>
>> @Entity
>> public class Customer implements Serializable {
>>
>> @PrePersist
>> @PreUpdate
>> private void validateData() {
>> if (firstname == null || "".equals(firstname))
>> throw new *ValidationException*("Invalid first name");
>> if (lastname == null || "".equals(lastname))
>> throw new ValidationException("Invalid last name");
>> }
>> }
>>
>> * The Validation Exception is a RuntimeException but uses the
>> ApplicationException annotation
>>
>> @*ApplicationException*(rollback = true)
>> public class *ValidationException* extends *RuntimeException* {
>>
>> }
>>
>> * Between the Entity and JSF there is a Stateless bean that
>> manipulates this entity but doesn't wrap or throw an exception
>>
>> @Stateless
>> public class CustomerBean implements CustomerRemote, CustomerLocal {
>>
>> @PersistenceContext(name = "petstorePU")
>> private EntityManager em;
>>
>> public Customer createCustomer(final Customer customer) {
>> em.persist(*customer*);
>> }
>>
>> }
>>
>> * My JSF Back Bean calls the Stateless to create a customer. He tries
>> to catch the ValidationException and display the error message on my
>> page
>>
>> public String doCreateCustomer() {
>>
>> FacesContext context = FacesContext.getCurrentInstance();
>> String navigateTo = null;
>>
>> try {
>> customer = customerBean.createCustomer(customer, address);
>> } *catch (ValidationException e)* {
>> context.addMessage(null, new
>> FacesMessage(FacesMessage.SEVERITY_WARN , e.getMessage(), null));
>> }
>>
>> If I change the catch (ValidationException e) into catch
>> (EJBException e) it woks because here is my stack trace on the server
>>
>> *javax.ejb.EJBException*
>> at
>> com.sun.ejb.containers.BaseContainer.processSystemException(BaseContainer.java:3753)
>>
>> at
>> com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:3653)
>>
>> at
>> com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:3455)
>>
>> at
>> com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1257)
>> at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke
>> (EJBLocalObjectInvocationHandler.java:192)
>> at
>> com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:118)
>>
>> at $Proxy163.createCustomer(Unknown Source)
>> at
>> com.yaps.petstore.web.jsf.AccountController.doCreateCustomer(Unknown
>> Source)
>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>> at
>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java
>> :39)
>> at
>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>>
>> at java.lang.reflect.Method.invoke(Method.java:585)
>> at com.sun.el.parser.AstValue.invoke(AstValue.java:157)
>> at
>> com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:283)
>> at
>> javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:71)
>>
>> at com.sun.faces.application.ActionListenerImpl.processAction
>> (ActionListenerImpl.java:96)
>> at javax.faces.component.UICommand.broadcast(UICommand.java:383)
>> at
>> javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:471)
>> at javax.faces.component.UIViewRoot.processApplication
>> (UIViewRoot.java:783)
>> at
>> com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:97)
>>
>> at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:244)
>> at com.sun.faces.lifecycle.LifecycleImpl.execute
>> (LifecycleImpl.java:113)
>> at javax.faces.webapp.FacesServlet.service(FacesServlet.java:244)
>> at
>> org.apache.catalina.core.ApplicationFilterChain.servletService(ApplicationFilterChain.java:397)
>>
>> at org.apache.catalina.core.StandardWrapperValve.invoke
>> (StandardWrapperValve.java:278)
>> at
>> org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:586)
>>
>> at
>> org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:556)
>>
>> at org.apache.catalina.core.StandardContextValve.invokeInternal
>> (StandardContextValve.java:246)
>> at
>> org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:185)
>>
>> at
>> org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:586)
>>
>> at com.sun.enterprise.web.WebPipeline.invoke (WebPipeline.java:73)
>> at
>> org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:182)
>>
>> at
>> org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:586)
>>
>> at com.sun.enterprise.web.VirtualServerPipeline.invoke
>> (VirtualServerPipeline.java:120)
>> at
>> org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:939)
>> at
>> org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:137)
>>
>> at org.apache.catalina.core.StandardPipeline.doInvoke
>> (StandardPipeline.java:586)
>> at
>> org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:556)
>>
>> at
>> org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:939)
>> at org.apache.coyote.tomcat5.CoyoteAdapter.service
>> (CoyoteAdapter.java:231)
>> at
>> com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.invokeAdapter(DefaultProcessorTask.java:619)
>>
>> at
>> com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.processNonBlocked
>> (DefaultProcessorTask.java:550)
>> at
>> com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.process(DefaultProcessorTask.java:780)
>>
>> at
>> com.sun.enterprise.web.connector.grizzly.DefaultReadTask.executeProcessorTask
>> (DefaultReadTask.java:326)
>> at
>> com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:251)
>>
>> at
>> com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:205)
>>
>> at
>> com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java:252)
>> at
>> com.sun.enterprise.web.connector.grizzly.WorkerThreadImpl.run(WorkerThreadImpl.java:103)
>>
>> Caused by: com.yaps.petstore.exception.* ValidationException*:
>> Invalid first name
>> at com.yaps.petstore.domain.customer.Customer.validateData(Unknown
>> Source)
>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>> at sun.reflect.NativeMethodAccessorImpl.invoke
>> (NativeMethodAccessorImpl.java:39)
>> at
>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>>
>> at java.lang.reflect.Method.invoke(Method.java:585)
>> at
>> oracle.toplink.essentials.internal.security.PrivilegedAccessHelper.invokeMethod
>> (PrivilegedAccessHelper.java:307)
>> at
>> oracle.toplink.essentials.internal.ejb.cmp3.metadata.listeners.MetadataEntityListener.invokeMethod(MetadataEntityListener.java:302)
>>
>> at
>> oracle.toplink.essentials.internal.ejb.cmp3.metadata.listeners.MetadataEntityClassListener.invokeMethod
>> (MetadataEntityClassListener.java:69)
>> at
>> oracle.toplink.essentials.internal.ejb.cmp3.metadata.listeners.MetadataEntityListener.prePersist(MetadataEntityListener.java:439)
>>
>> at
>> oracle.toplink.essentials.descriptors.DescriptorEventManager.notifyListener
>> (DescriptorEventManager.java:658)
>> at
>> oracle.toplink.essentials.descriptors.DescriptorEventManager.notifyEJB30Listeners(DescriptorEventManager.java:601)
>>
>> at
>> oracle.toplink.essentials.descriptors.DescriptorEventManager.executeEvent
>> (DescriptorEventManager.java:199)
>> at
>> oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.registerNotRegisteredNewObjectForPersist(UnitOfWorkImpl.java:3226)
>>
>> at
>> oracle.toplink.essentials.internal.ejb.cmp3.base.RepeatableWriteUnitOfWork.registerNotRegisteredNewObjectForPersist
>> (RepeatableWriteUnitOfWork.java:298)
>> at
>> oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.registerNewObjectForPersist(UnitOfWorkImpl.java:3186)
>>
>> at
>> oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerImpl.persist
>> (EntityManagerImpl.java:170)
>> at
>> com.sun.enterprise.util.EntityManagerWrapper.persist(EntityManagerWrapper.java:433)
>>
>> at
>> com.yaps.petstore.service.customer.CustomerBean.createCustomer(Unknown
>> Source)
>> at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
>> at
>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>>
>> at
>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>>
>> at java.lang.reflect.Method.invoke (Method.java:585)
>> at
>> com.sun.enterprise.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1050)
>>
>> at
>> com.sun.enterprise.security.SecurityUtil.invoke(SecurityUtil.java:165)
>> at com.sun.ejb.containers.BaseContainer.invokeTargetBeanMethod
>> (BaseContainer.java:2788)
>> at
>> com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:3870)
>> at
>> com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:184)
>>
>> ... 43 more
>>
>> I am confused because on the EJB specification this is what's written :
>>
>> 14.1.1 Application Exceptions
>>
>> An application exception may be a subclass (direct or indirect) of
>> java.lang.Exception (i.e., a "checked exception"), or an application
>> exception class may be defined as a subclass of the
>> java.lang.RuntimeException (an "unchecked exception")
>>
>> 14.1.2 Goals for Exception Hand
>>
>> An application exception thrown by an enterprise bean instance should
>> be reported to the client precisely (i.e., the client gets the same
>> exception)
>>
>> 14.2.1 Application Exceptions
>>
>> An application exception that is an unchecked exception is defined as
>> an application exception by annotating it with the
>> applicationException metadata annotation.
>>
>> Thanks for your help,
>>
>>
>>
>> Antonio
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: ejb-unsubscribe_at_glassfish.dev.java.net
> For additional commands, e-mail: ejb-help_at_glassfish.dev.java.net
>