2016-08-29 3 views
1

Solange ich mich erinnere, habe ich immer Typ-Aliase (z. B. typedefs in C++ oder Typ/newtype in Haskell) in Java. Im Android SDK gibt es support annotations, die @IntDef, @StringDef und verschiedene Ressourcentypen-Annotationen enthalten, die uns helfen, einen möglichen Missbrauch von Integer/String-Werten zur Kompilierzeit herauszufinden. Ich bin aus dem Android docs ein Stück Code einfügen Sie die kurze Vorstellung geben:Java Annotation Prozessor für Typ Aliase

@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS}) 
@Retention(RetentionPolicy.SOURCE) 
public @interface NavigationMode {} 

public static final int NAVIGATION_MODE_STANDARD = 0; 
public static final int NAVIGATION_MODE_LIST = 1; 
public static final int NAVIGATION_MODE_TABS = 2; 

@NavigationMode 
public abstract int getNavigationMode(); 

public abstract void setNavigationMode(@NavigationMode int mode); 

Eigentlich 95% der Fälle I Aliasing wollen, sind eine Art gleiche Art: wenn ich eine Art von Datenbank-Zeilen-ID bekam normalerweise long oder String, was dazu führt, dass Typinformationen über die Variable im Namen codiert werden müssen (z. B. long folderId, long messageId). Allerdings gibt es eine ärgerliche Einschränkung der StringDef/IntDef Annotationen: Aus irgendeinem Grund erfordern sie eine Reihe von vordefinierten Konstanten, so dass Sie nur eine endliche Menge von Werten beschreiben können, die offensichtlich nicht genug für DB-Kennungen ist.

Was ich will, ist eine Art ähnlich Anmerkung @TypeAlias sagen und ein Lint zu überprüfen, so könnte ich tun:

@TypeAlias 
@Retention(RetentionPolicy.SOURCE) 
public @interface FolderId { } 

@FolderId 
public long getFolderIdByName(Database db, String name) { 
    long id = db.foldersTable().findByName(name).getId(); 
    return id; 
    /* 
     we might need to suppress the check here 
     (because we pass long as a @FolderId long), 
     but that's okay, since we are aware of 
     what we are doing here, and it's the only 
     possible injection point for @FolderId 
    */ 
} 

public void deleteMessagesIn(Database db, @FolderId long folder) { 
    // whatever 
} 

public void deleteMessagesInInbox(Database db) { 
    deleteMessagesIn(db, 1); // rejected by Lint, trying to pass long as @FolderId long 
    deleteMessagesIn(db, getFolderIdByName(db, "Inbox")); // ok, passes Lint check 
} 

Ich sehe keinen guten Grund, auf eine Reihe von endlichen Typ Aliasing Anmerkungen beschränken Werte könnten wir einfach umgehen, indem wir, wie ich oben erwähnt habe, unterdrücken oder vielleicht eine andere Anmerkung speziell für Funktionen einführen, die Typ-Aliase bereitstellen.

Darüber hinaus geht es nicht nur um Einschränkungen der Android-Annotationen: jede einfache Java-Anwendung könnte auch von diesen Arten von Typ-Aliasen profitieren, und ich habe es nicht geschafft, etwas Ähnliches zu googeln. Wir könnten auch von der Verwendung des Ziels TYPE_PARAMETER profitieren, wodurch alles fast wie echte Aliase aussehen wird.

So sind die Fragen:

  • Gibt es statische Analysatoren, die diese Art von Kontrollen implementieren?
  • Wenn nicht, gibt es irgendwelche fundamentalen Einschränkungen, die ich vermeide, die verhindern, dass es umgesetzt wird? Da ich es wieder sehr nützlich finde, hätte jemand es getan, wenn es keinen gegeben hätte.

P.S. @mernst wies mich an Checker Rahmen, und ich schaffte es mit Android in relativ schmerzlos zu integrieren: https://github.com/karlicoss/checker-fenum-android-demo

Antwort

1

Ein statischen Analysator, der für die korrekte Verwendung von Typ-Aliasnamen (typedefs) prüft die Fake Enum Checker, die mit den Checker Framework verteilt . Es wurde verwendet, um Bugs in Swing und JabRef zu finden.

+0

Vielen Dank! Nicht so praktisch wie ich es erwartet habe, aber ich habe es für Android-Projekt funktioniert, super! – karlicoss

Verwandte Themen