I finally settled on another solution, which enforces the validation of certain entities prior to persisting them but allows me to avoid validation in the entity's set methods themselves. Using this method, the business logic is still taken care of prior to reaching the interceptor, and I can perform more complicated validation/action than in the set methods, such as validation which relies on graphs of sub-objects or on the interrelationships of various properties.
This is done using the Validatable interface:
Code:
/**
Used by classes for which the user has to perform some action which sets them to
"valid" prior to saving.
*/
public interface Validatable {
/** check if the class is validated */
public boolean isValidated();
}
And the following Interceptor:
Code:
/**
An interceptor for checking that entities are validated before saving/updating.
*/
public class ValidatingInterceptor implements Interceptor, Serializable {
public ValidatingInterceptor () {}
public Object instantiate(Class clazz, Serializable id) {
return null;
}
public void onDelete(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types)
throws CallbackException
{
}
// called when the object is updated in the database
public boolean onFlushDirty(Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types)
throws CallbackException
{
if (entity instanceof Validatable) {
Validatable validatable = (Validatable) entity;
if (!validatable.isValidated())
throw new CallbackException
("Validatable entity has not been validated!");
}
return false;
}
public boolean onLoad(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types)
throws CallbackException
{
return false;
}
public boolean onSave(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types)
throws CallbackException
{
if (entity instanceof Validatable) {
Validatable validatable = (Validatable) entity;
if (!validatable.isValidated())
throw new CallbackException
("Validatable entity has not been validated!");
}
return false;
}
public void postFlush(Iterator entities)
throws CallbackException
{
}
public void preFlush(Iterator entities)
throws CallbackException
{
}
public Boolean isUnsaved(Object entity) { return null; }
public int[] findDirty(Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types)
{
return null;
}
}
Your entity then looks something like this:
Code:
public class Entity implements Validatable {
private boolean m_validated = false;
// ...
public void validate() throws MyException {
if (!m_validated) {
// ... perform validation and other actions
// (like sending messages in my case),
// and throw MyException if necessary
m_validated = true;
}
}
public boolean isValidated() {
return m_validated
}
}
Note that client is
forced to call the validate() method before committing the session (otherwise an exception is thrown).
Here are the caveats: when deleting an object, you first need to set it to validated, otherwise flushDirty will throw an error.
- Assaf