Handle NoSuchFileExceptions from newer versions of javac.
[jglob.git] / src / dolda / jglob / Collector.java
1 package dolda.jglob;
2
3 import java.util.*;
4 import java.io.*;
5 import java.nio.file.*;
6 import javax.annotation.processing.*;
7 import javax.tools.*;
8 import javax.lang.model.*;
9 import javax.lang.model.element.*;
10 import javax.lang.model.util.*;
11
12 @SupportedAnnotationTypes({"*"})
13 public class Collector extends AbstractProcessor {
14     private ProcessingEnvironment cfg;
15     private Elements eu;
16     private boolean verbose = false;
17
18     public void init(ProcessingEnvironment cfg) {
19         this.cfg = cfg;
20         eu = cfg.getElementUtils();
21     }
22
23     private String tn(TypeElement el) {
24         return(eu.getBinaryName(el).toString());
25     }
26
27     private Set<String> getprev(TypeElement annotation) {
28         Set<String> prev = new HashSet<String>();
29         try {
30             FileObject lf = cfg.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/glob/" + tn(annotation));
31             InputStream in;
32             try {
33                 in = lf.openInputStream();
34             } catch(FileNotFoundException | NoSuchFileException e) {
35                 return(prev);
36             }
37             try {
38                 BufferedReader r = new BufferedReader(new InputStreamReader(in, "utf-8"));
39                 String ln;
40                 while((ln = r.readLine()) != null)
41                     prev.add(ln);
42                 return(prev);
43             } finally {
44                 in.close();
45             }
46         } catch(IOException e) {
47             cfg.getMessager().printMessage(Diagnostic.Kind.ERROR, "could not read previous globlist for " + tn(annotation) + ": " + e);
48             return(Collections.emptySet());
49         }
50     }
51
52     private void writenew(TypeElement annotation, Collection<String> names) {
53         try {
54             FileObject lf = cfg.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/glob/" + tn(annotation));
55             OutputStream out = lf.openOutputStream();
56             try {
57                 Writer w = new BufferedWriter(new OutputStreamWriter(out, "utf-8"));
58                 for(String nm : names)
59                     w.write(nm + "\n");
60                 w.flush();
61             } finally {
62                 out.close();
63             }
64         } catch(IOException e) {
65             cfg.getMessager().printMessage(Diagnostic.Kind.ERROR, "could not write new globlist for " + tn(annotation) + ": " + e);
66         }
67     }
68
69     private void process(TypeElement annotation, RoundEnvironment round, TypeMap types) {
70         Set<String> prev = getprev(annotation);
71         Set<String> carry = new HashSet<String>(prev);
72         Set<String> found = new HashSet<String>();
73         for(Element e : round.getElementsAnnotatedWith(annotation)) {
74             if(!(e instanceof TypeElement)) {
75                 cfg.getMessager().printMessage(Diagnostic.Kind.ERROR, tn(annotation) + " must annotate types", e);
76                 continue;
77             }
78             TypeElement type = (TypeElement)e;
79             String nm = tn(type);
80             if(!prev.contains(nm) && verbose)
81                 cfg.getMessager().printMessage(Diagnostic.Kind.NOTE, "added " + nm, type);
82             found.add(nm);
83             carry.remove(nm);
84         }
85         for(Iterator<String> i = carry.iterator(); i.hasNext();) {
86             String nm = i.next();
87             TypeElement el = types.get(nm);
88             if(el != null) {
89                 i.remove();
90                 if(verbose)
91                     cfg.getMessager().printMessage(Diagnostic.Kind.NOTE, "removed " + nm, el);
92             }
93         }
94         List<String> all = new ArrayList<String>();
95         all.addAll(carry);
96         all.addAll(found);
97         Collections.sort(all);
98         writenew(annotation, all);
99     }
100
101     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment round) {
102         for(TypeElement a : annotations) {
103             if(a.getAnnotation(Discoverable.class) != null)
104                 process(a, round, new TypeMap(round.getRootElements(), eu));
105         }
106         return(false);
107     }
108
109     public SourceVersion getSupportedSourceVersion() {
110         return(SourceVersion.latest());
111     }
112 }