openxava / documentation / Lesson 20: Validation on remove

Course: 1. Getting started | 2. Basic domain model (1) | 3. Basic domain model (2) | 4. Refining the user interface | 5. Agile development6. Mapped superclass inheritance | 7. Entity inheritance | 8. View inheritance | 9. Java properties | 10. Calculated properties | 11. @DefaultValueCalculator in collections | 12. @Calculation and collections totals | 13. @DefaultValueCalculator from file | 14. Manual schema evolution | 15. Multi user default value calculation | 16. Synchronize persistent and computed propierties | 17. Logic from database | 18. Validating with @EntityValidator 19. Validation alternatives  | 20. Validation on remove 21. Custom Bean Validation annotation  | 22. REST service call from validation  | 23. Attributes in annotations  | 24. Refining the standard behavior | 25. Behavior & business logic | 26. References & collections | A. Architecture & philosophy | B. Java Persistence API | C. Annotations | D. Automated testing

Table of contents

Lesson 20: Validation on remove
Validating on removal with @RemoveValidator
Validating on removal with a JPA callback method
What's the best way of validating?
Summary
In the last lesson we looked at validation alternatives to perform on save. In this lesson we are going to look at validation on remove.
If you don't like videos follow the instructions below.

Validating on removal with @RemoveValidator

The validations we have seen until now are processed when the entity is modified, but sometimes it's useful or it's required to process the validation before the removal of the entity, and to use the validation to cancel the entity removal.
We are going to modify the application to reject the removal of an order if it has an invoice associated. To achieve this annotate your Order entity with @RemoveValidator, as show in following code:
@RemoveValidator(com.yourcompany.invoicing.validators.OrderRemoveValidator.class) // The class with the validation
public class Order extends CommercialDocument {
Now, before removing an order the logic in OrderRemoveValidator is executed, and if validation fails the order is not removed. Let's look at the code for the validator:
package com.yourcompany.invoicing.validators; // In 'validators' package

import com.yourcompany.invoicing.model.*;
import org.openxava.util.*;
import org.openxava.validators.*;
 
public class OrderRemoveValidator
    implements IRemoveValidator { // Must implement IRemoveValidator
 
    private Order order;
 
    public void setEntity(Object entity) // The entity to remove will be injected
        throws Exception // with this method before validating
    {
        this.order = (Order) entity;
    }
 
    public void validate(Messages errors) // The validation logic
        throws Exception
    {
        if (order.getInvoice() != null) {
            // By adding messages to errors the validation
            // will fail and the removal will be aborted
            errors.add("cannot_delete_order_with_invoice");
        }
    }
}
The validation logic is in the validate() method. Before calling the entity to be validated, it is injected using setEntity(). If messages are added to the errors object the validation will fail and the entity will not be removed. You have to add the error message in the invoicing/src/main/resources/i18n/invoicing-messages_en.properties file:
cannot_delete_order_with_invoice=An order with an invoice cannot be deleted
If you try to remove an order with an associated invoice now, you will get an error message and the removal will be rejected.
You can see that using a @RemoveValidator is not difficult but verbose. You have to write a full new class to add a simple if. Let's examine a briefer alternative.

Validating on removal with a JPA callback method

We're going to try another, maybe simpler, way to do this removal validation just by moving the validation logic from the validator class to the Order entity itself, in this case in a @PreRemove method.
First, remove the OrderRemoveValidator class from your project. Also remove the @RemoveValidator annotation from your Order entity:
//@RemoveValidator(com.yourcompany.invoicing.validators.OrderRemoveValidator.class) // Remove the @RemoveValidator
public class Order extends CommercialDocument {
We have just removed the validation. Let's add the functionality again, but now inside the Order class itself. Add the validateOnRemove() method in your Order class:
@PreRemove // Just before removing the entity
private void validateOnRemove() {
    if (invoice != null) { // The validation logic
        throw new javax.validation.ValidationException( // Throws a runtime exception
            XavaResources.getString( // To get the text message
                "cannot_delete_order_with_invoice"));
    }
}
This validation will be processed before the removal of an order. If it fails a ValidationException is thrown. You can throw any runtime exception in order to abort the removal. You have done the validation with a single method inside the entity.

What's the best way of validating?

You have learned several ways to do validations in your model classes. Which of them is the best one? All of them are valid options. It depends on your circumstances and personal preferences. If you have a validation that is non-trivial and reusable across your application, then to use @EntityValidator and @RemoveValidator is a good option. On the other hand, if you want to use your model classes from outside OpenXava and without JPA, then the use of validation in setters is better.
In our example we'll use the @AssertTrue for the “delivered to be in invoice” validation and @PreRemove for the removal validation, because this is the simplest procedure.

Summary

In this lesson you have learned several ways to do validation in an OpenXava application. In the next lesson you are going to learn how to create your own custom bean validation.This can actually be very useful! 

Download source code of this lesson

Any problem with this lesson? Ask in the forum Everything fine?  Go to lesson 21