2015-12-30 9 views
13

Ich baue einen Annotation Processor für Android (aus Gründen zukünftiger Erklärungen nennen wir es TestProcessor).Wie kann überprüft werden, ob das Paket im Annotationsprozessor vorhanden ist (während der Kompilierung)?

Der Plan ist für den Prozessor in zwei Betriebsarten zu arbeiten:

  • Mode 1: Erzeugung des Codes A

  • Mode 2: Erzeugung des Codes A und B


Mode 2 sollte nur dann, wenn das zusätzliche (optional) ausgewählt wird Paket in der Umgebung vorhanden ist, für die der Prozessor Code erzeugt.

Gibt es eine Möglichkeit in der process Methode des Annotation Processors herauszufinden, wenn das optionale Paket existiert?


EDIT 1:

Kleine Klarstellung der "(optional) Paket". Mit dem zusätzlichen Paket meine ich ein Java-Paket, das kann, muss aber nicht im Projekt existieren (das heißt mit dem Prozessor). Das optionale Paket kann beispielsweise den Inhalt einer externen Bibliothek darstellen. Die externe Bibliothek kann, muss aber nicht im Projekt enthalten sein.

Lassen Sie mich nur ein kleines Beispiel machen:

  • Nehmen wir an, wir haben ein (ein Modul) Projekt Sample.
  • Sample verwendet meine TestProcessor.
  • die Square'sPicasso als Beispiel für eine externe Bibliothek
  • Wenn Sample HAS Square'sPicasso als eine ihrer Abhängigkeiten nehmen lassen, arbeitet TestProcessor in Mode 2 und Code A und B erzeugt. Mit anderen Worten: Wenn Sie problemlos Klassen von com.square.picasso (in Sample) verwenden können, sollte der Prozessor in Mode 2 arbeiten.
  • Wenn es keine Square'sPicasso in Sample's Abhängigkeiten betreibt TestProcessor in Mode 1 und erzeugt nur Code A.

EDIT 2:

Ich dachte an zwei Abhilfen für dieses Problem:

  1. Verwendung von zwei Arten von Annotationen für zwei processorModes (Beispiel: @DoStuffModeOne , @DoStuffModeTwo)
  2. eine zweite Art von Anmerkung Verwendung (das zum Beispiel auf den Application verwendet werden soll), die die Verwendung von Mode 2 (Beispiel: @TriggerModeTwo) löst

Für meinen Fall der zweite Problemumgehung ist viel mehr bevorzugt, aber ist immer noch viel schlechter als es wäre, wenn die TestProcessor selbst entscheiden könnte, welche Mode zu wählen.

+0

Was genau ist ein "zusätzliches (optional) Paket"? Meinst du ein Java-Paket? Wenn ja, was bedeutet es, dass ein Java-Paket existiert? Meinst du, dass ein Verzeichnis für dieses Java-Paket existiert? Meinst du, dass eine Quelldatei in diesem Verzeichnis existiert?Ich habe keinen Annotationsprozessor geschrieben, daher kann ich Ihnen nicht direkt helfen, aber Ihre Frage zu bearbeiten, um zu verdeutlichen, worauf Sie sich beziehen, könnte anderen helfen, Ihnen zu helfen. – CommonsWare

+0

Sicher, lassen Sie mich klarstellen, dass ... –

+0

zielen Sie auf eine bestimmte Paketprüfung? –

Antwort

2

Sie können eine der Klassen im Klassenpfad der Anwendung überprüfen. Führen Sie dann Ihre Logik basierend auf dem Ergebnis des Checks aus.

+1

Das einzige Problem ist, dass es nur funktioniert, wenn das 'optionale Paket' (' butterknife' in diesem Beispiel) NICHT im Compiler vorhanden ist. Ich weiß, dass diese Anforderung von mir ursprünglich nicht erwähnt wurde, also bist du momentan der beste Prätendent, der die Bounty erhält :) Lass mich noch ein paar Tage warten, um zu sehen, ob noch weitere Antworten kommen. –

0

Sie könnten diesen Code verwenden, um herauszufinden, ob eine Klasse in der Annotationsverarbeitungsumgebung vorhanden ist.

TypeElement typeElement = processingEnvironment.getElementUtils(). 
    getTypeElement("com.squareup.picasso.Picasso"); 

ich keinen Erfolg hatte mit der Elements.getPackageElement() Methode, weil sie erfolgreich für nicht vorhandene Pakete (zumindest unter Eclipse) zurückgeführt und zur Durchführung des PackageElement.getEnclosedElements() Methode auf Pakete wie diese erstellt leer war auch für Nicht-leer Pakete. Ich würde vorschlagen, dass Sie für eine bestimmte Klasse in Ihrem Paket von Interesse gehen, wie in meinem vorherigen Beispiel, weil es wie erwartet für vorhandene Typelemente funktioniert und null für nicht vorhandene Typen zurückgibt.

ich zur Zeit keine Annotation Verarbeitungs-API basierende Methode gefunden, um zu entscheiden, ob der Typ Element auf diese Weise gefunden auf einer Datei Quellcode basiert auf dem Quellpfad des Projekts oder einer binären Klassendatei auf der Kompilierungsklassenpfad. Es könnte eine Methode dafür geben, die processingEnvironment.getFiler().getResource(StandardLocation.SOURCE_PATH, ...) miteinbezieht, aber leider nicht tragbar ist, weil StandardLocation.SOURCE_PATH in Eclipse nicht unterstützt wird.

Ich hoffe, das hilft.

+0

Danke für die Antwort. Leider löst es das Problem nicht. Ich muss überprüfen, ob es im Quellcode existiert, für den die Annotationsverarbeitung ausgeführt wird. –

+0

Bedeutet das, dass Sie sowohl JDK-basierte Annotationsverarbeitungs-Builds als auch Eclipse-basierte Builds unterstützen müssen? JDK sollte mit 'processingEnvironment.getFiler(). GetResource (StandardLocation.SOURCE_PATH, ...)' arbeiten. Eclipse könnte auch funktionieren, aber es ist ein bisschen hässlicher. –

+0

Eclipse unterscheidet zwischen einem TypeElement, das auf einer Quelldatei oder einer binären Klassendatei basiert. Es wird von der Annotation Processing API nicht angezeigt, aber Sie können es problemlos durch Reflektion abrufen, nachdem Sie festgestellt haben, dass der Eclipse-Compiler tatsächlich Ihren Prozessor ausführt. Oder Sie können die relevante Eclipse-Plugin-API in Ihren Code einfügen und mit einer expliziten Umwandlung beginnen und von dort aus entscheiden, ob sie tatsächlich auf einer Java-Quelldatei oder einer Binärklasse basiert. Ich weiß, dass dies nicht der richtige Weg ist, aber was können wir tun, wenn Eclipse entschieden hat, eine Ressource von SOURCE_PATH zu entfernen. –

0

Zusätzlich zu der Lösung vorgeschlagen JBirdVegas; Mit dieser Funktion kann geprüft werden, ob in den externen Bibliotheken zur Laufzeit ein Paket existiert.

public static boolean packageExists(String packagePath) { 
    return Thread.currentThread().getContextClassLoader().getResource(packagePath) != null; 
} 

Verbrauch:

packageExists("apackage/innerpackage") 
Verwandte Themen