Android Open Source - GenDbHandler Gen Asyc Interface Annotation Processor






From Project

Back to project page GenDbHandler.

License

The source code is released under:

Open Data Commons ? Public Domain Dedication & Licence (PDDL) Preamble The Open Data Commons ? Public Domain Dedication & Licence is a document intended to allow you to freely share, modify, an...

If you think the Android project GenDbHandler listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package net.cattaka.util.genasyncif.apt;
//from  ww w  .  j ava  2s .  c om
import static javax.lang.model.util.ElementFilter.typesIn;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.ElementFilter;
import javax.tools.Diagnostic.Kind;
import javax.tools.JavaFileObject;

import net.cattaka.util.genasyncif.AsyncIfAttr;
import net.cattaka.util.genasyncif.GenAsyncInterface;

@SupportedSourceVersion(SourceVersion.RELEASE_6)
@SupportedAnnotationTypes("net.cattaka.util.genasyncif.*")
public class GenAsycInterfaceAnnotationProcessor extends AbstractProcessor {
    private static class ArgType {
        String typeName;

        String innerTypeName;

        String hiddenTypeName;

        boolean isGenerics;

        private ArgType(String typeName, String innerTypeName) {
            super();
            this.typeName = typeName;
            this.innerTypeName = innerTypeName;
            this.hiddenTypeName = innerTypeName;
            isGenerics = false;
        }

        private ArgType(String typeName, String innerTypeName, String hiddenTypeName,
                boolean isGenerics) {
            super();
            this.typeName = typeName;
            this.innerTypeName = innerTypeName;
            this.hiddenTypeName = hiddenTypeName;
            this.isGenerics = isGenerics;
        }

        @Override
        public String toString() {
            return "ArgType [" + typeName + ", " + innerTypeName + ", " + hiddenTypeName + "]";
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((typeName == null) ? 0 : typeName.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            ArgType other = (ArgType)obj;
            if (typeName == null) {
                if (other.typeName != null)
                    return false;
            } else if (!typeName.equals(other.typeName))
                return false;
            return true;
        }
    }

    private static class InterfaceInfo {
        String packageName;

        String interfaceName;

        String asyncClassName;

        String fullGenerics;

        String shortGenerics;

        public InterfaceInfo(String packageName, String interfaceName, String asyncClassName,
                String fullGenerics, String shortGenerics) {
            super();
            this.packageName = packageName;
            this.interfaceName = interfaceName;
            this.asyncClassName = asyncClassName;
            this.fullGenerics = fullGenerics;
            this.shortGenerics = shortGenerics;
        }

        @Override
        public String toString() {
            return "InterfaceInfo [packageName=" + packageName + ", className=" + interfaceName
                    + ", asyncClassName=" + asyncClassName + "]";
        }

    }

    private static class MethodInfo {
        boolean needSync;

        String methodName;

        String genericsDeclare;

        String eventName;

        List<ArgType> argTypes;

        List<String> throwsList;

        ArgType returnType;

        public MethodInfo(boolean needSync, String methodName, String genericsDeclare,
                String eventName, List<ArgType> argTypes, List<String> throwsList,
                ArgType returnType) {
            super();
            this.needSync = needSync;
            this.methodName = methodName;
            this.genericsDeclare = genericsDeclare;
            this.eventName = eventName;
            this.argTypes = argTypes;
            this.throwsList = throwsList;
            this.returnType = returnType;
        }

        @Override
        public String toString() {
            return "MethodInfo [methodName=" + methodName + ", argTypes=" + argTypes
                    + ", throwsList=" + throwsList + ", returnType=" + returnType + "]";
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((argTypes == null) ? 0 : argTypes.hashCode());
            result = prime * result + ((methodName == null) ? 0 : methodName.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            MethodInfo other = (MethodInfo)obj;
            if (argTypes == null) {
                if (other.argTypes != null)
                    return false;
            } else if (!argTypes.equals(other.argTypes))
                return false;
            if (methodName == null) {
                if (other.methodName != null)
                    return false;
            } else if (!methodName.equals(other.methodName))
                return false;
            return true;
        }

    }

    private String mTemplate;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);

        InputStream in = getClass().getResourceAsStream("template.txt");
        try {
            Reader reader = new InputStreamReader(in, "UTF-8");
            StringBuilder sb = new StringBuilder();
            char[] buf = new char[1 << 12];
            int r;
            while ((r = reader.read(buf)) > 0) {
                sb.append(buf, 0, r);
            }
            mTemplate = sb.toString();
        } catch (IOException e) {
            processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage());
            throw new RuntimeException(e);
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage());
            }
        }
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (TypeElement element : typesIn(roundEnv
                .getElementsAnnotatedWith(GenAsyncInterface.class))) {
            try {
                processElement(element);
            } catch (IOException e) {
                processingEnv.getMessager().printMessage(Kind.ERROR,
                        "Only single primary key is supported.", element);
            }
        }
        return true;
    }

    private void processElement(TypeElement srcElement) throws IOException {
        GenAsyncInterface gai = srcElement.getAnnotation(GenAsyncInterface.class);
        String packageName = getPackageName(srcElement);
        List<? extends TypeParameterElement> typeParameters = srcElement.getTypeParameters();
        String fullGenerics = "";
        String shortGenerics = "";
        if (typeParameters.size() > 0) {
            fullGenerics = createGenericsDeclare(typeParameters, true);
            shortGenerics = createGenericsDeclare(typeParameters, false);

        }
        String interfaceName = String.valueOf(srcElement.getSimpleName());
        String asyncClassName = gai.prefix() + srcElement.getSimpleName() + gai.suffix();
        String qualifiedName = packageName + ".async." + asyncClassName;

        InterfaceInfo interfaceInfo = new InterfaceInfo(packageName, interfaceName, asyncClassName,
                fullGenerics, shortGenerics);

        Filer filer = processingEnv.getFiler();
        JavaFileObject fileObject = filer.createSourceFile(qualifiedName, srcElement);
        PrintWriter writer = new PrintWriter(fileObject.openWriter());
        try {
            generateCode(gai, srcElement, writer, interfaceInfo);
        } finally {
            writer.close();
        }

    }

    private void generateCode(GenAsyncInterface gai, TypeElement srcElement, PrintWriter writer,
            InterfaceInfo info) throws IOException {
        List<MethodInfo> methodInfos = pullMethodInfos(srcElement);
        String packageName = info.packageName + ".async";
        String importLines = "import " + info.packageName + "." + info.interfaceName + ";";
        String asyncClassName = info.asyncClassName;
        String interfaceName = info.interfaceName;
        String methodEventLines = "";
        String suppressWarnings = "";

        boolean useAsyncInterfaceException = false;
        {
            for (MethodInfo mi : methodInfos) {
                if (mi.needSync) {
                    useAsyncInterfaceException = true;
                    break;
                }
            }
            if (useAsyncInterfaceException) {
                importLines += "\nimport net.cattaka.util.genasyncif.AsyncInterfaceException;";
            }
        }
        {
            Set<String> items = new TreeSet<String>();
            if (info.fullGenerics.length() > 0) {
                items.add("rawtypes");
            }
            outer: for (MethodInfo mi : methodInfos) {
                if (mi.genericsDeclare.length() > 0) {
                    items.add("unchecked");
                    break outer;
                }
                for (ArgType at : mi.argTypes) {
                    if (at.isGenerics) {
                        items.add("unchecked");
                        break outer;
                    }
                }
            }
            if (items.size() > 0) {
                StringBuilder sb = new StringBuilder();
                int c = 0;
                sb.append("        @SuppressWarnings({");
                for (String item : items) {
                    if (c > 0) {
                        sb.append(',');
                    }
                    sb.append('"');
                    sb.append(item);
                    sb.append('"');
                    c++;
                }
                sb.append("})");
                suppressWarnings = sb.toString();
            }
        }

        for (int i = 0; i < methodInfos.size(); i++) {
            MethodInfo mi = methodInfos.get(i);
            methodEventLines += "    private static final int " + mi.eventName
                    + " = EVENT_START + " + i + ";\n";
        }
        String methodLines;
        int workSize = 0;
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < methodInfos.size(); i++) {
                MethodInfo mi = methodInfos.get(i);
                workSize = Math.max(workSize, mi.argTypes.size() + 4);
                sb.append("    @Override\n");
                sb.append("    public " + mi.genericsDeclare + mi.returnType.typeName + " "
                        + mi.methodName + "(");
                for (int j = 0; j < mi.argTypes.size(); j++) {
                    ArgType arg = mi.argTypes.get(j);
                    if (j > 0) {
                        sb.append(", ");
                    }
                    sb.append(arg.typeName + " arg" + j);
                }
                sb.append(")");
                if (mi.throwsList.size() > 0) {
                    sb.append(" throws ");
                    for (int j = 0; j < mi.throwsList.size(); j++) {
                        if (j > 0) {
                            sb.append(", ");
                        }
                        sb.append(mi.throwsList.get(0));
                    }

                }
                sb.append(" {\n");
                sb.append("        Object[] work = obtain();\n");
                sb.append("        work[0] = this;\n");
                sb.append("        work[1] = orig;\n");
                for (int j = 0; j < mi.argTypes.size(); j++) {
                    // ArgType arg = mi.argTypes.get(j);
                    sb.append("        work[" + (j + 2) + "] = arg" + j + ";\n");
                }
                if (!mi.needSync) {
                    sb.append("        mHandler.obtainMessage(" + mi.eventName
                            + ", work).sendToTarget();\n");
                } else {
                    sb.append("        synchronized (work) {\n");
                    sb.append("            mHandler.obtainMessage(" + mi.eventName + ", work)\n");
                    sb.append("                    .sendToTarget();\n");
                    sb.append("            try {\n");
                    sb.append("                work.wait();\n");
                    sb.append("            } catch (InterruptedException e) {\n");
                    sb.append("                throw new AsyncInterfaceException(e);\n");
                    sb.append("            }\n");
                    sb.append("        }\n");
                    sb.append("        if (work[WORK_SIZE - 1] != null) {\n");
                    if (mi.throwsList.size() == 0) {
                        sb.append("            throw new AsyncInterfaceException((Exception) work[WORK_SIZE - 1]);\n");
                    } else {
                        for (int j = 0; j < mi.throwsList.size(); j++) {
                            String t = mi.throwsList.get(j);
                            sb.append("            ");
                            if (j > 0) {
                                sb.append("} else ");
                            }
                            sb.append("if (work[WORK_SIZE - 1] instanceof " + t + ") {\n");
                            sb.append("                throw (" + t + ") work[WORK_SIZE - 1];\n");
                        }
                        sb.append("            } else {\n");
                        sb.append("                throw new AsyncInterfaceException((Exception) work[WORK_SIZE - 1]);\n");
                        sb.append("            }\n");
                    }
                    sb.append("        }\n");
                    if (!"void".equalsIgnoreCase(mi.returnType.typeName)) {
                        if (mi.returnType.isGenerics) {
                            sb.append("        @SuppressWarnings(\"unchecked\")\n");
                        }
                        sb.append("        " + mi.returnType.typeName + " result = ("
                                + mi.returnType.innerTypeName + ") work[WORK_SIZE - 2];\n");
                    }
                    sb.append("        recycle(work);\n");
                    if (!"void".equalsIgnoreCase(mi.returnType.typeName)) {
                        sb.append("        return result;\n");
                    }
                }
                sb.append("    }\n");
            }
            methodLines = sb.toString();
        }
        String caseLines;
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < methodInfos.size(); i++) {
                MethodInfo mi = methodInfos.get(i);
                sb.append("            case " + mi.eventName + ": {\n");
                sb.append("                Object[] work = (Object[]) msg.obj;\n");
                if (!mi.needSync) {
                    sb.append("                ${asyncClassName} me = (${asyncClassName}) work[0];\n");
                }
                sb.append("                ${interfaceName} orig = (${interfaceName}) work[1];\n");
                for (int j = 0; j < mi.argTypes.size(); j++) {
                    ArgType arg = mi.argTypes.get(j);
                    sb.append("                " + arg.hiddenTypeName + " arg" + j + " = ("
                            + arg.hiddenTypeName + ") (work[" + (j + 2) + "]);\n");
                }

                if (!mi.needSync) {
                    sb.append("                orig." + mi.methodName + "(");
                    for (int j = 0; j < mi.argTypes.size(); j++) {
                        if (j > 0) {
                            sb.append(" ,");
                        }
                        sb.append("arg" + j);
                    }
                    sb.append(");\n");
                    sb.append("                me.recycle(work);\n");
                    sb.append("                return true;\n");
                } else {
                    sb.append("                try {\n");
                    sb.append("                    ");
                    if (!"void".equalsIgnoreCase(mi.returnType.typeName)) {
                        sb.append("Object result = ");
                    }
                    sb.append("orig." + mi.methodName + "(");
                    for (int j = 0; j < mi.argTypes.size(); j++) {
                        if (j > 0) {
                            sb.append(" ,");
                        }
                        sb.append("arg" + j);
                    }
                    sb.append(");\n");
                    if (!"void".equalsIgnoreCase(mi.returnType.typeName)) {
                        sb.append("                    work[WORK_SIZE - 2] = result;\n");
                    }
                    sb.append("                } catch (Exception e) {\n");
                    sb.append("                    work[WORK_SIZE - 1] = e;\n");
                    sb.append("                }\n");
                    sb.append("                synchronized (work) {\n");
                    sb.append("                    work.notify();\n");
                    sb.append("                }\n");
                    sb.append("                return true;\n");
                }
                sb.append("            }\n");
            }
            caseLines = sb.toString();
        }

        StringBuilder sb = new StringBuilder(mTemplate);
        replaceStringBuilder(sb, "${importLines}", importLines);
        replaceStringBuilder(sb, "${caseLines}", caseLines);
        replaceStringBuilder(sb, "${methodEventLines}", methodEventLines);
        replaceStringBuilder(sb, "${methodLines}", methodLines);
        replaceStringBuilder(sb, "${packageName}", packageName);
        replaceStringBuilder(sb, "${asyncClassName}", asyncClassName);
        replaceStringBuilder(sb, "${interfaceName}", interfaceName);
        replaceStringBuilder(sb, "${fullGenerics}", info.fullGenerics);
        replaceStringBuilder(sb, "${shortGenerics}", info.shortGenerics);
        replaceStringBuilder(sb, "${poolSize}", String.valueOf(gai.poolSize()));
        replaceStringBuilder(sb, "${suppressWarnings}", suppressWarnings);
        replaceStringBuilder(sb, "${workSize}", String.valueOf(workSize));

        writer.print(sb.toString());
    }

    public static List<MethodInfo> pullMethodInfos(TypeElement rootElement) {
        List<MethodInfo> methodInfos = new ArrayList<MethodInfo>();
        List<TypeElement> interfaces = pullInterfaces(rootElement);
        Set<MethodInfo> existMethodInfos = new HashSet<MethodInfo>();
        int count = 0;
        for (TypeElement element : interfaces) {
            for (ExecutableElement method : ElementFilter.methodsIn(element.getEnclosedElements())) {
                AsyncIfAttr attr = method.getAnnotation(AsyncIfAttr.class);
                if (attr != null && attr.ignore()) {
                    continue;
                }

                String methodName = method.getSimpleName().toString();
                String eventName = "EVENT_METHOD_" + count + "_" + methodName;
                String genericsDeclare = "";
                List<? extends TypeParameterElement> tps = method.getTypeParameters();
                if (tps.size() > 0) {
                    genericsDeclare = createGenericsDeclare(tps, true) + "";
                }

                List<ArgType> argTypes = new ArrayList<ArgType>();
                for (VariableElement arg : method.getParameters()) {
                    argTypes.add(createArgType(arg.asType()));
                }
                // for (TypeParameterElement arg : method.getTypeParameters()) {
                // }

                List<String> throwsList = new ArrayList<String>();
                for (TypeMirror tm : method.getThrownTypes()) {
                    throwsList.add(pickQualifiedName(tm));
                }

                ArgType returnType = createArgType(method.getReturnType());
                boolean needSync = !"void".equalsIgnoreCase(returnType.typeName)
                        || (throwsList.size() > 0);

                if (attr != null) {
                    if (attr.forceSync()) {
                        needSync = true;
                    }
                }

                MethodInfo methodInfo = new MethodInfo(needSync, methodName, genericsDeclare,
                        eventName, argTypes, throwsList, returnType);
                if (existMethodInfos.add(methodInfo)) {
                    methodInfos.add(methodInfo);
                    count++;
                }
            }
        }
        return methodInfos;
    }

    public static List<TypeElement> pullInterfaces(TypeElement root) {
        List<TypeElement> dts = new ArrayList<TypeElement>();
        List<TypeElement> tmp = new LinkedList<TypeElement>();
        tmp.add(root);
        while (tmp.size() > 0) {
            TypeElement dt = tmp.remove(0);
            dts.add(dt);
            List<? extends TypeMirror> tms = dt.getInterfaces();
            for (TypeMirror tm : tms) {
                if (tm instanceof DeclaredType) {
                    Element ele = ((DeclaredType)tm).asElement();
                    if (ele instanceof TypeElement) {
                        tmp.add((TypeElement)ele);
                    }
                }
            }
        }
        return dts;
    }

    private static ArgType createArgType(TypeParameterElement tpe) {
        List<? extends TypeMirror> tms = tpe.getBounds();
        ArgType at = null;
        for (TypeMirror tm : tms) {
            at = createArgType(tm);
            break;
        }

        String name = String.valueOf(tpe);
        if (at != null && !Object.class.getName().equals(at.typeName)) {
            return new ArgType(name, name + " extends " + at.typeName, "Object", true);
        } else {
            return new ArgType(name, name, "Object", true);
        }
    }

    private static ArgType createArgType(TypeMirror tm) {
        switch (tm.getKind()) {
            case BOOLEAN:
                return new ArgType("boolean", "Boolean");
            case BYTE:
                return new ArgType("byte", "Byte");
            case CHAR:
                return new ArgType("char", "Char");
            case SHORT:
                return new ArgType("short", "Short");
            case INT:
                return new ArgType("int", "Integer");
            case LONG:
                return new ArgType("long", "Long");
            case FLOAT:
                return new ArgType("float", "Float");
            case DOUBLE:
                return new ArgType("double", "Double");
            case VOID:
                return new ArgType("void", "Void");
            case TYPEVAR:
                String t = String.valueOf(((TypeVariable)tm).asElement());
                // String l =
                // String.valueOf(((TypeVariable)tm).getLowerBound());
                String u = String.valueOf(((TypeVariable)tm).getUpperBound());
                return new ArgType(t, t, u, true);
            case DECLARED: {
                String hiddenName = pickQualifiedName(tm);
                String name = String.valueOf(tm);
                DeclaredType dt = (DeclaredType)tm;
                List<? extends TypeMirror> tms = dt.getTypeArguments();
                if (tms.size() > 0) {
                    hiddenName += createHiddenGenericsDeclare(tms.size());
                    return new ArgType(name, name, hiddenName, true);
                } else {
                    return new ArgType(name, name, hiddenName, false);
                }
            }
            default: {
                String name = pickQualifiedName(tm);
                return new ArgType(name, name);
            }
        }
    }

    private static String createGenericsDeclare(List<? extends TypeMirror> tms) {
        StringBuilder sb = new StringBuilder();
        List<ArgType> ats = new ArrayList<ArgType>();
        for (TypeMirror tm : tms) {
            if (sb.length() > 0) {
                sb.append(",");
            }
            sb.append(createArgType(tm).typeName);
        }
        return sb.toString();
    }

    private static String createGenericsDeclare(
            List<? extends TypeParameterElement> typeParameters, boolean full) {
        StringBuilder sb = new StringBuilder();
        {
            for (TypeParameterElement tpe : typeParameters) {
                ArgType at = createArgType(tpe);
                if (sb.length() > 0) {
                    sb.append(',');
                }
                if (full) {
                    sb.append(at.innerTypeName);
                } else {
                    sb.append(at.typeName);
                }
            }
        }
        return '<' + sb.toString() + '>';
    }

    private static String createHiddenGenericsDeclare(int n) {
        StringBuilder sb = new StringBuilder();
        sb.append('<');
        for (int i = 0; i < n; i++) {
            if (i > 0) {
                sb.append(',');
            }
            sb.append('?');
        }
        sb.append('>');
        return sb.toString();
    }

    private static String pickQualifiedName(TypeMirror src) {
        if (src instanceof PrimitiveType) {
            return ((PrimitiveType)src).getKind().name().toLowerCase();
        } else if (src instanceof ArrayType) {
            return pickQualifiedName(((ArrayType)src).getComponentType()) + "[]";
        } else if (src instanceof DeclaredType) {
            Element element = ((DeclaredType)src).asElement();
            return getPackageName(element) + "." + String.valueOf(element.getSimpleName());
        }
        return null;
    }

    public static String getPackageName(Element element) {
        while (!(element instanceof PackageElement)) {
            element = element.getEnclosingElement();
        }
        return ((PackageElement)element).getQualifiedName().toString();
    }

    private static void replaceStringBuilder(StringBuilder sb, String target, String replacement) {
        int start = 0;
        while (true) {
            start = sb.indexOf(target, start);
            if (start >= 0) {
                sb.replace(start, start + target.length(), replacement);
            } else {
                break;
            }
        }
    }
}




Java Source Code List

net.cattaka.util.genasyncif.AsyncIfAttr.java
net.cattaka.util.genasyncif.AsyncInterfaceException.java
net.cattaka.util.genasyncif.GenAsyncInterface.java
net.cattaka.util.genasyncif.apt.GenAsycInterfaceAnnotationProcessor.java
net.cattaka.util.gendbhandler.Accessor.java
net.cattaka.util.gendbhandler.Attribute.java
net.cattaka.util.gendbhandler.GenDbHandler.java
net.cattaka.util.gendbhandler.apt.Bug300408.java
net.cattaka.util.gendbhandler.apt.Converter.java
net.cattaka.util.gendbhandler.apt.GenDbHandlerAnnotationProcessor.java
net.cattaka.util.gendbhandler.apt.InnerFieldType.java
net.cattaka.util.genparcelfunc.GenParcelFuncAnnotationProcessorFactory.java
net.cattaka.util.genparcelfunc.GenParcelFuncAnnotationProcessor.java
net.cattaka.util.genparcelfunc.GenParcelFuncPlugin.java
net.cattaka.util.genparcelfunc.GenParcelFunc.java
net.cattaka.util.genparcelfunc.ParcelFuncAttr.java