Anforderung: Alle Parameter in Methoden und Konstruktoren, die die Annotation @NotNull besitzen sollen geprüft werden. Wenn ein so markierter Parameter null ist, soll eine IllegalArgumentException ausgelöst werden.
Hier die Beispielimplementierung:
Als erstes die Annotation @NotNull für die zu prüfenden Parameter:
@Target({ ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) public @interface NotNull { String parameterName() default ""; }
Die Annotation @NotNull besitzt das Attribut parameterName. Hier kann der Name des Parameters übergeben werden. Dieser wird für die Fehlermeldung verwendet.
Dann benötigen wir einen Aspect, der alle Methoden und Konstruktoren mit der Annotation @NotNull "trifft".
Pointcut für alle Methoden mit der Annotation @NotNull: execution(* *(..,@NotNull (*),..))
Pointcut für alle Konstruktoren mit der Annotation @NotNull: execution(new(..,@NotNull (*),..))
@Aspect public class CheckArgumentsAspect { /** * Der Pointcut trifft auf alle Methoden in allen Packages zu, die * mindestens einen Parameter mit der Annotation {@link NotNull} besitzen. */ @Around("execution(* *(..,@NotNull (*),..))") public Object checkArgsForMethod(ProceedingJoinPoint joinPoint) throws Throwable { if (joinPoint.getSignature() instanceof MethodSignature) { MethodSignature methodSignature = (MethodSignature) joinPoint .getSignature(); Method method = methodSignature.getMethod(); Class<?>[] parameterTypes = method.getParameterTypes(); Annotation[][] parameterAnnotationArray = method .getParameterAnnotations(); System.out.println("Prüfe Parameter der Methode '" + methodSignature.toLongString() + "' mit den Parameterwerten '" + joinPoint.getArgs() + "'."); // Prüft alle Parameter checkParameter(joinPoint.getArgs(), parameterTypes, parameterAnnotationArray, methodSignature.toLongString()); } return joinPoint.proceed(); } /** * Der Pointcut trifft auf alle Konstruktoren zu, die mindestens einen * Parameter mit der Annotation {@link NotNull} besitzen. */ @Around("execution(new(..,@NotNull (*),..))") public Object checkArgsForConstructor(ProceedingJoinPoint joinPoint) throws Throwable { if (joinPoint.getSignature() instanceof ConstructorSignature) { ConstructorSignature constructorSignature = (ConstructorSignature) joinPoint.getSignature(); Constructor<?> constructor = constructorSignature.getConstructor(); Class<?>[] parameterTypes = constructor.getParameterTypes(); Annotation[][] parameterAnnotationArray = constructor .getParameterAnnotations(); System.out.println("Prüfe Parameter des Konstruktors '" + constructorSignature.toLongString() + "' mit den Parameterwerten '" + joinPoint.getArgs() + "'."); // Prüft alle Parameter checkParameter(joinPoint.getArgs(), parameterTypes, parameterAnnotationArray, constructorSignature.toLongString()); } return joinPoint.proceed(); } /** * Prüft alle Parameter. * * @param parameter * Alle Parameter. * @param parameterTypes * Die Typen zu den Parametern. * @param parameterAnnotationArray * Die Annotations zu den Parametern. * @param signature * Die Signatur der Methode oder des Konstruktors. */ private void checkParameter(Object[] parameter, Class<?>[] parameterTypes, Annotation[][] parameterAnnotationArray, String signature) { for (int i = 0; i < parameterTypes.length; i++) { Annotation[] parameterAnnotations = parameterAnnotationArray[i]; for (Annotation annotation : parameterAnnotations) { if (annotation instanceof NotNull) { // Hier wird das Argument auf null geprüft checkNotNull(parameter[i], parameterTypes[i], i, ((NotNull) annotation).parameterName(), signature); } } } } /** * Prüft den Parameter auf null. * * @param parameter * Der Parameter. * @param parameterType * Der Typ des Parameters. * @param parameterIndex * Der Index des Parameters. * @param parameterName * Der Name des Parameters. * @param signature * Die Signatur der Methode oder des Konstruktors. */ private void checkNotNull(Object parameter, Class<?> parameterType, int parameterIndex, String parameterName, String signature) { // Hier wird das Argument auf null geprüft if (parameter == null) { if (StringUtils.isBlank(parameterName)) { parameterName = "-"; } String longMsg = MessageFormat.format( "Fehler: Der {0}. Parameter (Name: {1}, Typ: {2}) von {3} " + "ist null.", parameterIndex + 1, parameterName, parameterType.getName(), signature); throw new IllegalArgumentException(longMsg); } } }
Eine Klasse mit zu prüfenden Parametern könnte zum Beispiel so aussehen:
public class TestClass { public TestClass() { super(); } public TestClass(@NotNull(parameterName = "kNotNull") Integer kNotNull) { super(); System.out.println(" kNotNull: " + kNotNull); } public void methodWithOneNotNullArg( @NotNull(parameterName = "aNotNull") Integer aNotNull) { System.out.println(" aNotNull: " + aNotNull); } public void methodWithOneNotNullArg(Long b, @NotNull(parameterName = "cNotNull") Integer cNotNull) { System.out.println(" b : " + b); System.out.println(" cNotNull: " + cNotNull); } public void methodWithTwoNotNullArg( @NotNull(parameterName = "dNotNull") Integer dNotNull, @NotNull Integer eNotNull) { System.out.println(" dNotNull: " + dNotNull); System.out.println(" eNotNull: " + eNotNull); } public void methodWithoutNotNullArg(Long f) { System.out.println(" f : " + f); } }
Jetzt sollten alle Parameter mit der Annotation @NotNull geprüft werden. Hier noch der passende JUnit-Test dazu:
public class TestClassTest { private TestClass testClass = new TestClass(); @Test public void testMethodWithOneNotNullArgInteger() { testClass.methodWithOneNotNullArg(1); } @Test public void testMethodWithOneNotNullArgIntegerNull() { try { testClass.methodWithOneNotNullArg(null); Assert.fail("Hier wurde eine IllegalArgumentException erwartet."); } catch (IllegalArgumentException e) { Assert.assertNotNull(e); System.err.println(" " + e.getMessage()); } } @Test public void testMethodWithOneNotNullArgIntegerInteger() { testClass.methodWithOneNotNullArg(11l, 11); } @Test public void testMethodWithOneNotNullArgIntegerIntegerNull1() { testClass.methodWithOneNotNullArg(null, 11); } @Test public void testMethodWithOneNotNullArgIntegerIntegerNull2() { try { testClass.methodWithOneNotNullArg(11l, null); Assert.fail("Hier wurde eine IllegalArgumentException erwartet."); } catch (IllegalArgumentException e) { Assert.assertNotNull(e); System.err.println(" " + e.getMessage()); } } @Test public void testMethodWithOneNotNullArgIntegerIntegerNullNull() { try { testClass.methodWithOneNotNullArg(null, null); Assert.fail("Hier wurde eine IllegalArgumentException erwartet."); } catch (IllegalArgumentException e) { Assert.assertNotNull(e); System.err.println(" " + e.getMessage()); } } @Test public void testMethodWithTwoNotNullArg() { testClass.methodWithTwoNotNullArg(111, 111); } @Test public void testMethodWithTwoNotNullArgNull1() { try { testClass.methodWithTwoNotNullArg(null, 222); Assert.fail("Hier wurde eine IllegalArgumentException erwartet."); } catch (IllegalArgumentException e) { Assert.assertNotNull(e); System.err.println(" " + e.getMessage()); } } @Test public void testMethodWithTwoNotNullArgNull2() { try { testClass.methodWithTwoNotNullArg(222, null); Assert.fail("Hier wurde eine IllegalArgumentException erwartet."); } catch (IllegalArgumentException e) { Assert.assertNotNull(e); System.err.println(" " + e.getMessage()); } } @Test public void testMethodWithTwoNotNullArgNullNull() { try { testClass.methodWithTwoNotNullArg(null, null); Assert.fail("Hier wurde eine IllegalArgumentException erwartet."); } catch (IllegalArgumentException e) { Assert.assertNotNull(e); System.err.println(" " + e.getMessage()); } } @Test public void testMethodWithoutNotNullArg() { testClass.methodWithoutNotNullArg(null); } @Test public void testMethodWithoutNotNullArgNull() { testClass.methodWithoutNotNullArg(null); } @Test public void testConstructorWithNotNullArg() { new TestClass(999); } @Test public void testConstructorWithNotNullArgNull() { try { new TestClass(null); Assert.fail("Hier wurde eine IllegalArgumentException erwartet."); } catch (IllegalArgumentException e) { Assert.assertNotNull(e); System.err.println(" " + e.getMessage()); } } }
Und jetzt oft @NotNull verwenden und weitere Annotations zum Prüfen von Argumenten erstellen!
Das Projekt befindet sich hier.