Frage

Ich benutze Aspektj für projektweite Richtlinien Durchsetzung.

Eine Sache, die ich jetzt implementieren möchte, ist, dass in irgendeiner Setter -Methoden keine Logik außer einer einfachen Validierung mit Guave's vorhanden sein sollte Preconditions.check* Methoden.

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";

Dies funktioniert wie erwartet und generiert Warnungen für jeden Nicht-Setter-Code. Es fällt jedoch für Konstrukte wie folgt nicht:

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;
}

Ich suche also ein Konstrukt, das jeden Code zulässt, solange er innerhalb der Parameter zu a passiert Preconditions.check* Anruf. Gibt es einen solchen Pointcut?

War es hilfreich?

Lösung

Ich weiß, dass es eine alte Frage ist, aber ich bin gerade darüber gestolpert, als ich nach etwas anderem gesucht habe.

Die Antwort lautet Nein, denn in JVM -Bytecode gibt es keine "Logik in a check* rufen ". Zum Beispiel, newFoo.matches(..) wird bewertet Vor Das Ergebnis wird an übergeben Preconditions.checkArgument(..), sehr ähnlich:

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

Wenn der Code so geschrieben würde, würden Sie eine Warnung anway ausstellen. Warum also nicht derselbe Java -Code, der möglicherweise zu einem ähnlichen oder identischen Byte -Code führt, als verschachtelter Anruf geschrieben wird? ;-)


Aktualisieren: Ich habe ein kleines Beispiel erstellt:

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);
    }
}

Wenn Sie den Byte -Code verwenden javap -c Application du siehst das:

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

}

Wie Sie sehen können, ist der Byte-Code der Zeilen 3-13 gegenüber 16-24 im Dump identisch, mit Ausnahme des Aufbewahrung und Wiederbelastung des Booleschen Wertes. Vielleicht zeigt dies, was ich schon einmal gesagt habe.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top