Package com.dp4j.processors

Source Code of com.dp4j.processors.SingletonProcessor

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.dp4j.processors;

import com.dp4j.*;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.*;
import java.util.Set;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
import javax.tools.Diagnostic.Kind;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;

/**
*
*  TODO: there must be only one instance, getInstance
* @author simpatico
*/
@SupportedAnnotationTypes(value = {"com.dp4j.Singleton", "org.jpatterns.gof.SingletonPattern", "com.google.code.annotation.pattern.design.creational.Singleton"}) //singleton
public class SingletonProcessor extends DProcessor {

    @Override
    protected void processElement(final Element e, TypeElement ann, boolean warningsOnly) {
        Set<Modifier> modifiers = e.getModifiers();
        if (modifiers.contains(Modifier.ABSTRACT)) {
            msgr.printMessage(Kind.ERROR, "a Singleton must not be abstract", e);
        }
        java.util.List<? extends Element> enclosedElements = e.getEnclosedElements();
        boolean getInstanceFound = false;
        boolean instanceFound = false;
        Element instanceElement = null;
        Name getInstanceMethName;
        Name instanceVarName;
        boolean lazy = false;//default
        if (ann.getQualifiedName().toString().equals(Singleton.class.getCanonicalName())) {
            final Singleton singleton = e.getAnnotation(Singleton.class);
            lazy = singleton.lazy();
            getInstanceMethName = elementUtils.getName(singleton.getInstance());
            instanceVarName = elementUtils.getName(singleton.instance());
        } else {
            getInstanceMethName = elementUtils.getName(getInstance.class.getSimpleName());
            instanceVarName = elementUtils.getName(getInstance.class.getSimpleName());
        }
        for (final Element element : enclosedElements) {
            if (element.getAnnotation(instance.class) != null) {
                if (instanceFound == true) {
                    msgr.printMessage(Kind.ERROR, "Found multiple methods annotated with @instance while at most one must be annotated", e);
                }
                instanceFound = true;
                instanceElement = element;
                instanceVarName = elementUtils.getName(element.getSimpleName());
            }

            if (element.getAnnotation(getInstance.class) != null) {
                if (getInstanceFound == true) {
                    msgr.printMessage(Kind.ERROR, "Found multiple methods annotated with @getInstance while at most one must be annotated", e);
                }
                getInstanceFound = true;
            }
        }

        if (instanceFound) {
            VariableTree tree = (VariableTree) trees.getTree(instanceElement);
            ExpressionTree initializer = tree.getInitializer();
            if (initializer == null) {
                lazy = true;
            } else {
                lazy = false; //default
            }
        }


        final Name singletonClassName = elementUtils.getName(e.getSimpleName());

        JCCompilationUnit singletonCU = (JCCompilationUnit) trees.getPath(e).getCompilationUnit();
        JCMethodDecl defCon = null;
        JCExpression defConInit = null;
        for (JCTree def : singletonCU.defs) {
            if (def instanceof JCClassDecl) {
                JCClassDecl singletonClass = (JCClassDecl) def;

                if (singletonClass.name.equals(singletonClassName)) {
                    for (JCTree singletonMethod : singletonClass.defs) {
                        try {
                            JCMethodDecl constructor = (JCMethodDecl) singletonMethod;
                            if (constructor.name.contentEquals("<init>")) {
                                if (constructor.params.isEmpty()) {
                                    defCon = constructor;
                                    if ((constructor.mods.flags & Flags.GENERATEDCONSTR) != 0) {
                                        defCon.mods = tm.Modifiers(Flags.PRIVATE);
                                    }
                                    defConInit = getEmptyArgsConstructor(defCon.sym);
                                }
                                if ((constructor.mods.flags & Flags.PRIVATE) == 0) {
                                    msgr.printMessage(Kind.ERROR, "For "+ singletonClassName + " to be a Singleton all its constructors must be private.");
                                    return;
                                }
                            }
                        } catch (ClassCastException ce) {
                            //it wasn't a method
                        }
                    }
                    final JCExpression instanceType = getId(singletonClassName);
                    tm.TypeApply(instanceType, null);

                    if (!instanceFound) {
                        if (defCon == null) {
                            msgr.printMessage(Kind.ERROR, "no singleton instance is declared for " + singletonClassName+ "and there is not any no-args constructor for me to declare one.");
                            return;
                        } else {
                            final JCTree instanceAnnTree = getIdentAfterImporting(instance.class);
                            final JCAnnotation instanceAnn = tm.Annotation(instanceAnnTree, List.<JCExpression>nil());
                            final JCExpression initVal;
                            long mod = Flags.PRIVATE + Flags.STATIC;
                            if (lazy) {
                                initVal = null;
                            } else {
                                initVal = defConInit;
                                mod += Flags.FINAL;
                            }
                            final JCModifiers instanceMods = tm.Modifiers(mod, List.of(instanceAnn));
                            final JCVariableDecl instance = tm.VarDef(instanceMods, instanceVarName, instanceType, initVal);
                            singletonClass.defs = singletonClass.defs.append(instance);
                            instanceFound = true;
                        }
                    }

                    if (!getInstanceFound) {
                        final JCIdent instance = tm.Ident(instanceVarName);
                        final JCStatement retType = tm.Return(instance);
                        final JCBlock body;
                        long mod = Flags.PUBLIC + Flags.STATIC;
                        if (lazy) {
                            JCAssign init = tm.Assign(instance, defConInit);
                            JCExpressionStatement thenStmt = tm.Exec(init);
                            JCIf initIf = getIfNull(instance, thenStmt);
                            body = tm.Block(0, List.of(initIf, retType));
                            mod += Flags.SYNCHRONIZED;
                        } else {
                            body = tm.Block(0, List.of(retType));
                        }
                        final List<JCVariableDecl> parameters = com.sun.tools.javac.util.List.nil();
                        final List<JCExpression> throwsClauses = com.sun.tools.javac.util.List.nil();
                        final JCTree getInstanceAnnTree = getIdentAfterImporting(getInstance.class);//tm.Ident(getInstanceAnnName);
                        final JCAnnotation getInstanceAnn = tm.Annotation(getInstanceAnnTree, List.<JCExpression>nil());
                        final JCExpression methodType = instanceType;

                        final JCMethodDecl getInstanceM = tm.MethodDef(tm.Modifiers(mod, List.of(getInstanceAnn)), getInstanceMethName, methodType, List.<JCTypeParameter>nil(), parameters, throwsClauses, body, null);

                        singletonClass.defs = singletonClass.defs.append(getInstanceM);
                    }
//                        JCTypeApply valueVarType = tm.TypeApply(singletonClass., List.<JCExpression>nil());
////                        JCNewClass newInstance = maker.NewClass(null, NIL_EXPRESSION, valueVarType, List.<JCExpression>of(field.init), null);
////                        JCStatement statement = maker.Exec(maker.Assign(maker.Ident(valueName), newInstance));
//
//                        instance.getType()

                }
            }
        }
        printVerbose(singletonCU, e);
    }
}
TOP

Related Classes of com.dp4j.processors.SingletonProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.