2012-04-17 10 views
3

WebアプリケーションのサービスレイヤにJSR303 JavaBean検証を実装しました(this article)。今私は、すべての検証例外(例えば、javax.validation.ConstraintViolationException)を私のカスタム例外に変換したいと思います。JSR303 JavaBean検証例外をカスタム例外に変換する

私は例外がサービス層にスローされるたびに呼び出されるアスペクト作成:

@Aspect 
public class ExceptionConversionAspect { 

    @AfterThrowing(pointcut="execution(* com.myexample.service.*.*(..))", throwing="e") 
    public void convertServiceException(Exception e) { 

     if (e instanceof ConstraintViolationException) { 
      // this is my custom exception 
      throw new InvalidServiceInputException("The service inputs failed validation", e); 
     } 
    } 
} 

をしかし、私のサービスがConstraintViolationExceptionと検証が失敗したときに、私の例外変換態様はトリガーされません。これは、検証例外がそれ自体アスペクトによってトリガされるためです。

@Aspect 
public class ValidateAspect { 

    @Autowired 
    private Validator validator; 

    // Match any public methods in a class annotated with @AutoValidating 
    @Around("execution(public * *(..)) && @within(com.myexample.validator.annotation.Validate)") 
    public Object validateMethodInvocation(ProceedingJoinPoint pjp) throws Throwable { 

    // some code here 
    .... 
} 

正しい順序でアスペクトをチェーンするにはどうすればよいですか?最初にValidateAspect、その後にExceptionConversionAspectがありますか?

+0

多分それはvalidateMethodInvocationメソッドの側面を作成するのに役立つだろう - それは適切な例外をスローしていますので、それはそのメソッドによってスローされた例外によってトリガまたはValidateAspectを無効にすることでしょうか? –

答えて

0

複数のアスペクトが共通のジョインポイントを共有する場合は、@DeclarePrecedenceステートメントを使用して手動で実行順序を設定できます。あなたのケースでは、あなたが新たな一面を作成することができます。何の優先順位が指定されていない場合

@Aspect 
@DeclarePrecedence("ValidateAspect, ExceptionConversionAspect") 
    public class SystemArchitecture { 
     // ... 
    } 

、ルールへの実行順序のデフォルトはhere

0

を定義したラウル・ベルトーネはほとんど右ではなく、かなり。ロジックを反転し、ExceptionConversionAspectを優先する必要があります。

のJava SEのための完全に動作するサンプル(私はただのJava EE例外をエミュレートする):

ヘルパークラス:

package javax.validation; 

public class ConstraintViolationException extends RuntimeException { 
    private static final long serialVersionUID = -8041265519275356912L; 

    public ConstraintViolationException(String arg0) { 
     super(arg0); 
    } 
} 
package com.myexample.validator.annotation; 

import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 

@Retention(RetentionPolicy.RUNTIME) 
public @interface Validate {} 
package com.myexample.service; 

public class InvalidServiceInputException extends RuntimeException { 
    public InvalidServiceInputException(String arg0, Throwable arg1) { 
     super(arg0, arg1); 
    } 
} 

サンプル・ドライバアプリケーション:

ドライバアプリケーションに@Validateという注釈が付けられ、サービスをエミュレートします。パッケージ名を参照してください。これは10個のメソッド呼び出しをループし、例外をキャッチして標準出力に出力し、実際に必要に応じて変換されたことを示します。

package com.myexample.service; 

import com.myexample.validator.annotation.Validate; 

@Validate 
public class Application { 
    public void doSomething(int i) { 
     System.out.printf("Doing something #%d%n", i); 
    } 

    public static void main(String[] args) { 
     Application application = new Application(); 
     for (int i = 0; i < 10; i++) { 
      try { 
       application.doSomething(i + 1); 
      } 
      catch (Exception e) { 
       System.out.println(e); 
       System.out.println(" cause: " + e.getCause()); 
      } 
     } 
    } 
} 

態様:

検証態様は、ランダムにデモ目的のためにConstraintViolationExceptionをスロー。

package com.myexample.aspect; 

import java.util.Random; 
import javax.validation.ConstraintViolationException; 
import org.aspectj.lang.ProceedingJoinPoint; 
import org.aspectj.lang.annotation.Around; 
import org.aspectj.lang.annotation.Aspect; 

@Aspect 
public class ValidateAspect { 
    private static final Random RANDOM = new Random(); 

    @Around("execution(public !static * *(..)) && @within(com.myexample.validator.annotation.Validate)") 
    public Object validateMethodInvocation(ProceedingJoinPoint thisJoinPoint) throws Throwable { 
     Object result = thisJoinPoint.proceed(); 
     if (RANDOM.nextBoolean()) 
      throw new ConstraintViolationException("uh-oh"); 
     return result; 
    } 
} 

例外変換のアスペクトには、追加の@DeclarePrecedenceアノテーションが追加されました。

package com.myexample.aspect; 

import javax.validation.ConstraintViolationException; 
import org.aspectj.lang.annotation.AfterThrowing; 
import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.DeclarePrecedence; 
import com.myexample.service.InvalidServiceInputException; 

@Aspect 
@DeclarePrecedence("ExceptionConversionAspect, *") 
public class ExceptionConversionAspect { 
    @AfterThrowing(pointcut = "execution(* com.myexample.service..*(..))", throwing = "e") 
    public void convertServiceException(Exception e) { 
     if (e instanceof ConstraintViolationException) { 
      throw new InvalidServiceInputException("The service inputs failed validation", e); 
     } 
    } 
} 

コンソール出力:

Doing something #1 
Doing something #2 
com.myexample.service.InvalidServiceInputException: The service inputs failed validation 
    cause: javax.validation.ConstraintViolationException: uh-oh 
Doing something #3 
com.myexample.service.InvalidServiceInputException: The service inputs failed validation 
    cause: javax.validation.ConstraintViolationException: uh-oh 
Doing something #4 
Doing something #5 
Doing something #6 
com.myexample.service.InvalidServiceInputException: The service inputs failed validation 
    cause: javax.validation.ConstraintViolationException: uh-oh 
Doing something #7 
Doing something #8 
Doing something #9 
Doing something #10