ProcessBindable.java revision 1b9940e612fc73202837fbe9db2f9035f307b5d1
1b617e5da04aa910be70204afb886b1ebebb80618George Mountpackage com.android.databinding.annotationprocessor;
2b617e5da04aa910be70204afb886b1ebebb80618George Mount
31b9940e612fc73202837fbe9db2f9035f307b5d1George Mountimport com.android.databinding.reflection.ModelAnalyzer;
41b9940e612fc73202837fbe9db2f9035f307b5d1George Mountimport com.android.databinding.reflection.ReflectionAnalyzer;
51b9940e612fc73202837fbe9db2f9035f307b5d1George Mount
6b617e5da04aa910be70204afb886b1ebebb80618George Mountimport android.binding.Bindable;
7b617e5da04aa910be70204afb886b1ebebb80618George Mount
8612997fe2e41366573855f56898b27d4c8787244George Mountimport java.io.File;
9b617e5da04aa910be70204afb886b1ebebb80618George Mountimport java.io.IOException;
10846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mountimport java.io.InputStream;
11612997fe2e41366573855f56898b27d4c8787244George Mountimport java.io.ObjectInputStream;
12612997fe2e41366573855f56898b27d4c8787244George Mountimport java.io.ObjectOutputStream;
13846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mountimport java.io.Serializable;
14b617e5da04aa910be70204afb886b1ebebb80618George Mountimport java.io.Writer;
15846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mountimport java.net.URL;
16b617e5da04aa910be70204afb886b1ebebb80618George Mountimport java.util.ArrayList;
17b617e5da04aa910be70204afb886b1ebebb80618George Mountimport java.util.Collections;
18846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mountimport java.util.Enumeration;
19846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mountimport java.util.HashMap;
20b617e5da04aa910be70204afb886b1ebebb80618George Mountimport java.util.HashSet;
21e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mountimport java.util.List;
22b617e5da04aa910be70204afb886b1ebebb80618George Mountimport java.util.Set;
23b617e5da04aa910be70204afb886b1ebebb80618George Mount
24b617e5da04aa910be70204afb886b1ebebb80618George Mountimport javax.annotation.processing.AbstractProcessor;
251b9940e612fc73202837fbe9db2f9035f307b5d1George Mountimport javax.annotation.processing.ProcessingEnvironment;
26b617e5da04aa910be70204afb886b1ebebb80618George Mountimport javax.annotation.processing.RoundEnvironment;
27b617e5da04aa910be70204afb886b1ebebb80618George Mountimport javax.annotation.processing.SupportedAnnotationTypes;
28b617e5da04aa910be70204afb886b1ebebb80618George Mountimport javax.annotation.processing.SupportedSourceVersion;
29b617e5da04aa910be70204afb886b1ebebb80618George Mountimport javax.lang.model.SourceVersion;
30b617e5da04aa910be70204afb886b1ebebb80618George Mountimport javax.lang.model.element.Element;
31e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mountimport javax.lang.model.element.ElementKind;
32b617e5da04aa910be70204afb886b1ebebb80618George Mountimport javax.lang.model.element.ExecutableElement;
33b617e5da04aa910be70204afb886b1ebebb80618George Mountimport javax.lang.model.element.Name;
341b9940e612fc73202837fbe9db2f9035f307b5d1George Mountimport javax.lang.model.element.PackageElement;
35b617e5da04aa910be70204afb886b1ebebb80618George Mountimport javax.lang.model.element.TypeElement;
36b617e5da04aa910be70204afb886b1ebebb80618George Mountimport javax.lang.model.element.VariableElement;
37b617e5da04aa910be70204afb886b1ebebb80618George Mountimport javax.lang.model.type.TypeKind;
38e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mountimport javax.lang.model.util.Elements;
39e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mountimport javax.lang.model.util.Types;
40b617e5da04aa910be70204afb886b1ebebb80618George Mountimport javax.tools.Diagnostic;
413561e3e665698843b1c664385a842e779198960bGeorge Mountimport javax.tools.FileObject;
42b617e5da04aa910be70204afb886b1ebebb80618George Mountimport javax.tools.JavaFileObject;
433561e3e665698843b1c664385a842e779198960bGeorge Mountimport javax.tools.StandardLocation;
44b617e5da04aa910be70204afb886b1ebebb80618George Mount
45b617e5da04aa910be70204afb886b1ebebb80618George Mount@SupportedAnnotationTypes({"android.binding.Bindable"})
46b617e5da04aa910be70204afb886b1ebebb80618George Mount@SupportedSourceVersion(SourceVersion.RELEASE_7)
47b617e5da04aa910be70204afb886b1ebebb80618George Mountpublic class ProcessBindable extends AbstractProcessor {
48b617e5da04aa910be70204afb886b1ebebb80618George Mount
49b617e5da04aa910be70204afb886b1ebebb80618George Mount    private boolean mFileGenerated;
50b617e5da04aa910be70204afb886b1ebebb80618George Mount
51b617e5da04aa910be70204afb886b1ebebb80618George Mount    public ProcessBindable() {
52b617e5da04aa910be70204afb886b1ebebb80618George Mount    }
53b617e5da04aa910be70204afb886b1ebebb80618George Mount
54b617e5da04aa910be70204afb886b1ebebb80618George Mount    @Override
551b9940e612fc73202837fbe9db2f9035f307b5d1George Mount    public synchronized void init(ProcessingEnvironment processingEnv) {
561b9940e612fc73202837fbe9db2f9035f307b5d1George Mount        super.init(processingEnv);
571b9940e612fc73202837fbe9db2f9035f307b5d1George Mount        ReflectionAnalyzer.setProcessingEnvironment(processingEnv);
581b9940e612fc73202837fbe9db2f9035f307b5d1George Mount    }
591b9940e612fc73202837fbe9db2f9035f307b5d1George Mount
601b9940e612fc73202837fbe9db2f9035f307b5d1George Mount    @Override
61b617e5da04aa910be70204afb886b1ebebb80618George Mount    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
62b617e5da04aa910be70204afb886b1ebebb80618George Mount        if (mFileGenerated) {
63b617e5da04aa910be70204afb886b1ebebb80618George Mount            return false;
64b617e5da04aa910be70204afb886b1ebebb80618George Mount        }
65846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        Intermediate properties = readIntermediateFile();
66b617e5da04aa910be70204afb886b1ebebb80618George Mount        for (Element element : roundEnv.getElementsAnnotatedWith(Bindable.class)) {
67846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            TypeElement enclosing = (TypeElement) element.getEnclosingElement();
68846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            properties.cleanProperties(enclosing.getQualifiedName().toString());
69846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        }
70846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        for (Element element : roundEnv.getElementsAnnotatedWith(Bindable.class)) {
71846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            TypeElement enclosing = (TypeElement) element.getEnclosingElement();
72b617e5da04aa910be70204afb886b1ebebb80618George Mount            String name = getPropertyName(element);
73b617e5da04aa910be70204afb886b1ebebb80618George Mount            if (name != null) {
74846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                properties.addProperty(enclosing.getQualifiedName().toString(), name);
75b617e5da04aa910be70204afb886b1ebebb80618George Mount            }
76b617e5da04aa910be70204afb886b1ebebb80618George Mount        }
77612997fe2e41366573855f56898b27d4c8787244George Mount        writeIntermediateFile(properties);
78b617e5da04aa910be70204afb886b1ebebb80618George Mount        generateBR(properties);
79b617e5da04aa910be70204afb886b1ebebb80618George Mount        mFileGenerated = true;
80b617e5da04aa910be70204afb886b1ebebb80618George Mount        return true;
81b617e5da04aa910be70204afb886b1ebebb80618George Mount    }
82b617e5da04aa910be70204afb886b1ebebb80618George Mount
83846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount    private void generateBR(Intermediate intermediate) {
84b617e5da04aa910be70204afb886b1ebebb80618George Mount        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
85b617e5da04aa910be70204afb886b1ebebb80618George Mount                "************* Generating BR file from Bindable attributes");
86846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        HashSet<String> properties = new HashSet<>();
87846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        intermediate.captureProperties(properties);
88846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        mergeClassPathResources(properties);
89b617e5da04aa910be70204afb886b1ebebb80618George Mount        try {
90b617e5da04aa910be70204afb886b1ebebb80618George Mount            ArrayList<String> sortedProperties = new ArrayList<String>();
91b617e5da04aa910be70204afb886b1ebebb80618George Mount            sortedProperties.addAll(properties);
92b617e5da04aa910be70204afb886b1ebebb80618George Mount            Collections.sort(sortedProperties);
93b617e5da04aa910be70204afb886b1ebebb80618George Mount
94b617e5da04aa910be70204afb886b1ebebb80618George Mount            JavaFileObject fileObject = processingEnv.getFiler()
95b617e5da04aa910be70204afb886b1ebebb80618George Mount                    .createSourceFile("android.binding.BR");
96b617e5da04aa910be70204afb886b1ebebb80618George Mount            Writer writer = fileObject.openWriter();
97b617e5da04aa910be70204afb886b1ebebb80618George Mount            writer.write("package android.binding;\n\n" +
98b617e5da04aa910be70204afb886b1ebebb80618George Mount                            "public final class BR {\n" +
99b617e5da04aa910be70204afb886b1ebebb80618George Mount                            "    public static final int _all = 0;\n"
100b617e5da04aa910be70204afb886b1ebebb80618George Mount            );
101b617e5da04aa910be70204afb886b1ebebb80618George Mount            int id = 0;
102b617e5da04aa910be70204afb886b1ebebb80618George Mount            for (String property : sortedProperties) {
103b617e5da04aa910be70204afb886b1ebebb80618George Mount                id++;
104b617e5da04aa910be70204afb886b1ebebb80618George Mount                writer.write("    public static final int " + property + " = " + id + ";\n");
105b617e5da04aa910be70204afb886b1ebebb80618George Mount            }
10643596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            writer.write("    public static int getId(String key) {\n");
10743596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            writer.write("        switch(key) {\n");
10843596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            id = 0;
10943596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            for (String property : sortedProperties) {
11043596c2b2997e40b709627419732100d78a62ff0Yigit Boyar                id++;
11143596c2b2997e40b709627419732100d78a62ff0Yigit Boyar                writer.write("            case \"" + property + "\": return " + id + ";\n");
11243596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            }
11343596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            writer.write("        }\n");
11443596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            writer.write("        return -1;\n");
11543596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            writer.write("    }");
116b617e5da04aa910be70204afb886b1ebebb80618George Mount            writer.write("}\n");
11743596c2b2997e40b709627419732100d78a62ff0Yigit Boyar
118b617e5da04aa910be70204afb886b1ebebb80618George Mount            writer.close();
119b617e5da04aa910be70204afb886b1ebebb80618George Mount        } catch (IOException e) {
120b617e5da04aa910be70204afb886b1ebebb80618George Mount            processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
121b617e5da04aa910be70204afb886b1ebebb80618George Mount                    "Could not generate BR file " + e.getLocalizedMessage());
122b617e5da04aa910be70204afb886b1ebebb80618George Mount        }
123b617e5da04aa910be70204afb886b1ebebb80618George Mount    }
124b617e5da04aa910be70204afb886b1ebebb80618George Mount
125b617e5da04aa910be70204afb886b1ebebb80618George Mount    private String getPropertyName(Element element) {
126b617e5da04aa910be70204afb886b1ebebb80618George Mount        switch (element.getKind()) {
127b617e5da04aa910be70204afb886b1ebebb80618George Mount            case FIELD:
128b617e5da04aa910be70204afb886b1ebebb80618George Mount                return stripPrefixFromField((VariableElement) element);
129b617e5da04aa910be70204afb886b1ebebb80618George Mount            case METHOD:
130b617e5da04aa910be70204afb886b1ebebb80618George Mount                return stripPrefixFromMethod((ExecutableElement) element);
131b617e5da04aa910be70204afb886b1ebebb80618George Mount            default:
132b617e5da04aa910be70204afb886b1ebebb80618George Mount                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
133b617e5da04aa910be70204afb886b1ebebb80618George Mount                        "@Bindable is not allowed on " + element.getKind(), element);
134b617e5da04aa910be70204afb886b1ebebb80618George Mount                return null;
135b617e5da04aa910be70204afb886b1ebebb80618George Mount        }
136b617e5da04aa910be70204afb886b1ebebb80618George Mount    }
137b617e5da04aa910be70204afb886b1ebebb80618George Mount
138b617e5da04aa910be70204afb886b1ebebb80618George Mount    private static String stripPrefixFromField(VariableElement element) {
139b617e5da04aa910be70204afb886b1ebebb80618George Mount        Name name = element.getSimpleName();
140b617e5da04aa910be70204afb886b1ebebb80618George Mount        if (name.length() >= 2) {
141b617e5da04aa910be70204afb886b1ebebb80618George Mount            char firstChar = name.charAt(0);
142b617e5da04aa910be70204afb886b1ebebb80618George Mount            char secondChar = name.charAt(1);
1437201118b5554426cea3fcd07e4fd96e999d3eea9George Mount            if (name.length() > 2 && firstChar == 'm' && secondChar == '_') {
1447201118b5554426cea3fcd07e4fd96e999d3eea9George Mount                char thirdChar = name.charAt(2);
1457201118b5554426cea3fcd07e4fd96e999d3eea9George Mount                if (Character.isJavaIdentifierStart(thirdChar)) {
1467201118b5554426cea3fcd07e4fd96e999d3eea9George Mount                    return "" + Character.toLowerCase(thirdChar) +
1477201118b5554426cea3fcd07e4fd96e999d3eea9George Mount                            name.subSequence(3, name.length());
1487201118b5554426cea3fcd07e4fd96e999d3eea9George Mount                }
1497201118b5554426cea3fcd07e4fd96e999d3eea9George Mount            } else if ((firstChar == 'm' && Character.isUpperCase(secondChar)) ||
150b617e5da04aa910be70204afb886b1ebebb80618George Mount                    (firstChar == '_' && Character.isJavaIdentifierStart(secondChar))) {
151b617e5da04aa910be70204afb886b1ebebb80618George Mount                return "" + Character.toLowerCase(secondChar) + name.subSequence(2, name.length());
152b617e5da04aa910be70204afb886b1ebebb80618George Mount            }
153b617e5da04aa910be70204afb886b1ebebb80618George Mount        }
154b617e5da04aa910be70204afb886b1ebebb80618George Mount        return name.toString();
155b617e5da04aa910be70204afb886b1ebebb80618George Mount    }
156b617e5da04aa910be70204afb886b1ebebb80618George Mount
157b617e5da04aa910be70204afb886b1ebebb80618George Mount    private String stripPrefixFromMethod(ExecutableElement element) {
158b617e5da04aa910be70204afb886b1ebebb80618George Mount        Name name = element.getSimpleName();
159b617e5da04aa910be70204afb886b1ebebb80618George Mount        CharSequence propertyName;
160b617e5da04aa910be70204afb886b1ebebb80618George Mount        if (isGetter(element) || isSetter(element)) {
161b617e5da04aa910be70204afb886b1ebebb80618George Mount            propertyName = name.subSequence(3, name.length());
162b617e5da04aa910be70204afb886b1ebebb80618George Mount        } else if (isBooleanGetter(element)) {
163b617e5da04aa910be70204afb886b1ebebb80618George Mount            propertyName = name.subSequence(2, name.length());
164b617e5da04aa910be70204afb886b1ebebb80618George Mount        } else {
165b617e5da04aa910be70204afb886b1ebebb80618George Mount            processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
166b617e5da04aa910be70204afb886b1ebebb80618George Mount                    "@Bindable associated with method must follow JavaBeans convention", element);
167b617e5da04aa910be70204afb886b1ebebb80618George Mount            return null;
168b617e5da04aa910be70204afb886b1ebebb80618George Mount        }
169b617e5da04aa910be70204afb886b1ebebb80618George Mount        char firstChar = propertyName.charAt(0);
170b617e5da04aa910be70204afb886b1ebebb80618George Mount        return "" + Character.toLowerCase(firstChar) +
171b617e5da04aa910be70204afb886b1ebebb80618George Mount                propertyName.subSequence(1, propertyName.length());
172b617e5da04aa910be70204afb886b1ebebb80618George Mount    }
173b617e5da04aa910be70204afb886b1ebebb80618George Mount
174b617e5da04aa910be70204afb886b1ebebb80618George Mount    private static boolean prefixes(CharSequence sequence, String prefix) {
175b617e5da04aa910be70204afb886b1ebebb80618George Mount        boolean prefixes = false;
176b617e5da04aa910be70204afb886b1ebebb80618George Mount        if (sequence.length() > prefix.length()) {
177b617e5da04aa910be70204afb886b1ebebb80618George Mount            int count = prefix.length();
178b617e5da04aa910be70204afb886b1ebebb80618George Mount            prefixes = true;
179b617e5da04aa910be70204afb886b1ebebb80618George Mount            for (int i = 0; i < count; i++) {
180b617e5da04aa910be70204afb886b1ebebb80618George Mount                if (sequence.charAt(i) != prefix.charAt(i)) {
181b617e5da04aa910be70204afb886b1ebebb80618George Mount                    prefixes = false;
182b617e5da04aa910be70204afb886b1ebebb80618George Mount                    break;
183b617e5da04aa910be70204afb886b1ebebb80618George Mount                }
184b617e5da04aa910be70204afb886b1ebebb80618George Mount            }
185b617e5da04aa910be70204afb886b1ebebb80618George Mount        }
186b617e5da04aa910be70204afb886b1ebebb80618George Mount        return prefixes;
187b617e5da04aa910be70204afb886b1ebebb80618George Mount    }
188b617e5da04aa910be70204afb886b1ebebb80618George Mount
189b617e5da04aa910be70204afb886b1ebebb80618George Mount    private static boolean isGetter(ExecutableElement element) {
190b617e5da04aa910be70204afb886b1ebebb80618George Mount        Name name = element.getSimpleName();
191b617e5da04aa910be70204afb886b1ebebb80618George Mount        return prefixes(name, "get") &&
192b617e5da04aa910be70204afb886b1ebebb80618George Mount                Character.isJavaIdentifierStart(name.charAt(3)) &&
193b617e5da04aa910be70204afb886b1ebebb80618George Mount                element.getParameters().isEmpty() &&
194b617e5da04aa910be70204afb886b1ebebb80618George Mount                element.getReturnType().getKind() != TypeKind.VOID;
195b617e5da04aa910be70204afb886b1ebebb80618George Mount    }
196b617e5da04aa910be70204afb886b1ebebb80618George Mount
197b617e5da04aa910be70204afb886b1ebebb80618George Mount    private static boolean isSetter(ExecutableElement element) {
198b617e5da04aa910be70204afb886b1ebebb80618George Mount        Name name = element.getSimpleName();
199b617e5da04aa910be70204afb886b1ebebb80618George Mount        return prefixes(name, "set") &&
200b617e5da04aa910be70204afb886b1ebebb80618George Mount                Character.isJavaIdentifierStart(name.charAt(3)) &&
201b617e5da04aa910be70204afb886b1ebebb80618George Mount                element.getParameters().size() == 1 &&
202b617e5da04aa910be70204afb886b1ebebb80618George Mount                element.getReturnType().getKind() == TypeKind.VOID;
203b617e5da04aa910be70204afb886b1ebebb80618George Mount    }
204b617e5da04aa910be70204afb886b1ebebb80618George Mount
205b617e5da04aa910be70204afb886b1ebebb80618George Mount    private static boolean isBooleanGetter(ExecutableElement element) {
206b617e5da04aa910be70204afb886b1ebebb80618George Mount        Name name = element.getSimpleName();
207b617e5da04aa910be70204afb886b1ebebb80618George Mount        return prefixes(name, "is") &&
208b617e5da04aa910be70204afb886b1ebebb80618George Mount                Character.isJavaIdentifierStart(name.charAt(2)) &&
209b617e5da04aa910be70204afb886b1ebebb80618George Mount                element.getParameters().isEmpty() &&
210b617e5da04aa910be70204afb886b1ebebb80618George Mount                element.getReturnType().getKind() == TypeKind.BOOLEAN;
211b617e5da04aa910be70204afb886b1ebebb80618George Mount    }
212612997fe2e41366573855f56898b27d4c8787244George Mount
213846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount    private Intermediate readIntermediateFile() {
214846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        Intermediate properties = null;
2153561e3e665698843b1c664385a842e779198960bGeorge Mount        ObjectInputStream in = null;
2163561e3e665698843b1c664385a842e779198960bGeorge Mount        try {
2173561e3e665698843b1c664385a842e779198960bGeorge Mount            FileObject intermediate = processingEnv.getFiler()
2183561e3e665698843b1c664385a842e779198960bGeorge Mount                    .getResource(StandardLocation.CLASS_OUTPUT,
2193561e3e665698843b1c664385a842e779198960bGeorge Mount                            ProcessBindable.class.getPackage().getName(), "binding_properties.bin");
2203561e3e665698843b1c664385a842e779198960bGeorge Mount            if (new File(intermediate.getName()).exists()) {
2213561e3e665698843b1c664385a842e779198960bGeorge Mount                in = new ObjectInputStream(intermediate.openInputStream());
222846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                properties = (Intermediate) in.readObject();
2233561e3e665698843b1c664385a842e779198960bGeorge Mount            }
2243561e3e665698843b1c664385a842e779198960bGeorge Mount        } catch (IOException e) {
2253561e3e665698843b1c664385a842e779198960bGeorge Mount            System.err.println("Could not read Binding properties intermediate file: " +
2263561e3e665698843b1c664385a842e779198960bGeorge Mount                    e.getLocalizedMessage());
2273561e3e665698843b1c664385a842e779198960bGeorge Mount        } catch (ClassNotFoundException e) {
2283561e3e665698843b1c664385a842e779198960bGeorge Mount            System.err.println("Could not read Binding properties intermediate file: " +
2293561e3e665698843b1c664385a842e779198960bGeorge Mount                    e.getLocalizedMessage());
2303561e3e665698843b1c664385a842e779198960bGeorge Mount        } finally {
2313561e3e665698843b1c664385a842e779198960bGeorge Mount            try {
2323561e3e665698843b1c664385a842e779198960bGeorge Mount                if (in != null) {
2333561e3e665698843b1c664385a842e779198960bGeorge Mount                    in.close();
2343561e3e665698843b1c664385a842e779198960bGeorge Mount                }
235612997fe2e41366573855f56898b27d4c8787244George Mount            } catch (IOException e) {
2363561e3e665698843b1c664385a842e779198960bGeorge Mount                e.printStackTrace();
237612997fe2e41366573855f56898b27d4c8787244George Mount            }
238612997fe2e41366573855f56898b27d4c8787244George Mount        }
239612997fe2e41366573855f56898b27d4c8787244George Mount        if (properties == null) {
240846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            properties = new IntermediateV1();
241612997fe2e41366573855f56898b27d4c8787244George Mount        }
242612997fe2e41366573855f56898b27d4c8787244George Mount        return properties;
243612997fe2e41366573855f56898b27d4c8787244George Mount    }
244612997fe2e41366573855f56898b27d4c8787244George Mount
245846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount    private void mergeClassPathResources(HashSet<String> intermediateProperties) {
246846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        try {
247846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            String resourcePath = ProcessBindable.class.getPackage().getName()
248846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                    .replace('.', '/') + "/binding_properties.bin";
249846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            Enumeration<URL> resources = getClass().getClassLoader()
250846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                    .getResources(resourcePath);
251846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            while (resources.hasMoreElements()) {
252846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                URL url = resources.nextElement();
253846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                System.out.println("Merging binding adapters from " + url);
254846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                InputStream inputStream = null;
255846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                try {
256846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                    inputStream = url.openStream();
257846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                    ObjectInputStream in = new ObjectInputStream(inputStream);
258846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                    Intermediate properties = (Intermediate) in.readObject();
259846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                    if (properties != null) {
260846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                        properties.captureProperties(intermediateProperties);
261846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                    }
262846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                } catch (IOException e) {
263846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                    System.err.println("Could not merge in Bindables from " + url + ": " +
264846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                            e.getLocalizedMessage());
265846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                } catch (ClassNotFoundException e) {
266846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                    System.err.println("Could not read Binding properties intermediate file: " +
267846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                            e.getLocalizedMessage());
268846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                } finally {
269846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                    try {
270846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                        inputStream.close();
271846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                    } catch (IOException e2) {
272846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                        System.err.println("Error closing intermediate Bindables store: " +
273846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                                e2.getLocalizedMessage());
274846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                    }
275846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                }
276846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            }
277846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        } catch (IOException e) {
278846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            System.err.println("Could not read Binding properties intermediate file: " +
279846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                    e.getLocalizedMessage());
280846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        }
281846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount    }
282846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount
283846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount    private void writeIntermediateFile(Intermediate properties) {
284612997fe2e41366573855f56898b27d4c8787244George Mount        try {
2853561e3e665698843b1c664385a842e779198960bGeorge Mount            FileObject intermediate = processingEnv.getFiler().createResource(
2863561e3e665698843b1c664385a842e779198960bGeorge Mount                    StandardLocation.CLASS_OUTPUT, ProcessBindable.class.getPackage().getName(),
2873561e3e665698843b1c664385a842e779198960bGeorge Mount                    "binding_properties.bin");
2883561e3e665698843b1c664385a842e779198960bGeorge Mount            ObjectOutputStream out = new ObjectOutputStream(intermediate.openOutputStream());
289612997fe2e41366573855f56898b27d4c8787244George Mount            out.writeObject(properties);
290612997fe2e41366573855f56898b27d4c8787244George Mount            out.close();
291612997fe2e41366573855f56898b27d4c8787244George Mount        } catch (IOException e) {
292612997fe2e41366573855f56898b27d4c8787244George Mount            processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
293612997fe2e41366573855f56898b27d4c8787244George Mount                    "Could not write to intermediate file: " + e.getLocalizedMessage());
294612997fe2e41366573855f56898b27d4c8787244George Mount        }
295612997fe2e41366573855f56898b27d4c8787244George Mount    }
296846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount
297846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount    private interface Intermediate {
298846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        void captureProperties(Set<String> properties);
299846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount
300846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        void cleanProperties(String className);
301846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount
302846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        void addProperty(String className, String propertyName);
303846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount    }
304846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount
305846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount    private static class IntermediateV1 implements Serializable, Intermediate {
306846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        private static final long serialVersionUID = 1L;
307846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount
308846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        private final HashMap<String, HashSet<String>> mProperties = new HashMap<>();
309846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount
310846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        @Override
311846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        public void captureProperties(Set<String> properties) {
312846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            for (HashSet<String> propertySet : mProperties.values()) {
313846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                properties.addAll(propertySet);
314846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            }
315846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        }
316846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount
317846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        @Override
318846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        public void cleanProperties(String className) {
319846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            mProperties.remove(className);
320846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        }
321846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount
322846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        @Override
323846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        public void addProperty(String className, String propertyName) {
324846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            HashSet<String> properties = mProperties.get(className);
325846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            if (properties == null) {
326846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                properties = new HashSet<>();
327846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount                mProperties.put(className, properties);
328846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            }
329846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount            properties.add(propertyName);
330846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount        }
331846795ea3e69eb482968cfea3312df04787c9bcfGeorge Mount    }
332b617e5da04aa910be70204afb886b1ebebb80618George Mount}
333