Reputation: 453
Is there an easy way to have Hibernate validate field length constraints in the set() methods for each property?
I want to prevent the fields from EVER containing invalid values instead of waiting for Exceptions to occur later.
I have a class with a Username property:
@Column(name = "username", length = 12)
public String getUsername()
{
return this.username;
}
public void setUsername(String username)
{
this.username = username;
}
I can modify my Hibernate templates to create the set() methods this way:
@Column(name = "username", length = 12)
public String getUsername()
{
return this.username;
}
public void setUsername(String username)
{
Method m = ClassWithUsername.getDeclaredMethod("setUsername");
javax.persistence.Column col = m.getAnnotation(javax.persistence.Column.class);
int maxLen = col.length();
// Validate the field length
if(username!=null && username.length() > maxLen)
throw Exception("Username must be no more than " + maxLen + " characters.");
this.username = username;
}
Before I do this, I am wondering if there is some other approaches.
Upvotes: 2
Views: 3068
Reputation: 14061
I'm not sure if my suggestion would be a "better" approach, but you asked for "some other approach" :-)
My first option would be to something like this:
public void setUsername(String username) {
User user = user.clone();
user.username = username;
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Car>> constraintViolations = validator.validateProperty(user, "username");
if (constraintViolations.size() == 0) {
this.username = username;
} else {
throw new IllegalArgumentException("Invalid username");
}
}
Of course, you can optimize your code by creating a helper class that holds a static reference to the validator, so that you don't need to create it at every setUsername call. Or you can even encapsulate this whole logic into the helper, so that you can pass only this on your setter (be careful with this approach, as the validator should not call the setter to change the username value):
public void setUsername(String username) {
MyValidatorHelper.validateOnSetter(this, username, "username");
this.username = username;
}
Note that, in this case, MyValidatorHelper would throw the exception, so, the second line would be executed only if the exception is not thrown.
Another option is to play with CDI Interceptors. I have not tested (like I have not tested the previous example), but I think you can encapsulate the above logic into a CDI Interceptor, and intercept the it with @AroundInvoke. This way, you can even "forget" to call the validator helper from inside your setters, having CDI invoke it for you. The disadvantage of this is that your entities would have to be CDI managed beans (they probably are, anyway) and that you'd have it enabled by default for all setters, which may or may not be a good idea.
Upvotes: 0
Reputation: 5946
How about using Bean Validation?? refer to http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/
The length attribute of the Column annotation is used to specify: The column length. (Applies only if a string-valued column is used.)
For example, you can define max length of stock_code column is 5, but in generated ddl, stock_code column is varchar(10). In this case, you can catch ConstraintViolationException in saving entity.
[If an entity is found to be invalid, the list of constraint violations is propagated by the ConstraintViolationException which exposes the set of ConstraintViolations. This exception is wrapped in a RollbackException when the violation happens at commit time. Otherwise the ConstraintViolationException is returned (for example when calling flush()]
Hopefully this meets your requirement.
in your entity class
@Column(name = "stock_code", unique = true, nullable = false, length = 10)
@Size(max = 5)
public String getStockCode() {
return this.stockCode;
}
public void setStockCode(String stockCode) {
this.stockCode = stockCode;
}
in your dao class
try {
session.beginTransaction();
Stock stock = new Stock();
stock.setStockCode("77777");
stock.setStockName("PADINI");
session.save(stock);
session.getTransaction().commit();
} catch (ConstraintViolationException e) {
session.getTransaction().rollback();
System.out.println("Violate Constraint..");
} catch (Exception e1) {
session.getTransaction().rollback();
System.out.println("Other Exception");
} finally {
session.close();
}
Upvotes: 1