org.hibernate.eclipse.jdt.ui.internal.jpa.process.ProcessEntityInfo.java Source code

Java tutorial

Introduction

Here is the source code for org.hibernate.eclipse.jdt.ui.internal.jpa.process.ProcessEntityInfo.java

Source

/*******************************************************************************
  * Copyright (c) 2007-2008 Red Hat, Inc.
  * Distributed under license by Red Hat, Inc. All rights reserved.
  * This program is made available under the terms of the
  * Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributor:
  *     Red Hat, Inc. - initial API and implementation
  ******************************************************************************/
package org.hibernate.eclipse.jdt.ui.internal.jpa.process;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.ArrayType;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.MarkerAnnotation;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.NumberLiteral;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.ThisExpression;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.hibernate.eclipse.jdt.ui.internal.jpa.collect.CollectEntityInfo;
import org.hibernate.eclipse.jdt.ui.internal.jpa.common.EntityInfo;
import org.hibernate.eclipse.jdt.ui.internal.jpa.common.EntityInfosCollection;
import org.hibernate.eclipse.jdt.ui.internal.jpa.common.JPAConst;
import org.hibernate.eclipse.jdt.ui.internal.jpa.common.OwnerType;
import org.hibernate.eclipse.jdt.ui.internal.jpa.common.RefColumnInfo;
import org.hibernate.eclipse.jdt.ui.internal.jpa.common.RefEntityInfo;
import org.hibernate.eclipse.jdt.ui.internal.jpa.common.RefFieldInfo;
import org.hibernate.eclipse.jdt.ui.internal.jpa.common.RefType;
import org.hibernate.eclipse.jdt.ui.internal.jpa.common.EntityInfo.FieldGetterType;

/**
 * Visitor to insert JPA annotations into proper 
 * places of entity class.
 * 
 * @author Vitali
 */
public class ProcessEntityInfo extends ASTVisitor {

    /**
     * information about entity's annotations for whole compilation unit
     */
    protected EntityInfosCollection entityInfos;
    /**
     * information about entity's annotations
     */
    protected EntityInfo entityInfo;
    /**
     * information about all entities
     */
    protected Map<String, EntityInfo> entities;
    /**
     * rewriter to generate new AST blocks
     */
    protected ASTRewrite rewriter;
    /**
     * annotation style
     */
    protected AnnotStyle annotationStyle = AnnotStyle.FIELDS;
    /**
     * default length for column which corresponds to String field
     */
    protected int defaultStrLength = AllEntitiesProcessor.columnLength;
    /**
     * flag to enable optimistic locking
     */
    protected boolean enableOptLock = false;

    public void setEntityInfos(EntityInfosCollection entityInfos) {
        this.entityInfos = entityInfos;
    }

    public void setEntities(Map<String, EntityInfo> entities) {
        this.entities = entities;
    }

    public void setASTRewrite(ASTRewrite rewriter) {
        this.rewriter = rewriter;
    }

    public boolean visit(CompilationUnit node) {
        entityInfo = null;
        // TODO: sort all imports in alphabetic order
        //ListRewrite lrw = rewriter.getListRewrite(node, CompilationUnit.IMPORTS_PROPERTY);
        for (int i = 0; i < JPAConst.ALL_IMPORTS.size(); i++) {
            String tmp = JPAConst.ALL_IMPORTS.get(i);
            if (entityInfos.needImport(tmp)) {
                addImport(node, tmp);
            }
        }
        return true;
    }

    public boolean addImport(CompilationUnit node, String importDeclaration) {
        String[] importDeclarations = importDeclaration.split("\\."); //$NON-NLS-1$
        if (importDeclarations.length <= 1) {
            return false;
        }
        ImportDeclaration importDecl = rewriter.getAST().newImportDeclaration();
        SimpleName simpleName0 = rewriter.getAST().newSimpleName(importDeclarations[0]);
        SimpleName simpleName1 = rewriter.getAST().newSimpleName(importDeclarations[1]);
        QualifiedName qualifiedName0 = rewriter.getAST().newQualifiedName(simpleName0, simpleName1);
        for (int i = 2; i < importDeclarations.length; i++) {
            SimpleName simpleNameI = rewriter.getAST().newSimpleName(importDeclarations[i]);
            qualifiedName0 = rewriter.getAST().newQualifiedName(qualifiedName0, simpleNameI);
        }
        importDecl.setName(qualifiedName0);
        ListRewrite lrw = rewriter.getListRewrite(node, CompilationUnit.IMPORTS_PROPERTY);
        // insert import declaration in the proper place
        // prefer alphabetic order and package separation
        Iterator<?> it = lrw.getRewrittenList().iterator();
        ASTNode insertBeforeNode = null;
        for (; it.hasNext();) {
            Object obj = it.next();
            if (!(obj instanceof ImportDeclaration)) {
                continue;
            }
            ImportDeclaration id = (ImportDeclaration) obj;
            String idName = id.getName().getFullyQualifiedName();
            if (idName.compareTo(importDeclaration) > 0) {
                insertBeforeNode = id;
                break;
            }
        }
        if (insertBeforeNode == null) {
            lrw.insertLast(importDecl, null);
        } else {
            lrw.insertBefore(importDecl, insertBeforeNode, null);
        }
        return true;
    }

    @SuppressWarnings("unchecked")
    public boolean visit(TypeDeclaration node) {
        ITypeBinding typeBinding = node.resolveBinding();
        String nodeName = typeBinding == null ? null : typeBinding.getBinaryName();
        if (nodeName == null) {
            return false;
        }
        entityInfo = entityInfos.getEntityInfo(nodeName);
        if (entityInfo == null) {
            return false;
        }
        if (entityInfo.isAddMappedSuperclassFlag()) {
            MarkerAnnotation matd = rewriter.getAST().newMarkerAnnotation();
            matd.setTypeName(rewriter.getAST().newSimpleName(JPAConst.ANNOTATION_MAPPEDSUPERCLASS));
            ListRewrite lrw = rewriter.getListRewrite(node, TypeDeclaration.MODIFIERS2_PROPERTY);
            lrw.insertFirst(matd, null);
        }
        if (entityInfo.isAddEntityFlag()) {
            MarkerAnnotation matd = rewriter.getAST().newMarkerAnnotation();
            matd.setTypeName(rewriter.getAST().newSimpleName(JPAConst.ANNOTATION_ENTITY));
            ListRewrite lrw = rewriter.getListRewrite(node, TypeDeclaration.MODIFIERS2_PROPERTY);
            lrw.insertFirst(matd, null);
        }
        /** /
        if (!entityInfo.isImplicitConstructorFlag() && !entityInfo.isDefaultConstructorFlag() &&
        entityInfo.isAddSerializableInterfaceFlag()) {
           // add serializable interface
           SimpleName sn = null;
           //if (!entityInfo.isAddSerializableInterfaceImportFlag()) {
        sn = rewriter.getAST().newSimpleName(JPAConst.ANNOTATION_SERIALIZABLE);
           //}
           //else {
           //   sn = rewriter.getAST().newSimpleName(JPAConst.IMPORT_SERIALIZABLE);
           //}
           SimpleType st = rewriter.getAST().newSimpleType(sn);
           ListRewrite lrw = rewriter.getListRewrite(node, TypeDeclaration.SUPER_INTERFACE_TYPES_PROPERTY);
           lrw.insertFirst(st, null);
           // add "private static final long serialVersionUID = 1L;"
           // ...
        }
        /**/
        if (!entityInfo.isImplicitConstructorFlag() && !entityInfo.isDefaultConstructorFlag()
                && entityInfo.isAddSerializableInterfaceFlag()) {

            MethodDeclaration md = rewriter.getAST().newMethodDeclaration();
            md.setConstructor(true);
            Modifier modifier = rewriter.getAST().newModifier(Modifier.ModifierKeyword.PROTECTED_KEYWORD);
            md.modifiers().add(modifier);
            Block body = rewriter.getAST().newBlock();
            md.setBody(body);
            SimpleName sn = rewriter.getAST().newSimpleName(entityInfo.getName());
            md.setName(sn);
            ListRewrite lrw = rewriter.getListRewrite(node, TypeDeclaration.BODY_DECLARATIONS_PROPERTY);
            List<?> list = lrw.getOriginalList();
            MethodDeclaration insertBeforeNode = null;
            Iterator<?> it = list.iterator();
            while (it.hasNext()) {
                Object obj = it.next();
                if (obj instanceof MethodDeclaration) {
                    insertBeforeNode = (MethodDeclaration) obj;
                    break;
                }
            }
            if (insertBeforeNode == null) {
                lrw.insertLast(md, null);
            } else {
                lrw.insertBefore(md, insertBeforeNode, null);
            }
        }
        if (enableOptLock && entityInfo.isAddVersionFlag() && !entityInfo.hasVersionAnnotation()) {
            // add property "version", add getter/setter getVersion/setVersion,
            // add annotation for the property or for the getter
            //
            final String version = "version"; //$NON-NLS-1$
            final String versionType = "Integer"; //$NON-NLS-1$
            //
            VariableDeclarationFragment vdFragment = rewriter.getAST().newVariableDeclarationFragment();
            SimpleName variableName = rewriter.getAST().newSimpleName(version);
            vdFragment.setName(variableName);
            FieldDeclaration fieldVersion = rewriter.getAST().newFieldDeclaration(vdFragment);
            Modifier modifier = rewriter.getAST().newModifier(Modifier.ModifierKeyword.PROTECTED_KEYWORD);
            fieldVersion.modifiers().add(modifier);
            Name typeName = rewriter.getAST().newName(versionType);
            SimpleType type = rewriter.getAST().newSimpleType(typeName);
            fieldVersion.setType(type);
            //
            MethodDeclaration mdGetter = rewriter.getAST().newMethodDeclaration();
            modifier = rewriter.getAST().newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD);
            mdGetter.modifiers().add(modifier);
            Block body = rewriter.getAST().newBlock();
            ReturnStatement returnVersion = rewriter.getAST().newReturnStatement();
            variableName = rewriter.getAST().newSimpleName(version);
            returnVersion.setExpression(variableName);
            body.statements().add(returnVersion);
            mdGetter.setBody(body);
            SimpleName sn = rewriter.getAST().newSimpleName("getVersion"); //$NON-NLS-1$
            mdGetter.setName(sn);
            typeName = rewriter.getAST().newName(versionType);
            type = rewriter.getAST().newSimpleType(typeName);
            mdGetter.setReturnType2(type);
            //
            MethodDeclaration mdSetter = rewriter.getAST().newMethodDeclaration();
            modifier = rewriter.getAST().newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD);
            mdSetter.modifiers().add(modifier);
            body = rewriter.getAST().newBlock();
            Assignment assignment = rewriter.getAST().newAssignment();
            FieldAccess fieldAccess = rewriter.getAST().newFieldAccess();
            ThisExpression thisExpression = rewriter.getAST().newThisExpression();
            fieldAccess.setExpression(thisExpression);
            variableName = rewriter.getAST().newSimpleName(version);
            fieldAccess.setName(variableName);
            assignment.setLeftHandSide(fieldAccess);
            variableName = rewriter.getAST().newSimpleName(version);
            assignment.setRightHandSide(variableName);
            ExpressionStatement expressionStatement = rewriter.getAST().newExpressionStatement(assignment);
            body.statements().add(expressionStatement);
            mdSetter.setBody(body);
            sn = rewriter.getAST().newSimpleName("setVersion"); //$NON-NLS-1$
            mdSetter.setName(sn);
            SingleVariableDeclaration svd = rewriter.getAST().newSingleVariableDeclaration();
            variableName = rewriter.getAST().newSimpleName(version);
            svd.setName(variableName);
            typeName = rewriter.getAST().newName(versionType);
            type = rewriter.getAST().newSimpleType(typeName);
            svd.setType(type);
            mdSetter.parameters().add(svd);
            //
            ListRewrite lrw = rewriter.getListRewrite(node, TypeDeclaration.BODY_DECLARATIONS_PROPERTY);
            if (entityInfo.getVersionFieldGetter() != FieldGetterType.FIELD
                    && entityInfo.getVersionFieldGetter() != FieldGetterType.FIELD_GETTER) {
                lrw.insertLast(fieldVersion, null);
            }
            if (entityInfo.getVersionFieldGetter() != FieldGetterType.GETTER
                    && entityInfo.getVersionFieldGetter() != FieldGetterType.FIELD_GETTER) {
                lrw.insertLast(mdGetter, null);
                lrw.insertLast(mdSetter, null);
            }
            if (annotationStyle == AnnotStyle.FIELDS) {
                MarkerAnnotation matd = rewriter.getAST().newMarkerAnnotation();
                matd.setTypeName(rewriter.getAST().newSimpleName(JPAConst.ANNOTATION_VERSION));
                lrw = rewriter.getListRewrite(fieldVersion, FieldDeclaration.MODIFIERS2_PROPERTY);
                lrw.insertFirst(matd, null);
            } else if (annotationStyle == AnnotStyle.GETTERS) {
                MarkerAnnotation matd = rewriter.getAST().newMarkerAnnotation();
                matd.setTypeName(rewriter.getAST().newSimpleName(JPAConst.ANNOTATION_VERSION));
                lrw = rewriter.getListRewrite(mdGetter, MethodDeclaration.MODIFIERS2_PROPERTY);
                lrw.insertFirst(matd, null);
            }
        }
        return true;
    }

    @SuppressWarnings("unchecked")
    public boolean visit(FieldDeclaration node) {
        if (entityInfo == null) {
            return false;
        }
        if (annotationStyle != AnnotStyle.FIELDS) {
            return true;
        }
        Type type = node.getType();
        if (type == null) {
            return true;
        }
        if (type.isSimpleType() || type.isPrimitiveType()) {
            if (entityInfo.isAddGeneratedValueFlag()) {
                String primaryIdName = entityInfo.getPrimaryIdName();
                Iterator<VariableDeclarationFragment> itVarNames = node.fragments().iterator();
                boolean addGeneratedValueMarker = false;
                while (itVarNames.hasNext()) {
                    VariableDeclarationFragment var = itVarNames.next();
                    String name = var.getName().getIdentifier();
                    if (primaryIdName.equals(name)) {
                        addGeneratedValueMarker = true;
                        break;
                    }
                }
                if (addGeneratedValueMarker) {
                    MarkerAnnotation matd = rewriter.getAST().newMarkerAnnotation();
                    matd.setTypeName(rewriter.getAST().newSimpleName(JPAConst.ANNOTATION_GENERATED_VALUE));
                    ListRewrite lrw = rewriter.getListRewrite(node, FieldDeclaration.MODIFIERS2_PROPERTY);
                    lrw.insertFirst(matd, null);
                }
            }
            if (entityInfo.isAddPrimaryIdFlag()) {
                String primaryIdName = entityInfo.getPrimaryIdName();
                Iterator<VariableDeclarationFragment> itVarNames = node.fragments().iterator();
                boolean addIdMarker = false;
                while (itVarNames.hasNext()) {
                    VariableDeclarationFragment var = itVarNames.next();
                    String name = var.getName().getIdentifier();
                    if (primaryIdName.equals(name)) {
                        addIdMarker = true;
                        break;
                    }
                }
                if (addIdMarker) {
                    MarkerAnnotation matd = rewriter.getAST().newMarkerAnnotation();
                    matd.setTypeName(rewriter.getAST().newSimpleName(JPAConst.ANNOTATION_ID));
                    ListRewrite lrw = rewriter.getListRewrite(node, FieldDeclaration.MODIFIERS2_PROPERTY);
                    lrw.insertFirst(matd, null);
                }
            }
            if (enableOptLock && entityInfo.isAddVersionFlag() && !entityInfo.hasVersionAnnotation()) {
                Iterator<VariableDeclarationFragment> itVarNames = node.fragments().iterator();
                boolean addVersionMarker = false;
                while (itVarNames.hasNext()) {
                    VariableDeclarationFragment var = itVarNames.next();
                    String name = var.getName().getIdentifier();
                    if ("version".equals(name)) { //$NON-NLS-1$
                        addVersionMarker = true;
                        break;
                    }
                }
                if (addVersionMarker) {
                    MarkerAnnotation matd = rewriter.getAST().newMarkerAnnotation();
                    matd.setTypeName(rewriter.getAST().newSimpleName(JPAConst.ANNOTATION_VERSION));
                    ListRewrite lrw = rewriter.getListRewrite(node, FieldDeclaration.MODIFIERS2_PROPERTY);
                    lrw.insertFirst(matd, null);
                }
            }
        }
        if (type.isSimpleType() && (AllEntitiesProcessor.columnLength != defaultStrLength)) {
            SimpleType simpleType = (SimpleType) type;
            String typeName = simpleType.getName().getFullyQualifiedName();
            if ("java.lang.String".equals(typeName) || "String".equals(typeName)) { //$NON-NLS-1$ //$NON-NLS-2$
                String fieldId = null;
                Iterator<VariableDeclarationFragment> itVarNames = node.fragments().iterator();
                while (itVarNames.hasNext()) {
                    VariableDeclarationFragment var = itVarNames.next();
                    fieldId = var.getName().getIdentifier();
                    if (fieldId != null) {
                        break;
                    }
                }
                RefColumnInfo rci = entityInfo.getRefColumnInfo(fieldId);
                if (rci == null || !rci.isExist()) {
                    // if there is no @Column annotation - create new @Column annotation
                    // with user defined default value length 
                    NormalAnnotation natd = rewriter.getAST().newNormalAnnotation();
                    natd.setTypeName(rewriter.getAST().newSimpleName(JPAConst.ANNOTATION_COLUMN));
                    ListRewrite lrw = rewriter.getListRewrite(node, FieldDeclaration.MODIFIERS2_PROPERTY);
                    lrw.insertFirst(natd, null);
                    MemberValuePair mvp = rewriter.getAST().newMemberValuePair();
                    mvp.setName(rewriter.getAST().newSimpleName("length")); //$NON-NLS-1$
                    NumberLiteral nl = rewriter.getAST().newNumberLiteral(String.valueOf(defaultStrLength));
                    mvp.setValue(nl);
                    natd.values().add(mvp);
                }
            }
        }
        if (type.isSimpleType() || type.isParameterizedType() || type.isArrayType()) {
            Iterator<VariableDeclarationFragment> itVarNames = node.fragments().iterator();
            String fieldId = ""; //$NON-NLS-1$
            RefType refType = RefType.UNDEF;
            boolean annotated = false;
            String fullyQualifiedName2 = ""; //$NON-NLS-1$
            while (itVarNames.hasNext()) {
                VariableDeclarationFragment var = itVarNames.next();
                String name = var.getName().getIdentifier();
                fieldId = name;
                refType = entityInfo.getFieldIdRelValue(fieldId);
                annotated = entityInfo.getFieldIdAnnotatedValue(fieldId);
                fullyQualifiedName2 = entityInfo.getFieldIdFQNameValue(fieldId);
                if (refType != RefType.UNDEF) {
                    break;
                }
            }
            Set<RefFieldInfo> setRFI = entityInfo.getRefFieldInfoSet(fullyQualifiedName2);
            if (!annotated && setRFI != null && isSimilarType(type, fullyQualifiedName2)) {
                RefEntityInfo rei = entityInfo.getFieldIdRefEntityInfo(fieldId);
                // try to process bidirectional relationships:
                // nRefType == JPAConst.ONE2ONE - OneToOne - the owning side corresponds
                //              to the side that contains the corresponding foreign key
                // nRefType == JPAConst.MANY2ONE - ManyToOne - owning side is always the "many" side
                // nRefType == JPAConst.MANY2MANY - ManyToMany bidirectional relationships 
                //              either side may be the owning side
                if (setRFI.size() > 1 && refType != RefType.MANY2ONE) {
                    if (rei.mappedBy == null || rei.mappedBy == "") { //$NON-NLS-1$
                        addSimpleMarkerAnnotation(node, JPAConst.getRefType(refType));
                    } else {
                        // give to the user information about selected mapping
                        addComplexNormalAnnotation(node, JPAConst.getRefType(refType), rei);
                    }
                } else if (refType == RefType.MANY2ONE || refType == RefType.ENUMERATED || rei.mappedBy == null
                        || rei.mappedBy == "") { //$NON-NLS-1$
                    addSimpleMarkerAnnotation(node, JPAConst.getRefType(refType));
                } else {
                    // in case of bidirectional OneToOne - mark both sides with mappedBy - 
                    // user should select the right decision 
                    addComplexNormalAnnotation(node, JPAConst.getRefType(refType), rei);
                }
            }
        }
        return true;
    }

    @SuppressWarnings("unchecked")
    public boolean visit(MethodDeclaration node) {
        if (entityInfo == null) {
            return false;
        }
        if (annotationStyle != AnnotStyle.GETTERS) {
            return true;
        }
        if (node.getName().getFullyQualifiedName().compareTo(entityInfo.getName()) == 0 || node.isConstructor()) {
            // this is constructor declaration
            return true;
        }
        // -) is it setter?
        if (node.getName().getIdentifier().startsWith("set") //$NON-NLS-1$
                && node.parameters().size() == 1) {
            // setter - do not process it
            return true;
        }
        // +) is it getter?
        if (!(node.getName().getIdentifier().startsWith("get") //$NON-NLS-1$
                || node.getName().getIdentifier().startsWith("is")) //$NON-NLS-1$
                || node.parameters().size() > 0) {
            // not the getter - do not process it
            return true;
        }
        Type type = node.getReturnType2();
        if (type == null) {
            return true;
        }
        String returnIdentifier = CollectEntityInfo.getReturnIdentifier(node);
        if (type.isSimpleType() || type.isPrimitiveType()) {
            if (entityInfo.isAddGeneratedValueFlag()) {
                String primaryIdName = entityInfo.getPrimaryIdName();
                boolean addGeneratedValueMarker = false;
                if (primaryIdName.equals(returnIdentifier)) {
                    addGeneratedValueMarker = true;
                }
                if (addGeneratedValueMarker) {
                    MarkerAnnotation matd = rewriter.getAST().newMarkerAnnotation();
                    matd.setTypeName(rewriter.getAST().newSimpleName(JPAConst.ANNOTATION_GENERATED_VALUE));
                    ListRewrite lrw = rewriter.getListRewrite(node, MethodDeclaration.MODIFIERS2_PROPERTY);
                    lrw.insertFirst(matd, null);
                }
            }
            if (entityInfo.isAddPrimaryIdFlag()) {
                String primaryIdName = entityInfo.getPrimaryIdName();
                boolean addIdMarker = false;
                if (primaryIdName.equals(returnIdentifier)) {
                    addIdMarker = true;
                }
                if (addIdMarker) {
                    MarkerAnnotation matd = rewriter.getAST().newMarkerAnnotation();
                    matd.setTypeName(rewriter.getAST().newSimpleName(JPAConst.ANNOTATION_ID));
                    ListRewrite lrw = rewriter.getListRewrite(node, MethodDeclaration.MODIFIERS2_PROPERTY);
                    lrw.insertFirst(matd, null);
                }
            }
            if (enableOptLock && entityInfo.isAddVersionFlag() && !entityInfo.hasVersionAnnotation()) {
                boolean addVersionMarker = false;
                if ("version".equals(returnIdentifier)) { //$NON-NLS-1$
                    addVersionMarker = true;
                }
                if (addVersionMarker) {
                    MarkerAnnotation matd = rewriter.getAST().newMarkerAnnotation();
                    matd.setTypeName(rewriter.getAST().newSimpleName(JPAConst.ANNOTATION_VERSION));
                    ListRewrite lrw = rewriter.getListRewrite(node, MethodDeclaration.MODIFIERS2_PROPERTY);
                    lrw.insertFirst(matd, null);
                }
            }
        }
        if (type.isSimpleType() && (AllEntitiesProcessor.columnLength != defaultStrLength)) {
            SimpleType simpleType = (SimpleType) type;
            String typeName = simpleType.getName().getFullyQualifiedName();
            if ("java.lang.String".equals(typeName) || "String".equals(typeName)) { //$NON-NLS-1$ //$NON-NLS-2$
                String fieldId = returnIdentifier;
                RefColumnInfo rci = entityInfo.getRefColumnInfo(fieldId);
                if (rci == null || !rci.isExist()) {
                    // if there is no @Column annotation - create new @Column annotation
                    // with user defined default value length 
                    NormalAnnotation natd = rewriter.getAST().newNormalAnnotation();
                    natd.setTypeName(rewriter.getAST().newSimpleName(JPAConst.ANNOTATION_COLUMN));
                    ListRewrite lrw = rewriter.getListRewrite(node, MethodDeclaration.MODIFIERS2_PROPERTY);
                    lrw.insertFirst(natd, null);
                    MemberValuePair mvp = rewriter.getAST().newMemberValuePair();
                    mvp.setName(rewriter.getAST().newSimpleName("length")); //$NON-NLS-1$
                    NumberLiteral nl = rewriter.getAST().newNumberLiteral(String.valueOf(defaultStrLength));
                    mvp.setValue(nl);
                    natd.values().add(mvp);
                }
            }
        }
        if (type.isSimpleType() || type.isParameterizedType() || type.isArrayType()) {
            String fieldId = ""; //$NON-NLS-1$
            RefType refType = RefType.UNDEF;
            boolean annotated = false;
            String fullyQualifiedName2 = ""; //$NON-NLS-1$
            fieldId = returnIdentifier;
            refType = entityInfo.getFieldIdRelValue(fieldId);
            annotated = entityInfo.getFieldIdAnnotatedValue(fieldId);
            fullyQualifiedName2 = entityInfo.getFieldIdFQNameValue(fieldId);
            Set<RefFieldInfo> setRFI = entityInfo.getRefFieldInfoSet(fullyQualifiedName2);
            if (!annotated && setRFI != null && isSimilarType(type, fullyQualifiedName2)) {
                RefEntityInfo rei = entityInfo.getFieldIdRefEntityInfo(fieldId);
                // try to process bidirectional relationships:
                // nRefType == JPAConst.ONE2ONE - OneToOne - the owning side corresponds
                //              to the side that contains the corresponding foreign key
                // nRefType == JPAConst.MANY2ONE - ManyToOne - owning side is always the "many" side
                // nRefType == JPAConst.MANY2MANY - ManyToMany bidirectional relationships 
                //              either side may be the owning side
                if (setRFI.size() > 1 && refType != RefType.MANY2ONE) {
                    if (rei.mappedBy == null || rei.mappedBy == "") { //$NON-NLS-1$
                        addSimpleMarkerAnnotation(node, JPAConst.getRefType(refType));
                    } else {
                        // give to the user information about selected mapping
                        addComplexNormalAnnotation(node, JPAConst.getRefType(refType), rei);
                    }
                } else if (refType == RefType.MANY2ONE || refType == RefType.ENUMERATED || rei.mappedBy == null
                        || rei.mappedBy == "") { //$NON-NLS-1$
                    addSimpleMarkerAnnotation(node, JPAConst.getRefType(refType));
                } else {
                    // in case of bidirectional OneToOne - mark both sides with mappedBy - 
                    // user should select the right decision 
                    addComplexNormalAnnotation(node, JPAConst.getRefType(refType), rei);
                }
            }
        }
        return true;
    }

    // simple type name check 
    public boolean isSimilarType(Type type, String fullyQualifiedName) {
        String typeName = null;
        if (type.isSimpleType()) {
            SimpleType st = (SimpleType) type;
            typeName = st.getName().getFullyQualifiedName();
        } else if (type.isArrayType()) {
            ArrayType at = (ArrayType) type;
            Type componentType = at;
            while (componentType.isArrayType()) {
                componentType = ((ArrayType) componentType).getComponentType();
            }
            if (componentType.isSimpleType()) {
                SimpleType st = (SimpleType) componentType;
                typeName = st.getName().getFullyQualifiedName();
            }
        }
        if (typeName != null && fullyQualifiedName.indexOf(typeName) == -1) {
            return false;
        }
        return true;
    }

    public boolean addSimpleMarkerAnnotation(BodyDeclaration node, String name) {
        if (name == null || name.length() == 0) {
            return false;
        }
        MarkerAnnotation matd = rewriter.getAST().newMarkerAnnotation();
        matd.setTypeName(rewriter.getAST().newSimpleName(name));
        ListRewrite lrw = null;
        if (node instanceof FieldDeclaration) {
            lrw = rewriter.getListRewrite(node, FieldDeclaration.MODIFIERS2_PROPERTY);
        } else if (node instanceof MethodDeclaration) {
            lrw = rewriter.getListRewrite(node, MethodDeclaration.MODIFIERS2_PROPERTY);
        }
        if (lrw != null) {
            lrw.insertFirst(matd, null);
        }
        return true;
    }

    @SuppressWarnings("unchecked")
    public boolean addComplexNormalAnnotation(BodyDeclaration node, String name, RefEntityInfo rei) {
        if (name == null || name.length() == 0) {
            return false;
        }
        NormalAnnotation natd = rewriter.getAST().newNormalAnnotation();
        MemberValuePair mvp = null;
        if (rei.mappedBy != null && (rei.owner == OwnerType.YES || rei.owner == OwnerType.UNDEF)) {
            mvp = rewriter.getAST().newMemberValuePair();
            mvp.setName(rewriter.getAST().newSimpleName("mappedBy")); //$NON-NLS-1$
            StringLiteral sl = rewriter.getAST().newStringLiteral();
            sl.setLiteralValue(rei.mappedBy);
            mvp.setValue(sl);
        }
        natd.setTypeName(rewriter.getAST().newSimpleName(name));
        if (mvp != null) {
            natd.values().add(mvp);
        }
        NormalAnnotation natd2 = null;
        /** /
        if (rei.owner == OwnerType.NO) {
           natd2 = rewriter.getAST().newNormalAnnotation();
           natd2.setTypeName(rewriter.getAST().newSimpleName(JPAConst.ANNOTATION_JOINCOLUMN));
           mvp = null;
           String fullyQualifiedName2 = rei.fullyQualifiedName;
           EntityInfo entryInfo2 = entities.get(fullyQualifiedName2);
           if (entryInfo2 != null) {
        mvp = rewriter.getAST().newMemberValuePair();
        mvp.setName(rewriter.getAST().newSimpleName("name")); //$NON-NLS-1$
        StringLiteral sl = rewriter.getAST().newStringLiteral();
        sl.setLiteralValue(entryInfo2.getPrimaryIdName());
        mvp.setValue(sl);
           }
           if (mvp != null) {
        natd2.values().add(mvp);
           }
        }
        /**/
        ListRewrite lrw = null;
        if (node instanceof FieldDeclaration) {
            lrw = rewriter.getListRewrite(node, FieldDeclaration.MODIFIERS2_PROPERTY);
        } else if (node instanceof MethodDeclaration) {
            lrw = rewriter.getListRewrite(node, MethodDeclaration.MODIFIERS2_PROPERTY);
        }
        if (lrw != null) {
            if (natd2 != null) {
                lrw.insertFirst(natd2, null);
            }
            lrw.insertFirst(natd, null);
        }
        return true;
    }

    public AnnotStyle getAnnotationStyle() {
        return annotationStyle;
    }

    public void setAnnotationStyle(AnnotStyle annotationStyle) {
        this.annotationStyle = annotationStyle;
    }

    public int getDefaultStrLength() {
        return defaultStrLength;
    }

    public void setDefaultStrLength(int defaultStrLength) {
        this.defaultStrLength = defaultStrLength;
    }

    public boolean getEnableOptLock() {
        return enableOptLock;
    }

    public void setEnableOptLock(boolean enableOptLock) {
        this.enableOptLock = enableOptLock;
    }
}