Let the presentation layer (JSF) handle business exceptions from the service layer (EJB)

Update the EJB method of the provided entity (using CMT):

@Override
@SuppressWarnings("unchecked")
public boolean update(Entity entity) throws OptimisticLockException {
    // Code to merge the entity.
    return true;
}

If a concurrent update is detected, javax. XML is thrown persistence. Optimisticlockexception, the update will be handled precisely by the caller (managed bean)

public void onRowEdit(RowEditEvent event) {
    try {
        service.update((Entity) event.getObject())
    } catch(OptimisticLockException e) {
        // Add a user-friendly faces message.
    }
}

But doing so will have an impact on javax. XML on the presentation layer The persistence API creates additional dependencies, a design smell that leads to tight coupling

Which exception should be wrapped so that the tight coupling problem is completely omitted? Or is there a standard way to handle this exception, which in turn does not result in enforcing any service layer dependencies on the presentation layer?

By the way, I find it awkward to catch this exception in EJB (on the service layer itself) and then return a flag value to the client (JSF)

Solution

Create a runtime exception specific to the custom service layer, which is annotated with @ applicationexception with rollback = true

@ApplicationException(rollback=true)
public abstract class ServiceException extends RuntimeException {}

Create some specific subclasses for general business exceptions, such as constraint violations, required entities, and optimistic locks

public class DuplicateEntityException extends ServiceException {}
public class EntityNotFoundException extends ServiceException {}
public class EntityAlreadyModifiedException extends ServiceException {}

Some of them can be thrown directly

public void register(User user) {
    if (findByEmail(user.getEmail()) != null) {
        throw new DuplicateEntityException();
    }

    // ...
}
public void addToOrder(OrderItem item,Long orderId) {
    Order order = orderService.getById(orderId);

    if (order == null) {
        throw new EntityNotFoundException();
    }

    // ...
}

Some of them require global interceptors

@Interceptor
public class ExceptionInterceptor implements Serializable {

    @AroundInvoke
    public Object handle(InvocationContext context) throws Exception {
        try {
            return context.proceed();
        }
        catch (javax.persistence.EntityNotFoundException e) { // Can be thrown by Query#getSingleResult().
            throw new EntityNotFoundException(e);
        }
        catch (OptimisticLockException e) {
            throw new EntityAlreadyModifiedException(e);
        }
    }

}

In EJB jar XML as the default interceptor (on all EJBs), as shown below

<interceptors>
    <interceptor>
        <interceptor-class>com.example.service.ExceptionInterceptor</interceptor-class>
    </interceptor>
</interceptors>
<assembly-descriptor>
    <interceptor-binding>
        <ejb-name>*</ejb-name>
        <interceptor-class>com.example.service.ExceptionInterceptor</interceptor-class>
    </interceptor-binding>
</assembly-descriptor>

As a general hint, in JSF, you can also have a global exception handler that adds only one faces message Starting with this kickoff example, you can do the following in the yourexceptionhandler#handle() method:

if (exception instanceof EntityAlreadyModifiedException) { // Unwrap if necessary.
    // Add FATAL faces message and return.
}
else {
    // Continue as usual.
}
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>