LoginSignup
3
1

More than 5 years have passed since last update.

OVal(アノテーションベースのバリデーションFW)のコード例

Last updated at Posted at 2018-01-22

OValというアノテーションベースのアノテーションによる入力制限を付けれるバリデーションFWを使ってみました。
そのときのコード例をメモします。

依存関係

pom.xml
<!-- https://mvnrepository.com/artifact/net.sf.oval/oval -->
<dependency>
    <groupId>net.sf.oval</groupId>
    <artifactId>oval</artifactId>
    <version>1.90</version>
</dependency>
build.gradle
// https://mvnrepository.com/artifact/net.sf.oval/oval
compile group: 'net.sf.oval', name: 'oval', version: '1.90'

Springで使う場合

net.sf.oval.integration.spring.SpringValidator
org.springframework.validation.Validatorを実装しているらしいです。
まだ使っていないので、使ってみたらまたレポートします。

基本的なコードの例

ビーンクラス
public class SampleBean{
    /** ID */
    @Assert(expr = "null!=_value&&''!=_value", lang = "js"
//lang = は"bsh" / "beanshell", "groovy", or "js" / "javascript".のどれか好きなの選んで使ってね
//この程度だったら@NotEmpty使えばよかったかも…
            ,message="IDが入力されてないです")
    private String id;

    /** No */
    private Integer no;

    /** 登録日 */
    @Assert(expr = "null!=_value&&''!=_value", lang = "js"
            ,message="登録日が入力されてないです")
    @MatchPattern(pattern=DateUtil.DATE_MATCH_PATTERN
            ,message="登録日の形式がおかしいです"
            ,when="js:null!=_value&&''!=_value")
    @DateRange(format=DateUtil.DATE_HH_MM_FORMAT,message="登録日の日付範囲がおかしいです")
    @ValidateWithMethod(methodName="isValidDate", parameterType=String.class)
            ,message="12月の日付を入力してください")
    private String abcTime;

    //getter,setter省略

    private boolean isValidDate(String arg){//12月だけtrue返すよ
        if(arg.matches("\d{4}/12/.*")){
            return true;
        }else{
            return false;
        }
    }
}
バリデートの仕方
net.sf.oval.Validator validator = new net.sf.oval.Validator();
List<ConstraintViolation> clist =  validator.validate( validatedObject );

staticメソッドでバリデーションしたい

という場合は標準機能にはないので、バリデートのアノテーションとチェックメソッドを自作します。
java8で書いたほうがスマートなんですが、java7の環境しか使わせてもらえないので(T-T)、java7のコードです。

ValidateWithStaticMethod.java(アノテーション)
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import net.sf.oval.ConstraintTarget;
import net.sf.oval.ConstraintViolation;
import net.sf.oval.configuration.annotation.Constraint;
import net.sf.oval.configuration.annotation.Constraints;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE })
@Constraint(checkWith = ValidateWithStaticMethodCheck.class)
public @interface ValidateWithStaticMethod {
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE })
    @Constraints
    public @interface List {
        ValidateWithStaticMethod[] value();
        String when() default "";
    }

    ConstraintTarget[] appliesTo() default ConstraintTarget.CONTAINER;

    String errorCode() default "net.sf.oval.constraint.ValidateWithMethod";

    boolean ignoreIfNull() default true;

    boolean ignoreIfNullOrEmpty() default true;

    String message() default "メッセージが定義されていません(ValidateWithStaticMethod)";

    Class<?> clazz();

    String methodName();

    String[] profiles() default {};

    int severity() default 0;

    String target() default "";

    String when() default "";
}
ValidateWithStaticMethodCheck.java(チェックロジック)

import static net.sf.oval.Validator.*;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import net.sf.oval.ConstraintTarget;
import net.sf.oval.Validator;
import net.sf.oval.configuration.annotation.AbstractAnnotationCheck;
import net.sf.oval.context.OValContext;
import net.sf.oval.exception.ReflectionException;

/**
 * Staticメソッドによるチェック
 */
public class ValidateWithStaticMethodCheck extends AbstractAnnotationCheck<ValidateWithStaticMethod> {
    private static final long serialVersionUID = 1L;

    private final Map<Class<?>, Method> validationMethodsByClass = new WeakHashMap<Class<?>, Method>();

    private boolean ignoreIfNull;
    private boolean ignoreIfNullOrEmpty;
    private Class<?> clazz;
    private String methodName;

    @Override
    public void configure(final ValidateWithStaticMethod constraintAnnotation) {
        super.configure(constraintAnnotation);
        setMethodName(constraintAnnotation.methodName());
        setClazz(constraintAnnotation.clazz());
        setIgnoreIfNull(constraintAnnotation.ignoreIfNull());
        setIgnoreIfNullOrEmpty(constraintAnnotation.ignoreIfNullOrEmpty());
    }

    @Override
    protected Map<String, String> createMessageVariables() {
        final Map<String, String> messageVariables = getCollectionFactory().createMap(4);
        messageVariables.put("ignoreIfNull", Boolean.toString(ignoreIfNull));
        messageVariables.put("ignoreIfNullOrEmpty", Boolean.toString(ignoreIfNullOrEmpty));
        messageVariables.put("methodName", methodName);
        return messageVariables;
    }

    @Override
    protected ConstraintTarget[] getAppliesToDefault() {
        return new ConstraintTarget[] { ConstraintTarget.VALUES };
    }

    public String getMethodName() {
        return methodName;
    }

    public boolean isIgnoreIfNull() {
        return ignoreIfNull;
    }

    public boolean isSatisfied(final Object validatedObject, final Object valueToValidate, final OValContext context, final Validator validator)
            throws ReflectionException {
        if (valueToValidate == null && ignoreIfNull)
            return true;
        if(ignoreIfNullOrEmpty){
            if (valueToValidate == null)
                return true;
            //emptyの判定条件を追加したい場合、ここに追記してください
            if ( valueToValidate instanceof String && "".equals(valueToValidate) )
                return true;
            if ( valueToValidate instanceof Object[] && 0==((Object[])valueToValidate).length )
                return true;
            if ( valueToValidate instanceof List && 0==((List<?>)valueToValidate).size() )
                return true;
        }
        boolean result;
        Method method;
        try {
            Class<?> parameterType = valueToValidate.getClass();
            method =  clazz.getMethod(methodName, parameterType);
            result = (boolean)method.invoke(null, valueToValidate);
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            throw new ReflectionException( e );
        }
        return result;
    }

    public void setIgnoreIfNull(final boolean ignoreIfNull) {
        this.ignoreIfNull = ignoreIfNull;
        requireMessageVariablesRecreation();
    }


    public void setIgnoreIfNullOrEmpty(final boolean ignoreIfNullOrEmpty) {
        this.ignoreIfNullOrEmpty = ignoreIfNullOrEmpty;
        requireMessageVariablesRecreation();
    }

    public Class<?> getClazz() {
        return clazz;
    }

    public void setClazz(Class<?> clazz) {
        this.clazz = clazz;
    }

    public void setMethodName(final String methodName) {
        this.methodName = methodName;
        synchronized (validationMethodsByClass) {
            validationMethodsByClass.clear();
        }
        requireMessageVariablesRecreation();
    }

}
アノテーションの付け方
//ValidationMethods.isFormatTelNo(String str)を使う場合のコード例
@ValidateWithStaticMethod(clazz=ValidationMethods.class
        ,methodName="isFormatTelNo"
        ,message="電話番号がおかしいです。。。")
private String telNo;

同じアノテーション複数つけたい

こう書けばいいみたいです。

@ValidateWithStaticMethod.List(value={
        @ValidateWithStaticMethod(clazz=ValidationMethods.class
                ,methodName="isFormatTelNo"
                ,message="電話番号の形式がおかしいです"),
        @ValidateWithStaticMethod(clazz=ValidationMethods.class
                ,methodName="isOkTelNumberSize"
                ,message="電話番号の桁数がおかしいです")
})
private String telNo;

標準で提供されているアノテーション一覧

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1