class A {
private String someField;
#validation
private String annotatedField;
}
I'm implementing a custom constraint validation annotation #validation to validate annotatedField. I need to know the value of someField to satisfy the logic of my validation.
Validator implements ConstraintValidator<validation, String>{
#Override
public void initialize(validation constraintAnnotation) {
}
#Override
public boolean isValid(String annotatedField, ConstraintValidatorContext context) {
if (StringUtils.isBlank(annotatedField)) {
return true;
}
String someField; // get some someField value given the annotatedField
}
}
Is there a way to do this using reflection?
This turns out to be not possible.
A class-level constraint annotation would be recommended to address this problem.
Related
I'm currently studying building API's with Spring. I'm working with Spring Validator to validate my input. Here it is my custom validator:
public class NewHoldValidator implements Validator {
private EntityManager manager;
public NewHoldValidator(EntityManager manager) {
this.manager = manager;
}
#Override
public boolean supports(Class<?> clazz) {
return NewHoldRequest.class.isAssignableFrom(clazz);
}
#Override
public void validate(Object target, Errors errors) {
if (errors.hasErrors()) {
return;
}
NewHoldRequest request = (NewHoldRequest) target;
Patron patron = manager.find(Patron.class, request.patronId);
BookInstance bookInstance = manager.find(BookInstance.class, request.bookInstanceId);
Assert.state(patron != null, "Patron does not exists.");
Assert.state(bookInstance != null, "Book instance does not exists.");
if (!bookInstance.acceptToBeHoldTo(patron)) {
errors.reject(null, "This book instance cannot be hold to this patron");
}
if (!request.hasDaysHold()) {
if (!patron.researcher()) {
errors.rejectValue("daysHold", null, "You need to pass a daysHold attribute");
}
}
}
}
And here is my NewHoldRequest class:
public class NewHoldRequest {
#NotNull
public final Long patronId;
#NotNull
public final Long bookInstanceId;
#Positive
#Max(60)
public final Integer daysHold;
public NewHoldRequest(#NotNull Long patronId, #NotNull Long bookInstanceId, #Positive #Max(60) Integer daysHold) {
this.patronId = patronId;
this.bookInstanceId = bookInstanceId;
this.daysHold = daysHold;
}
#Override
public String toString() {
return "NewHoldRequest{" + "patronId=" + patronId + ", bookId=" + bookInstanceId + ", daysHold=" + daysHold + '}';
}
public boolean hasDaysHold() {
return this.daysHold != null;
}
Even if my field "daysHold" is public I still need to create a getter to it so Spring can show the rejected error properly, otherwise, it will throw a NotReadablePropertyException. Is there a way to define that Spring can reject public fields without getters or I will need to add accessor methods to all fields I want to reject?
Here is the message that shows up when my validation is triggered.
org.springframework.beans.NotReadablePropertyException: Invalid property 'daysHold' of bean class [com.api.library.usecases.newhold.NewHoldRequest]: Bean property 'daysHold' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
I'll advise you to use the interface ConstraintValidator. It's a generic's interface, without casting and other problems.
You should create a custom constraint annotation for you it's #NewHoldValid after that implement CustomValidator interface:
#Component
public class NewHoldValidator implements ConstraintValidator<NewHoldValid, NewHoldRequest> {
#Override
public boolean isValid(NewHoldRequest value, ConstraintValidatorContext context) {
if(ANY_CONDITION){
return true;
}else {
return false;
}
}
After that use #NewHoldValid annotation above your NewHoldRequest.
If you'll want to set an error message text which different from default use that:
context.buildConstraintViolationWithTemplate("Your error message").addConstraintViolation();
I have an abstract class named Company with some properties. Two different types of classes created by extending this abstract class. I have to add a custom validation in the abstract class. When the request came, I have to identify the type of the class. I have used 'instance of' for checking the type but it not working as expected. How do I check that ?
#UniqueCode(columnName = "companyCode")
public abstract class Company {
private String companyCode;
private String companyName;
// some other code
}
public class PsiCompany extends Company {
private Long id;
}
public class IndentAgent extends Company {
private Long id;
private String cbRegNo;
}
public class UniqueCodeValidator implements ConstraintValidator<UniqueCode, Object> {
#Override
public void initialize(UniqueCode constraintAnnotation) {}
#Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
/*
* How do I know the class type from object ?
*/
}
}
Whenever I sent IndentAgent object it works fine but if I sent PsiCompany object it also goes in IndentAgent code blocks. How can I identify the class type from the object in isValid() method ?
This works :
#Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
if (value instanceof PsiCompany) {
System.out.println("PsiCompany");
// do your thing
} else if (value instanceof IndentAgent) {
System.out.println("IndentAgent");
// do your other thing
}
// return bool
}
I need to build a process which will validate a record against ~200 validation rules. A record can be one of ~10 types. There is some segmentation from validation rules to record types but there exists a lot of overlap which prevents me from cleanly binning the validation rules.
During my design I'm considering a chain of responsibility pattern for all of the validation rules. Is this a good idea or is there a better design pattern?
Validation is frequently a Composite pattern. When you break it down, you want to seperate the what you want to from the how you want to do it, you get:
If foo is valid
then do something.
Here we have the abstraction is valid -- Caveat: This code was lifted from currrent, similar examples so you may find missing symbology and such. But this is so you get the picture. In addition, the
Result
Object contains messaging about the failure as well as a simple status (true/false).
This allow you the option of just asking "did it pass?" vs. "If it failed, tell me why"
QuickCollection
and
QuickMap
Are convenience classes for taking any class and quickly turning them into those respected types by merely assigning to a delegate. For this example it means your composite validator is already a collection and can be iterated, for example.
You had a secondary problem in your question: "cleanly binding" as in, "Type A" -> rules{a,b,c}" and "Type B" -> rules{c,e,z}"
This is easily managed with a Map. Not entirely a Command pattern but close
Map<Type,Validator> typeValidators = new HashMap<>();
Setup the validator for each type then create a mapping between types. This is really best done as bean config if you're using Java but Definitely use dependency injection
public interface Validator<T>{
public Result validate(T value);
public static interface Result {
public static final Result OK = new Result() {
#Override
public String getMessage() {
return "OK";
}
#Override
public String toString() {
return "OK";
}
#Override
public boolean isOk() {
return true;
}
};
public boolean isOk();
public String getMessage();
}
}
Now some simple implementations to show the point:
public class MinLengthValidator implements Validator<String> {
private final SimpleResult FAILED;
private Integer minLength;
public MinLengthValidator() {
this(8);
}
public MinLengthValidator(Integer minLength) {
this.minLength = minLength;
FAILED = new SimpleResult("Password must be at least "+minLength+" characters",false);
}
#Override
public Result validate(String newPassword) {
return newPassword.length() >= minLength ? Result.OK : FAILED;
}
#Override
public String toString() {
return this.getClass().getSimpleName();
}
}
Here is another we will combine with
public class NotCurrentValidator implements Validator<String> {
#Autowired
#Qualifier("userPasswordEncoder")
private PasswordEncoder encoder;
private static final SimpleResult FAILED = new SimpleResult("Password cannot be your current password",false);
#Override
public Result validate(String newPassword) {
boolean passed = !encoder.matches(newPassword,user.getPassword());
return (passed ? Result.OK : FAILED);
}
#Override
public String toString() {
return this.getClass().getSimpleName();
}
}
Now here is a composite:
public class CompositePasswordRule extends QuickCollection<Validator> implements Validator<String> {
public CompositeValidator(Collection<Validator> rules) {
super.delegate = rules;
}
public CompositeValidator(Validator<?>... rules) {
super.delegate = Arrays.asList(rules);
}
#Override
public CompositeResult validate(String newPassword) {
CompositeResult result = new CompositeResult(super.delegate.size());
for(Validator rule : super.delegate){
Result temp = rule.validate(newPassword);
if(!temp.isOk())
result.put(rule,temp);
}
return result;
}
public static class CompositeResult extends QuickMap<Validator,Result> implements Result {
private Integer appliedCount;
private CompositeResult(Integer appliedCount) {
super.delegate = VdcCollections.delimitedMap(new HashMap<PasswordRule, Result>(), "-->",", ");
this.appliedCount = appliedCount;
}
#Override
public String getMessage() {
return super.delegate.toString();
}
#Override
public String toString() {
return super.delegate.toString();
}
#Override
public boolean isOk() {
boolean isOk = true;
for (Result r : delegate.values()) {
isOk = r.isOk();
if(!isOk)
break;
}
return isOk;
}
public Integer failCount() {
return this.size();
}
public Integer passCount() {
return appliedCount - this.size();
}
}
}
and now a snippet of use:
private Validator<String> pwRule = new CompositeValidator<String>(new MinLengthValidator(),new NotCurrentValidator());
Validator.Result result = pwRule.validate(newPassword);
if(!result.isOk())
throw new PasswordConstraintException("%s", result.getMessage());
user.obsoleteCurrentPassword();
user.setPassword(passwordEncoder.encode(newPassword));
user.setPwExpDate(DateTime.now().plusDays(passwordDaysToLive).toDate());
userDao.updateUser(user);
Chain of responsibility implies that there is an order in which the validations must take place. I would probably use something similar to the Strategy pattern where you have a Set of validation strategies that are applied to a specific type of record. You could then use a factory to examine the record and apply the correct set of validations.
What is the best way to trim this string/where is the best place to put the trim code?
Say I have the following textfield in my jsp:
<s:textfield label="First Name" name="person.firstname"/>
The action class:
public class BaseAction extends ActionSupport implements ServletRequestAware, SessionAware {
private Person person;
// Getters, setters and action logic
}
The bean:
public class Person implements Serializable {
private String lastname;
private String firstname;
// Getters and setters
}
I can change the default setting in the bean but this seems like a hack:
public void setFirstname(String firstname) {
this.firstname = firstname.trim();
}
EDIT: I did also see this question: struts2 trim all string obtained from forms where it's also suggested by some that the "correct" method is to use an interceptor.
Why is an interceptor the "correct" way? What is so wrong about changing the bean's setters?
It can be done with Struts2 converters.
public class TrimmingStringConverter extends StrutsTypeConverter {
public Object convertFromString(Map ctx, String[] values, Class arg2) {
if (values != null && values.length > 0) {
return values[0].trim();
}
return null;
}
public String convertToString(Map ctx, Object o) {
if (o != null) {
return o.toString();
}
else {
return null;
}
}
public Object convertValue(Map context, Object o, Class toClass)
{
if (o == null) {
return null;
} else if (toClass == java.lang.String.class) {
if (o instanceof String[]) {
String[] os = (String[]) o;
if (os.length > 0) {
return os[0].trim();
}
}
return o.toString().trim();
}
return super.convertValue(context, o, toClass);
}
}
It must be registered in xwork-conversion.properties:
java.lang.String=es.jogaco.webapp.TrimmingStringConverter
This will be applied to all user input.
It will work if you have the default struts2 interceptors. Quoted from struts2 doc:
By default, the conversion interceptor is included in struts-default.xml in the default stack
Plus I have it working in my struts2 app.
Short answer is Not by default, there is no build in mechanism to do this and you either need to do it in your action class or some-kind of java-script will do that for you.
Other possible way is to create an interceptor to do this with option to excludes or something like on similar trek.
I believe Interceptor is a good way to do this,its better to have such interceptor comes with S2.
I have a db table with column of datatype char(20). I'm not allowed to change it to a varchar.
I'm writing a JPA entity mapped to this table. I would like the string field representing this column in my entity class to always contain the trimmed value, not the 20-character value padded with spaces that exists in the db.
I can't see any easy way to do this. (an annotation would rock!). At the moment I'm just returning a trimmed value from my getter(), but this feels like a kludge.
A google search is offering no help on this. Any ideas?
Or you can use lifecycle annotations:
#Entity
public class MyEntity {
#PostLoad
protected void repair(){
if(myStringProperty!=null)myStringProperty=myStringProperty.trim();
}
private String myStringProperty;
public String getMyStringProperty() {
return myStringProperty;
}
public void setMyStringProperty(String myStringProperty) {
this.myStringProperty = myStringProperty;
}
}
If this occurs on multiple entities you can create a custom annotation and write a dedicated EntityListener.
Annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface Trim {}
Listener
public class TrimListener {
private final Map<Class<?>, Set<Field>> trimProperties =
new HashMap<Class<?>, Set<Field>>();
#PostLoad
public void repairAfterLoad(final Object entity) throws Exception {
for (final Field fieldToTrim : getTrimProperties(entity.getClass())) {
final String propertyValue = (String) fieldToTrim.get(entity);
if (propertyValue != null)
fieldToTrim.set(entity, propertyValue.trim());
}
}
private Set<Field> getTrimProperties(Class<?> entityClass) throws Exception {
if (Object.class.equals(entityClass))
return Collections.emptySet();
Set<Field> propertiesToTrim = trimProperties.get(entityClass);
if (propertiesToTrim == null) {
propertiesToTrim = new HashSet<Field>();
for (final Field field : entityClass.getDeclaredFields()) {
if (field.getType().equals(String.class)
&& field.getAnnotation(Trim.class) != null) {
field.setAccessible(true);
propertiesToTrim.add(field);
}
}
trimProperties.put(entityClass, propertiesToTrim);
}
return propertiesToTrim;
}
}
Now annotate all relevant String fields with #Trim and register the Listener as default entity listener in your persistence.xml:
<persistence-unit ..>
<!-- ... -->
<default-entity-listeners>
com.somepackage.TrimListener
and.maybe.SomeOtherListener
</default-entity-listeners>
</persistence-unit>
The accepted answer (using JPA entity listeners / #Trim annotation) is a dangerous one. Calling the setter on the retrieved entity appears to mark the entity as dirty. When I tried this myself at a root entity level (using Spring3 / hibernate), it triggered tons of extraneous updates to related entities that were otherwise not modified during the transaction. It was a real mess in production, and tracking it down to this being the cause took time.
In the end I opted to go with the more straightforward approach of trimming each of the fields manually on-demand (in a custom entity-to-domain mapper, or in the entity getter) similar to Edwin's answer.
It's an old question but it was very useful for me to get to my answer. In my case, the easiest way was to create a simple "javax.persistence.Converter", like this:
#Converter
public class StringTrimConverter implements AttributeConverter<String, String> {
#Override
public String convertToDatabaseColumn(String attribute) {
return attribute;
}
#Override
public String convertToEntityAttribute(String dbData) {
return dbData.trim();
}
}
And you can use it like this:
#Entity
#Table(name = "ViewAddress")
public class PostalAddress extends DbObject {
#Convert(converter = StringTrimConverter.class)
private String street;
#Convert(converter = StringTrimConverter.class)
private String number;
(...)
It works just fine.
Put the annotation on the getter method, set the #Acesss to AccessType.Property and trim the field there using String.trim() method.
Or simply put the trim in the getter method and always access the field through it. It is not going to get any simpler than that.
If you do not mind using pure Hibernate and deviating from the JPA standard you can use Hibernate #ColumnTransformer provided that you have a database function to do the work of
You can find how to do it in the Hibernate reference:
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#mapping-column-read-and-write
I hope that helps!
I am using this method, which makes the trimming transparent without having to use annotations in every string field.
In the same package that you have your session factory class (the one you use to get Sessions, e.g org.blablabla.yourpackage.etc.SessionGetter.getSession(), you must create a file named package-info.java and put this content inside it:
#TypeDefs({
#TypeDef(name = "trimmedStringType",
defaultForType = String.class,
typeClass = StringUserType.class)
})
package org.blablabla.yourpackage.etc;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;
Then you create the class StringUserType in this same package:
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.usertype.EnhancedUserType;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
public class StringUserType implements EnhancedUserType, Serializable {
private static final int[] SQL_TYPES = new int[]{Types.VARCHAR};
#Override
public int[] sqlTypes() {
return SQL_TYPES;
}
#Override
public Class returnedClass() {
return String.class;
}
#Override
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) {
return true;
}
if (x == null || y == null) {
return false;
}
String dtx = (String) x;
String dty = (String) y;
return dtx.equals(dty);
}
#Override
public int hashCode(Object object) throws HibernateException {
return object.hashCode();
}
#Override
public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
Object s = StandardBasicTypes.STRING.nullSafeGet(resultSet, names, session, owner);
if (s == null) {
return null;
}
return s.toString().trim();
}
#Override
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index, SessionImplementor session)
throws HibernateException, SQLException {
if (value == null) {
StandardBasicTypes.STRING.nullSafeSet(preparedStatement, null, index, session);
} else {
StandardBasicTypes.STRING.nullSafeSet(preparedStatement, value.toString().trim(), index, session);
}
}
#Override
public Object deepCopy(Object value) throws HibernateException {
return value;
}
#Override
public boolean isMutable() {
return false;
}
#Override
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
#Override
public Object assemble(Serializable cached, Object value) throws HibernateException {
return cached;
}
#Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
#Override
public String objectToSQLString(Object object) {
throw new UnsupportedOperationException();
}
#Override
public String toXMLString(Object object) {
return object.toString();
}
#Override
public Object fromXMLString(String string) {
return string;
}
}
And that's it, no need to create custom annotations in your beans, it will "magically" trim the strings whenever you get the objects from the database.
What JPA provider are you using?
If you are using EclipseLink CHAR fields are trimmed by default. You can disable this through the session trimStrings property (ensure you have not set this).
Accepted answer works except registering the listener in persistence.xml. I did it with orm.xml.
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
http://xmlns.jcp.org/xml/ns/persistence/orm_2_1.xsd"
version="2.1">
<persistence-unit-metadata>
<persistence-unit-defaults>
<entity-listeners>
<entity-listener class="org.example.TrimListener">
</entity-listener>
</entity-listeners>
</persistence-unit-defaults>
</persistence-unit-metadata>
</entity-mappings>
All you have to do is put this on your controller and it works as expected you dont need a listener or anything of that
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}
If your domain requirement states it needs trimmed information, you need to store the data in trimmed value. I see nothing wrong about it.
Domain Model
An object model of the
domain that incorporates both behavior
and data. (PEAA - Martin Fowler)
If you explicitly have to enforce the business rule at the database level, one option is that you have a choice of writing a trigger, you can use built-in SQL trim method. But it will be like using a rocket to crack an egg.