Pregunta

Estoy usando SuppectJ para la aplicación de políticas en todo el proyecto.

Una cosa que estoy tratando de implementar ahora es que no debería haber lógica en ningún método de setter, excepto la validación simple con la guayaba. Preconditions.check* métodos.

public pointcut withinSetter() :
    withincode(public void set*(*));
public pointcut inputValidation() :
    call(public void Preconditions.check*(*));
public pointcut setFieldValue() : set(* *);
public pointcut entity() : within(com.mycompany.BaseEntity+);

declare warning :
entity() && withinSetter() && !setFieldValue() && !inputValidation():
"Please don't use Logic in Setters";

Esto funciona como se esperaba, generando advertencias para cualquier código no setter. Sin embargo, falla para construcciones como esta:

public void setFoo(final String newFoo) {
    Preconditions.checkNotNull(newFoo); // this is OK
    Preconditions.checkArgument(
                 newFoo.matches("\\p{Alpha}{3}"), // this generates a warning
                                                  // because String.matches()
                                                  // is called
                "Foo must have exactly 3 characters!");
    this.foo = newFoo;
}

Entonces, lo que estoy buscando es una construcción que permita cualquier código, siempre que suceda dentro de los parámetros a un Preconditions.check* llamar. ¿Hay tal punto de vista?

¿Fue útil?

Solución

Sé que es una pregunta antigua, pero solo me topé mientras busqué algo más.

La respuesta es no, porque en el bytecodo JVM no existe la "lógica dentro de un check* llamar ". Por ejemplo, newFoo.matches(..) se evalúa antes de el resultado se pasa a Preconditions.checkArgument(..), muy parecido a esto:

boolean match = newFoo.matches("\\p{Alpha}{3}");
Preconditions.checkArgument(match, "Foo must have exactly 3 characters!");

Si el código se escribió así, usted emitiría una advertencia Anway, entonces, ¿por qué no si el mismo código Java, que posiblemente resulta en un código de byte similar o idéntico, se escribe como una llamada anidada? ;-)


Actualizar: He creado un pequeño ejemplo:

public class Application {
    public static void main(String[] args) {
        String newFoo = "Scrum";
        boolean match = newFoo.matches("\\p{Alpha}{3}");
        checkArgument(
            match,
            "Foo must have exactly 3 characters!"
        );
        checkArgument(
            newFoo.matches("\\p{Alpha}{3}"),
            "Foo must have exactly 3 characters!"
        );
    }

    private static void checkArgument(boolean status, String errorMessage) {
        if (!status)
            System.out.println(errorMessage);
    }
}

Si descarga el código de byte usando javap -c Application ves esto:

Compiled from "Application.java"
public class Application extends java.lang.Object{
public Application();
  Code:
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   ldc #16; //String Scrum
   2:   astore_1
   3:   aload_1
   4:   ldc #18; //String \p{Alpha}{3}
   6:   invokevirtual   #20; //Method java/lang/String.matches:(Ljava/lang/String;)Z
   9:   istore_2
   10:  iload_2
   11:  ldc #26; //String Foo must have exactly 3 characters!
   13:  invokestatic    #28; //Method checkArgument:(ZLjava/lang/String;)V
   16:  aload_1
   17:  ldc #18; //String \p{Alpha}{3}
   19:  invokevirtual   #20; //Method java/lang/String.matches:(Ljava/lang/String;)Z
   22:  ldc #26; //String Foo must have exactly 3 characters!
   24:  invokestatic    #28; //Method checkArgument:(ZLjava/lang/String;)V
   27:  return

}

Como puede ver, el código de byte de las líneas 3-13 versus 16-24 en el volcado es idéntico, excepto para el almacenamiento y la carga del valor booleano. Tal vez esto ilustra lo que he dicho antes.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top