|
|
@@ -12,12 +12,13 @@ import java.io.IOException;
|
|
|
import java.io.InputStreamReader;
|
|
|
import java.io.OutputStreamWriter;
|
|
|
import java.io.PrintWriter;
|
|
|
-import java.util.List;
|
|
|
+import java.util.Collection;
|
|
|
import java.util.Map;
|
|
|
import java.util.Set;
|
|
|
import javax.annotation.processing.AbstractProcessor;
|
|
|
import javax.annotation.processing.Filer;
|
|
|
import javax.annotation.processing.RoundEnvironment;
|
|
|
+import javax.annotation.processing.SupportedAnnotationTypes;
|
|
|
import javax.lang.model.element.Element;
|
|
|
import javax.lang.model.element.TypeElement;
|
|
|
import javax.lang.model.type.DeclaredType;
|
|
|
@@ -28,36 +29,39 @@ import javax.lang.model.util.Elements;
|
|
|
import javax.tools.Diagnostic.Kind;
|
|
|
import javax.tools.FileObject;
|
|
|
import javax.tools.StandardLocation;
|
|
|
-import net.ranides.assira.collection.SingleCollection;
|
|
|
import net.ranides.assira.collection.map.MultiHashMap;
|
|
|
import net.ranides.assira.collection.map.MultiMap;
|
|
|
+import net.ranides.assira.io.FileHelper;
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
+ * Based on "org.kohsuke.metainf-services"
|
|
|
+ * http://weblogs.java.net/blog/kohsuke/archive/2009/03/my_project_of_t.html
|
|
|
+ * (C) by Kohsuke Kawaguchi(kk@kohsuke.org) under MIT license
|
|
|
+ *
|
|
|
* @author ranides
|
|
|
*/
|
|
|
+@SupportedAnnotationTypes(
|
|
|
+ "net.ranides.assira.annotations.Meta.JavaService"
|
|
|
+)
|
|
|
public class ProcessorDef extends AbstractProcessor {
|
|
|
|
|
|
- private static final Set<String> SUPPORTED = new SingleCollection<String>(Meta.ExportService.class.getName());
|
|
|
-
|
|
|
- @Override
|
|
|
- public Set<String> getSupportedAnnotationTypes() {
|
|
|
- return SUPPORTED;
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
|
|
- if ( roundEnv.processingOver() ) {
|
|
|
- return false;
|
|
|
+ if ( !roundEnv.processingOver() ) {
|
|
|
+ writeMeta( readMeta( getServices(roundEnv) ) );
|
|
|
}
|
|
|
-
|
|
|
- MultiMap<String, String> services = new MultiHashMap<String, String>();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private MultiMap<String, String> getServices(RoundEnvironment roundEnv) {
|
|
|
|
|
|
+ MultiMap<String, String> services = new MultiHashMap<String, String>();
|
|
|
Elements elements = processingEnv.getElementUtils();
|
|
|
-
|
|
|
+
|
|
|
// discover services from the current compilation sources
|
|
|
- for (Element element : roundEnv.getElementsAnnotatedWith(Meta.ExportService.class)) {
|
|
|
- Meta.ExportService info = element.getAnnotation(Meta.ExportService.class);
|
|
|
+ for (Element element : roundEnv.getElementsAnnotatedWith(Meta.JavaService.class)) {
|
|
|
+ Meta.JavaService info = element.getAnnotation(Meta.JavaService.class);
|
|
|
if(info==null) {
|
|
|
continue; // shouldn't happen - ignore
|
|
|
}
|
|
|
@@ -75,32 +79,41 @@ public class ProcessorDef extends AbstractProcessor {
|
|
|
String tn = elements.getBinaryName(type).toString();
|
|
|
services.putItem(cn, tn);
|
|
|
}
|
|
|
+ return services;
|
|
|
+ }
|
|
|
|
|
|
- // also load up any existing values, since this compilation may be partial
|
|
|
+ private MultiMap<String, String> readMeta(MultiMap<String, String> services) {
|
|
|
Filer filer = processingEnv.getFiler();
|
|
|
- for (Map.Entry<String,List<String>> e : services.entrySet()) {
|
|
|
+
|
|
|
+ for (Map.Entry<String, Collection<String>> e : services.entrySet()) {
|
|
|
+ BufferedReader reader = null;
|
|
|
try {
|
|
|
String contract = e.getKey();
|
|
|
- List<String> target = e.getValue();
|
|
|
+ Collection<String> target = e.getValue();
|
|
|
|
|
|
FileObject file = filer.getResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/services/" +contract);
|
|
|
- BufferedReader reader = new BufferedReader(new InputStreamReader(file.openInputStream(), "UTF-8"));
|
|
|
+ reader = new BufferedReader(new InputStreamReader(file.openInputStream(), "UTF-8"));
|
|
|
String line;
|
|
|
while( null!=(line=reader.readLine()) ) { target.add(line); }
|
|
|
- reader.close();
|
|
|
|
|
|
- } catch (FileNotFoundException x) {
|
|
|
- // doesn't exist
|
|
|
- } catch (IOException x) {
|
|
|
- processingEnv.getMessager().printMessage(Kind.ERROR,"Failed to load existing service definition files: "+x);
|
|
|
+ } catch (FileNotFoundException _) {
|
|
|
+ // ignore, if doesn't exist
|
|
|
+ } catch (IOException cause) {
|
|
|
+ processingEnv.getMessager().printMessage(Kind.ERROR,"Failed to load existing service definition files: "+cause);
|
|
|
+ } finally {
|
|
|
+ FileHelper.close(reader);
|
|
|
}
|
|
|
}
|
|
|
+ return services;
|
|
|
+ }
|
|
|
+
|
|
|
+ private MultiMap<String, String> writeMeta(MultiMap<String, String> services) {
|
|
|
+ Filer filer = processingEnv.getFiler();
|
|
|
|
|
|
- // now write them back out
|
|
|
- for (Map.Entry<String,List<String>> e : services.entrySet()) {
|
|
|
+ for (Map.Entry<String,Collection<String>> e : services.entrySet()) {
|
|
|
try {
|
|
|
String contract = e.getKey();
|
|
|
- List<String> classes = e.getValue();
|
|
|
+ Collection<String> classes = e.getValue();
|
|
|
processingEnv.getMessager().printMessage(Kind.NOTE,"Writing META-INF/services/"+contract);
|
|
|
|
|
|
FileObject file = filer.createResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/services/" +contract);
|
|
|
@@ -109,46 +122,45 @@ public class ProcessorDef extends AbstractProcessor {
|
|
|
writer.println(value);
|
|
|
}
|
|
|
writer.close();
|
|
|
-
|
|
|
} catch (IOException x) {
|
|
|
processingEnv.getMessager().printMessage(Kind.ERROR,"Failed to write service definition files: "+x);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- return false;
|
|
|
+ return services;
|
|
|
}
|
|
|
-
|
|
|
- private TypeElement getContract(TypeElement type, Meta.ExportService a) {
|
|
|
- // explicitly specified?
|
|
|
- try {
|
|
|
- a.value();
|
|
|
- throw new AssertionError();
|
|
|
- } catch (MirroredTypeException e) {
|
|
|
- TypeMirror m = e.getTypeMirror();
|
|
|
- if (m.getKind()== TypeKind.VOID) {
|
|
|
- // contract inferred from the signature
|
|
|
- boolean hasBaseClass = type.getSuperclass().getKind()!=TypeKind.NONE && !isObject(type.getSuperclass());
|
|
|
- boolean hasInterfaces = !type.getInterfaces().isEmpty();
|
|
|
- if(hasBaseClass^hasInterfaces) {
|
|
|
- if(hasBaseClass)
|
|
|
- return (TypeElement)((DeclaredType)type.getSuperclass()).asElement();
|
|
|
- return (TypeElement)((DeclaredType)type.getInterfaces().get(0)).asElement();
|
|
|
- }
|
|
|
-
|
|
|
- error(type, "Contract type was not specified, but it couldn't be inferred.");
|
|
|
- return null;
|
|
|
+
|
|
|
+ private TypeElement getContract(TypeElement type, Meta.JavaService annotation) {
|
|
|
+ TypeMirror m = getExportValue(annotation);
|
|
|
+ if (m.getKind()== TypeKind.VOID) {
|
|
|
+ // contract inferred from the signature
|
|
|
+ boolean hasBaseClass = type.getSuperclass().getKind()!=TypeKind.NONE && !isObject(type.getSuperclass());
|
|
|
+ boolean hasInterfaces = !type.getInterfaces().isEmpty();
|
|
|
+ if(hasBaseClass^hasInterfaces) {
|
|
|
+ if(hasBaseClass)
|
|
|
+ return (TypeElement)((DeclaredType)type.getSuperclass()).asElement();
|
|
|
+ return (TypeElement)((DeclaredType)type.getInterfaces().get(0)).asElement();
|
|
|
}
|
|
|
|
|
|
- if (m instanceof DeclaredType) {
|
|
|
- DeclaredType dt = (DeclaredType) m;
|
|
|
- return (TypeElement)dt.asElement();
|
|
|
- } else {
|
|
|
- error(type, "Invalid type specified as the contract");
|
|
|
- return null;
|
|
|
- }
|
|
|
+ error(type, "Contract type was not specified, but it couldn't be inferred.");
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+ if (m instanceof DeclaredType) {
|
|
|
+ DeclaredType dt = (DeclaredType) m;
|
|
|
+ return (TypeElement)dt.asElement();
|
|
|
+ } else {
|
|
|
+ error(type, "Invalid type specified as the contract");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private TypeMirror getExportValue(Meta.JavaService annotation) {
|
|
|
+ try {
|
|
|
+ annotation.value();
|
|
|
+ throw new AssertionError();
|
|
|
+ } catch (MirroredTypeException exception) {
|
|
|
+ return exception.getTypeMirror();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private boolean isObject(TypeMirror t) {
|