com.javasimple.parser.JavaClassTransformer.java Source code

Java tutorial

Introduction

Here is the source code for com.javasimple.parser.JavaClassTransformer.java

Source

/**
 * *****************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Camilo Alvarez
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Contributors: Camilo Alvarez - initial API and implementation
 ******************************************************************************
 */
package com.javasimple.parser;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

import org.antlr.v4.runtime.ANTLRFileStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;

import com.javasimple.Annotation;
import com.javasimple.AnnotationMethod;
import com.javasimple.AnnotationParam;
import com.javasimple.AnnotationParamValueAnnotation;
import com.javasimple.AnnotationParamValueArray;
import com.javasimple.AnnotationParamValueExpression;
import com.javasimple.AnnotationType;
import com.javasimple.ClassConstructor;
import com.javasimple.ClassOrInterface;
import com.javasimple.Documentable;
import com.javasimple.Documentation;
import com.javasimple.EnumConstant;
import com.javasimple.JavaClass;
import com.javasimple.JavaEnumeration;
import com.javasimple.JavaField;
import com.javasimple.JavaImport;
import com.javasimple.JavaInterface;
import com.javasimple.JavaMethod;
import com.javasimple.JavasimpleFactory;
import com.javasimple.JavasimplePackage;
import com.javasimple.Modifier;
import com.javasimple.NamedElement;
import com.javasimple.Parameter;
import com.javasimple.StructuralElement;
import com.javasimple.parser.java.JavaBaseListener;
import com.javasimple.parser.java.JavaLexer;
import com.javasimple.parser.java.JavaParser;
import com.javasimple.parser.java.JavaParser.ClassBodyDeclarationContext;
import com.javasimple.parser.java.JavaParser.TypeDeclarationContext;
import com.javasimple.parser.java.JavaParser.VariableInitializerContext;
import com.javasimple.parser.javadoc.JavadocParser;

/**
 *
 * @author cadmilo
 */
public final class JavaClassTransformer {

    public static void parse(final JavaApplicationTransformer app, final String fileName) throws IOException {
        final ANTLRFileStream fileStream = new ANTLRFileStream(fileName);
        final JavaLexer lexer = new JavaLexer(fileStream);
        final CommonTokenStream tokenStream = new CommonTokenStream(lexer);
        final JavaParser parser = new JavaParser(tokenStream);
        final JavaBaseListener listener;
        final LinkedList<TypeReference> unresolvedTypeReferences = new LinkedList<TypeReference>();
        listener = new JavaBaseListener() {

            // Handle JavaClass Declaration
            private String packageName;
            private List<String> imports;
            private Stack<Object> processStack;
            private int declaredElements = 0;

            private boolean processingBlock() {
                return !processStack.isEmpty() && processStack.peek() instanceof Boolean;
            }

            @Override
            public void enterBlock(JavaParser.BlockContext ctx) {
                processStack.push(true);
            }

            @Override
            public void exitBlock(JavaParser.BlockContext ctx) {
                if (processStack.size() >= 2) {
                    Object element = processStack.get(processStack.size() - 2);
                    if (element instanceof StringBuilder) {
                        // Process method/constructor source code
                        Utils.convertirTexto(ctx.children, (StringBuilder) element);
                    }
                }
                processStack.pop();
            }

            @Override
            public void enterClassCreatorRest(JavaParser.ClassCreatorRestContext ctx) {
                processStack.push(true);
            }

            @Override
            public void exitClassCreatorRest(JavaParser.ClassCreatorRestContext ctx) {
                processStack.pop();
            }

            //
            // @Override
            // public void enterMethodBody(JavaParser.MethodBodyContext ctx) {
            // classStack.push(true);
            // }
            //
            // @Override
            // public void exitMethodBody(JavaParser.MethodBodyContext ctx) {
            // classStack.pop();
            // }
            //
            @Override
            public void enterConstructorBody(JavaParser.ConstructorBodyContext ctx) {
                if (processingBlock()) {
                    return;
                }
                processStack.add(new StringBuilder());
            }

            @Override
            public void enterMethodBody(JavaParser.MethodBodyContext ctx) {
                if (processingBlock()) {
                    return;
                }
                processStack.push(new StringBuilder());
            }

            @Override
            public void enterCompilationUnit(JavaParser.CompilationUnitContext ctx) {
                imports = new ArrayList<String>();
                processStack = new Stack();
            }

            @Override
            public void exitPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
                packageName = ctx.qualifiedName().getText();
            }

            @Override
            public void exitImportDeclaration(JavaParser.ImportDeclarationContext ctx) {
                final String importText = ctx.getText();
                // from 6 to discard 'import'
                // Until length-1 to discard ';'
                imports.add(importText.substring(6, importText.length() - 1));
            }

            @Override
            public void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                processStack.push(null);
                declaredElements++;
            }

            @Override
            public void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                processStack.push(null);
                declaredElements++;
            }

            @Override
            public void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                processStack.push(null);
            }

            @Override
            public void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                processStack.push(null);
                declaredElements++;
            }

            @Override
            public void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                try {
                    JavaInterface javaInterface;
                    if (declaredElements == 1) {
                        javaInterface = (JavaInterface) app.createJavaElement(SymbolType.Interface, packageName,
                                ctx.Identifier().getText());
                    } else {
                        javaInterface = (JavaInterface) JavasimpleFactory.eINSTANCE.createJavaInterface();
                        javaInterface.setName(ctx.Identifier().getText());
                        declaredElements--;
                    }
                    if (ctx.typeList() != null) {
                        for (JavaParser.TypeContext typeContext : ctx.typeList().type()) {
                            registerUnresolvedReference(javaInterface, SymbolType.Interface,
                                    JavasimplePackage.eINSTANCE.getJavaInterface_InheritedInterfaces(),
                                    typeContext);
                        }
                    }
                    processClassOrInteface(javaInterface);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                try {
                    JavaEnumeration javaEnumeration;
                    if (declaredElements == 1) {
                        javaEnumeration = (JavaEnumeration) app.createJavaElement(SymbolType.Enumeration,
                                packageName, ctx.Identifier().getText());
                        declaredElements--;
                    } else {
                        javaEnumeration = (JavaEnumeration) JavasimpleFactory.eINSTANCE.createJavaEnumeration();
                        javaEnumeration.setName(ctx.Identifier().getText());
                        declaredElements--;
                    }
                    processClassOrInteface(javaEnumeration);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                try {
                    JavaClass javaClass;
                    if (declaredElements == 1) {
                        javaClass = (JavaClass) app.createJavaElement(SymbolType.Class, packageName,
                                ctx.Identifier().getText());
                    } else {
                        // System.out.println("Inner Class " + fileName + "--->"
                        // + ctx.Identifier().getText());
                        javaClass = JavasimpleFactory.eINSTANCE.createJavaClass();
                        javaClass.setName(ctx.Identifier().getText());
                        javaClass.setPackageName(fileName);
                    }
                    declaredElements--;
                    registerUnresolvedReference(javaClass, SymbolType.Class,
                            JavasimplePackage.eINSTANCE.getJavaClass_SuperClass(), ctx.type());
                    if (ctx.typeList() != null) {
                        for (JavaParser.TypeContext typeContext : ctx.typeList().type()) {
                            registerUnresolvedReference(javaClass, SymbolType.Interface,
                                    JavasimplePackage.eINSTANCE.getJavaClass_Implements(), typeContext);
                        }
                    }
                    processClassOrInteface(javaClass);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                try {
                    AnnotationType aType = (AnnotationType) app.createJavaElement(SymbolType.AnnotationType,
                            packageName, ctx.Identifier().getText());
                    processClassOrInteface(aType);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }

            private void processClassOrInteface(ClassOrInterface element) {
                try {
                    Object top;
                    while (!processStack.isEmpty() && (top = processStack.pop()) != null) {
                        if (top instanceof ClassConstructor) {
                            if (element instanceof JavaClass) {
                                ((JavaClass) element).getConstructors().add(0, (ClassConstructor) top);
                            } else if (top instanceof JavaClass) {
                                ((JavaEnumeration) element).getConstructors().add(0, (ClassConstructor) top);
                            }
                        } else if (top instanceof JavaInterface) {
                            element.getInnerInterfaces().add(0, (JavaInterface) top);
                        } else if (top instanceof JavaEnumeration) {
                            element.getInnerEnumerations().add(0, (JavaEnumeration) top);
                        } else if (top instanceof AnnotationType) {
                            element.getInnerAnotationTypes().add(0, (AnnotationType) top);
                        } else if (top instanceof JavaClass) {
                            element.getInnerClasses().add(0, (JavaClass) top);
                        } else if (top instanceof JavaField) {
                            element.getFields().add(0, (JavaField) top);
                        } else if (top instanceof JavaMethod) {
                            element.getMethods().add(0, (JavaMethod) top);
                        } else if (top instanceof EnumConstant) {
                            ((JavaEnumeration) element).getConstans().add(0, (EnumConstant) top);
                        } else if (top instanceof AnnotationMethod) {
                            ((AnnotationType) element).getAnnotationsMethods().add(0, (AnnotationMethod) top);
                        } else if (top instanceof Documentation) {
                            ((Documentable) element).setDocumentation((Documentation) top);
                        } else {
                            throw new RuntimeException("UnProcess element in the stack :" + top);
                        }
                    }
                    processModifiers(element);
                    if (processStack.isEmpty()) {
                        // System.out.println("End to ptocess: " + fileName);
                        for (String importName : imports) {
                            final JavaImport importV = JavasimpleFactory.eINSTANCE.createJavaImport();
                            importV.setName(importName);
                            element.getImports().add(0, importV);
                        }
                    }
                    processStack.push(element);
                    // If is the main element register all subclases
                    if (declaredElements == 0) {
                        registerInnerElements(element);
                    }
                } catch (Exception e) {
                    System.out.println("----->" + fileName + "<------");
                    System.out.println(element.getName());
                    System.out.println(processStack);
                    e.printStackTrace();
                }
            }

            private void registerInnerElements(ClassOrInterface element) {
                registerElements(element.getInnerClasses());
                registerElements(element.getInnerAnotationTypes());
                registerElements(element.getInnerEnumerations());
                registerElements(element.getInnerInterfaces());
            }

            private void registerElements(List elements) {
                for (Object elementi : elements) {
                    app.registerInnerElement(((ClassOrInterface) elementi).getQualifiedName(), elementi);
                    registerInnerElements((ClassOrInterface) elementi);
                }
            }

            @Override
            public void exitEnumConstant(JavaParser.EnumConstantContext ctx) {
                if (processingBlock()) {
                    return;
                }
                final EnumConstant enumConstant = JavasimpleFactory.eINSTANCE.createEnumConstant();
                enumConstant.setName(ctx.Identifier().getText());
                processModifiers(enumConstant);
                processStack.push(enumConstant);
            }

            @Override
            public void exitConstDeclaration(JavaParser.ConstDeclarationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                try {
                    final ArrayList<String> fieldsNames = new ArrayList<String>(ctx.constantDeclarator().size());
                    final ArrayList<VariableInitializerContext> defaultValues = new ArrayList<VariableInitializerContext>(
                            ctx.constantDeclarator().size());
                    final ArrayList<Boolean> arrayFlags = new ArrayList<Boolean>(ctx.constantDeclarator().size());
                    for (JavaParser.ConstantDeclaratorContext constantDeclaratorContext : ctx
                            .constantDeclarator()) {
                        fieldsNames.add(constantDeclaratorContext.Identifier().getText());
                        if (constantDeclaratorContext.variableInitializer() != null) {
                            defaultValues.add(constantDeclaratorContext.variableInitializer());
                        } else {
                            defaultValues.add(null);
                        }
                        if (constantDeclaratorContext.getText().split("=")[0].endsWith("[]")) {
                            arrayFlags.add(true);
                        } else {
                            arrayFlags.add(false);
                        }
                    }
                    processFieldDeclaration(ctx.type(), fieldsNames, defaultValues, arrayFlags);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void exitAnnotationTypeElementRest(JavaParser.AnnotationTypeElementRestContext ctx) {
                if (processingBlock()) {
                    return;
                }
                if (ctx.type() != null) {
                    if (ctx.annotationMethodOrConstantRest() != null) {
                        if (ctx.annotationMethodOrConstantRest().annotationMethodRest() != null) {
                            final JavaParser.AnnotationMethodRestContext restContext = ctx
                                    .annotationMethodOrConstantRest().annotationMethodRest();
                            final AnnotationMethod method = JavasimpleFactory.eINSTANCE.createAnnotationMethod();
                            method.setName(restContext.Identifier().getText());
                            if (processStack.peek() instanceof AnnotationParam) {
                                method.setDefaultValue((AnnotationParam) processStack.pop());
                            }
                            // TODO: Check
                            registerUnresolvedReference(method, SymbolType.Class,
                                    JavasimplePackage.eINSTANCE.getAnnotationMethod_Type(), ctx.type());
                            // method.setType();
                            method.setArray(isArray(ctx.type()));
                            processModifiers(method);
                            processStack.push(method);
                        } else if (ctx.annotationMethodOrConstantRest().annotationConstantRest() != null) {
                            JavaParser.AnnotationConstantRestContext restContext = ctx
                                    .annotationMethodOrConstantRest().annotationConstantRest();
                            processVariableDeclarators(ctx.type(), restContext.variableDeclarators());
                        }
                    }

                }
            }

            @Override
            public void exitFieldDeclaration(JavaParser.FieldDeclarationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                processVariableDeclarators(ctx.type(), ctx.variableDeclarators());
            }

            private void processVariableDeclarators(JavaParser.TypeContext typeContext,
                    JavaParser.VariableDeclaratorsContext ctx) {
                try {
                    final ArrayList<String> fieldsNames = new ArrayList<String>(ctx.variableDeclarator().size());
                    final ArrayList<VariableInitializerContext> defaultValues = new ArrayList<VariableInitializerContext>(
                            ctx.variableDeclarator().size());
                    final ArrayList<Boolean> arrayFlags = new ArrayList<Boolean>(ctx.variableDeclarator().size());
                    for (JavaParser.VariableDeclaratorContext variableDeclaratorContext : ctx
                            .variableDeclarator()) {
                        fieldsNames.add(variableDeclaratorContext.variableDeclaratorId().Identifier().getText());
                        if (variableDeclaratorContext.variableInitializer() != null) {
                            defaultValues.add(variableDeclaratorContext.variableInitializer());
                        } else {
                            defaultValues.add(null);
                        }
                        if (variableDeclaratorContext.variableDeclaratorId().getText().endsWith("[]")) {
                            arrayFlags.add(true);
                        } else {
                            arrayFlags.add(false);
                        }
                    }
                    processFieldDeclaration(typeContext, fieldsNames, defaultValues, arrayFlags);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            private void processFieldDeclaration(final JavaParser.TypeContext typeContext,
                    final List<String> fieldsNames, final List<VariableInitializerContext> defaultValues,
                    final List<Boolean> arrayFlags) {
                try {
                    // final com.javasimple.Type type = getType(typeContext);
                    for (int i = 0; i < fieldsNames.size(); i++) {
                        final String fieldName = fieldsNames.get(i);
                        final VariableInitializerContext defaultValue = defaultValues.get(i);
                        final boolean isArray = arrayFlags.get(i);
                        final JavaField field = JavasimpleFactory.eINSTANCE.createJavaField();
                        registerUnresolvedReference(field, SymbolType.Class,
                                JavasimplePackage.eINSTANCE.getJavaField_Type(), typeContext);
                        // field.setType(type);
                        field.setName(fieldName);
                        if (defaultValue != null) {
                            final String expression = app.handler.processFieldDefaultValueExpression(defaultValue);
                            field.setDefaultValue(expression);
                        }
                        if (isArray(typeContext) || isArray) {
                            field.setArray(true);
                        } else {
                            field.setArray(false);
                        }
                        // TODO: FIX IT It should apply to all the fields
                        processModifiers(field);
                        processStack.push(field);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void exitEveryRule(ParserRuleContext ctx) {
                if (ctx.getClass().equals(TypeDeclarationContext.class)
                        || ctx.getClass().equals(ClassBodyDeclarationContext.class)) {

                    int tokPos = ctx.getStart().getTokenIndex();
                    final List<Token> hiddenTokens = tokenStream.getHiddenTokensToLeft(tokPos);
                    String doc = null;
                    if (hiddenTokens != null) {
                        for (int i = hiddenTokens.size() - 1; i > -1 && doc == null; i--) {
                            final Token refTok = hiddenTokens.get(i);
                            if (refTok != null) {
                                doc = refTok.getText();
                                if (doc.startsWith("/**") == false) {
                                    doc = null;
                                }
                            }

                        }
                    }

                    if (doc != null) {
                        Documentation documentation = JavadocParser.parse(doc);
                        Object obj = processStack.peek();
                        if (obj instanceof Documentable) {
                            ((Documentable) obj).setDocumentation(documentation);
                        }
                    }

                }
            }

            @Override
            public void enterConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) {
                super.enterConstructorDeclaration(ctx); // To change body of
                // generated methods,
                // choose Tools |
                // Templates.
            }

            @Override
            public void exitConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                try {
                    ClassConstructor classConstructor = JavasimpleFactory.eINSTANCE.createClassConstructor();
                    classConstructor.setName(ctx.Identifier().getText());
                    Object top;
                    // Parameters
                    while (processStack.isEmpty() == false && (top = processStack.pop()) != null) {
                        if (top instanceof Parameter) {
                            classConstructor.getParameters().add(0, (Parameter) top);
                        } else if (top instanceof StringBuilder) {
                            classConstructor.setSource(((StringBuilder) top).toString());
                        }
                    }
                    processModifiers(classConstructor);
                    processStack.push(classConstructor);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void exitInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                processMethod(ctx.Identifier().getText(), ctx.type(), null);
            }

            @Override
            public void exitMethodDeclaration(JavaParser.MethodDeclarationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                if (ctx.qualifiedNameList() != null) {
                    processMethod(ctx.Identifier().getText(), ctx.type(), ctx.qualifiedNameList().qualifiedName());
                } else {
                    processMethod(ctx.Identifier().getText(), ctx.type(), null);
                }
            }

            private void processMethod(String identifier, JavaParser.TypeContext type,
                    List<JavaParser.QualifiedNameContext> exceptions) {
                try {
                    JavaMethod method = JavasimpleFactory.eINSTANCE.createJavaMethod();
                    method.setName(identifier);
                    registerUnresolvedReference(method, SymbolType.Class,
                            JavasimplePackage.eINSTANCE.getJavaMethod_ReturnType(), type);
                    if (type != null) {
                        method.setReturnArray(type.getText().endsWith("[]"));
                    }
                    // method.setReturnType(getType(type));
                    Object element = processStack.peek();
                    if (element instanceof StringBuilder) {
                        method.setSource(((StringBuilder) element).toString());
                        processStack.pop();
                    }
                    Object top;
                    // Read parameters until find null
                    while (processStack.isEmpty() == false && (top = processStack.pop()) != null) {
                        if (top instanceof Parameter) {
                            method.getParameters().add(0, (Parameter) top);
                        }
                    }
                    processModifiers(method);
                    if (exceptions != null) {
                        for (JavaParser.QualifiedNameContext exception : exceptions) {
                            registerUnresolvedReference(method, SymbolType.Class,
                                    JavasimplePackage.eINSTANCE.getJavaMethod_Exceptions(), exception.getText());
                        }
                    }
                    processStack.push(method);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void enterFormalParameters(JavaParser.FormalParametersContext ctx) {
                if (processingBlock()) {
                    return;
                }
                processStack.push(null);
            }

            @Override
            public void exitFormalParameter(JavaParser.FormalParameterContext ctx) {
                if (processingBlock()) {
                    return;
                }
                Parameter param = JavasimpleFactory.eINSTANCE.createParameter();
                param.setName(ctx.variableDeclaratorId().Identifier().getText());
                registerUnresolvedReference(param, SymbolType.Class,
                        JavasimplePackage.eINSTANCE.getParameter_Type(), ctx.type());
                // param.setType(getType(ctx.type()));
                param.setArray(isArray(ctx.type()));
                processModifiers(param);
                processStack.push(param);
            }

            @Override
            public void exitLastFormalParameter(JavaParser.LastFormalParameterContext ctx) {
                if (processingBlock()) {
                    return;
                }
                Parameter param = JavasimpleFactory.eINSTANCE.createParameter();
                param.setName(ctx.variableDeclaratorId().Identifier().getText());
                registerUnresolvedReference(param, SymbolType.Class,
                        JavasimplePackage.eINSTANCE.getParameter_Type(), ctx.type());
                // param.setType(getType(ctx.type()));
                param.setArray(isArray(ctx.type()));
                param.setVarArray(true);
                processModifiers(param);
                processStack.push(param);
            }

            // @Override
            // public void
            // enterElementValuePair(JavaParser.ElementValuePairContext ctx) {
            // classStack.push(null);
            // }
            @Override
            public void enterElementValueArrayInitializer(JavaParser.ElementValueArrayInitializerContext ctx) {
                if (processingBlock()) {
                    return;
                }
                processStack.push(null);
            }

            @Override
            public void exitElementValue(JavaParser.ElementValueContext ctx) {
                if (processingBlock()) {/* ctx.getText() */

                    return;
                }
                try {
                    AnnotationParam param = null;
                    if (ctx.expression() != null) {
                        AnnotationParamValueExpression expression = JavasimpleFactory.eINSTANCE
                                .createAnnotationParamValueExpression();
                        final String valueExpression = app.handler
                                .processAnnotationValueExpresion(ctx.expression());
                        expression.setValue(valueExpression);
                        param = expression;
                    } else if (ctx.annotation() != null) {
                        AnnotationParamValueAnnotation expression = JavasimpleFactory.eINSTANCE
                                .createAnnotationParamValueAnnotation();
                        expression.setAnnotation((Annotation) processStack.pop());
                        param = expression;
                    } else if (ctx.elementValueArrayInitializer() != null) {
                        AnnotationParamValueArray expression = JavasimpleFactory.eINSTANCE
                                .createAnnotationParamValueArray();
                        Object top;
                        while ((top = processStack.pop()) != null) {
                            if (top instanceof Annotation) {
                                AnnotationParamValueAnnotation arrayElement = JavasimpleFactory.eINSTANCE
                                        .createAnnotationParamValueAnnotation();
                                arrayElement.setAnnotation((Annotation) top);
                                expression.getValues().add(0, arrayElement);
                            } else {
                                try {
                                    expression.getValues().add(0, (AnnotationParam) top);
                                } catch (Exception ex) {
                                    ex.printStackTrace();
                                }
                            }
                        }
                        param = expression;
                    }
                    processStack.push(param);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void exitElementValuePair(JavaParser.ElementValuePairContext ctx) {
                if (processingBlock()) {
                    return;
                }
                final AnnotationParam param = (AnnotationParam) processStack.peek();
                if (ctx.Identifier() != null) {
                    if (param == null) {
                        throw new RuntimeException();
                    }
                    param.setKey(ctx.Identifier().getText());
                }
            }

            @Override
            public void enterAnnotation(JavaParser.AnnotationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                processStack.push(null);
            }

            @Override
            public void exitAnnotation(JavaParser.AnnotationContext ctx) {
                if (processingBlock()) {
                    return;
                }
                try {
                    // final String annotationPackageName = getPackage(imports,
                    // ctx.annotationName().qualifiedName().getText());
                    // AnnotationType aType = (AnnotationType)
                    // app.getOrCreateReferencedJavaElement(SymbolType.AnnotationType,
                    // packageName, annotationPackageName,
                    // ctx.annotationName().qualifiedName().getText());
                    Annotation an = JavasimpleFactory.eINSTANCE.createAnnotation();
                    registerUnresolvedReference(an, SymbolType.AnnotationType,
                            JavasimplePackage.eINSTANCE.getAnnotation_AnnotationType(),
                            ctx.annotationName().qualifiedName().getText());
                    // an.setAnnotationType(aType);
                    Object top;
                    while (!processStack.isEmpty() && (top = processStack.pop()) != null) {
                        AnnotationParam param = (AnnotationParam) top;
                        if (param.getKey() == null) {
                            an.setValue(param);
                        } else {
                            an.getParameters().add(0, param);
                        }
                    }
                    processStack.push(an);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            /**
             * Generic method to put in the stack the modifiers
             *
             * @param ctx
             */
            @Override
            public void exitModifier(JavaParser.ModifierContext ctx) {
                if (processingBlock()) {
                    return;
                }
                if (ctx.classOrInterfaceModifier() == null) {
                    processStack.push(Modifier.getByName(ctx.getText()));
                }

            }

            /**
             * Put in the stack the modifiers of a class or interface
             *
             * @param ctx
             */
            @Override
            public void exitClassOrInterfaceModifier(JavaParser.ClassOrInterfaceModifierContext ctx) {
                if (processingBlock()) {
                    return;
                }
                /**
                 * The ClassOrInterfaceContext include the annotation we only
                 * add when is not an annotation
                 */
                if (ctx.annotation() == null) {
                    processStack.push(Modifier.getByName(ctx.getText()));
                }

            }

            /**
             * Put in the stack the modifiers of a variable AKA final
             *
             * @param ctx
             */
            @Override
            public void exitVariableModifier(JavaParser.VariableModifierContext ctx) {
                if (processingBlock()) {
                    return;
                }
                if (ctx.annotation() == null) {
                    processStack.push(Modifier.getByName(ctx.getText()));
                }
            }

            /**
             * Search in the stack for all the modifiers
             *
             * @param se
             */
            private void processModifiers(StructuralElement se) {
                String a;
                Object top;
                try {
                    while (!processStack.isEmpty() && (processStack.peek() instanceof Modifier
                            || processStack.peek() instanceof Annotation)) {
                        top = processStack.pop();
                        if (top instanceof Annotation) {
                            se.getAnnotations().add(0, (Annotation) top);
                        } else if (top instanceof Modifier) {
                            se.getModifiers().add(0, (Modifier) top);
                        }
                    }
                } catch (Exception e) {
                    System.out.println("----->" + fileName + "<------");
                    System.out.println(((NamedElement) se).getName());
                    System.out.println(processStack);
                    e.printStackTrace();
                }
            }

            private void registerUnresolvedReference(EObject javaElement, SymbolType symbolType, EReference feature,
                    JavaParser.TypeContext type) {
                if (type != null) {
                    unresolvedTypeReferences
                            .add(new TypeReference(javaElement, symbolType, feature, packageName, imports, type));
                }
            }

            private void registerUnresolvedReference(EObject javaElement, SymbolType symbolType, EReference feature,
                    String qualifiedName) {
                if (qualifiedName != null) {
                    unresolvedTypeReferences.add(new TypeReference(javaElement, symbolType, feature, packageName,
                            imports, qualifiedName));
                }
            }

            private boolean isArray(final JavaParser.TypeContext typeContext) {
                if (typeContext == null) {
                    return false;
                } else {
                    return typeContext.getText().endsWith("[]");
                }
            }

        };
        // parser.addParseListener(listener);
        // parser.addErrorListener(new ConsoleErrorListener());
        ParseTreeWalker walker = new ParseTreeWalker();
        ParseTree pTree = parser.compilationUnit();
        walker.walk(listener, pTree);
        app.registerUnresolvedReferences(unresolvedTypeReferences);
        // lexer.getInputStream().
    }

}