private static FileObject generateJpaController()

in java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/jpacontroller/JpaControllerGenerator.java [205:897]


    private static FileObject generateJpaController(
            final String fieldName, 
            final FileObject pkg, 
            final ElementHandle<ExecutableElement> idGetter, 
            final String persistenceUnit, 
            final String controllerClass,
            final String exceptionPackage, 
            final String entityClass, 
            final String simpleEntityName,
            final List<ElementHandle<ExecutableElement>> toOneRelMethods,
            final List<ElementHandle<ExecutableElement>> toManyRelMethods,
            final boolean isInjection,
            final boolean isFieldAccess,
            FileObject controllerFileObject, 
            final EmbeddedPkSupport embeddedPkSupport,
            final String version,
            final boolean jakartaPersistencePackages
    ) throws IOException {
        
            final String[] idPropertyType = new String[1];
            final String[] derivedIdPropertyType = new String[1];
            final String[] idGetterName = new String[1];
            final String[] derivedIdGetterName = new String[1];
            final boolean[] embeddable = new boolean[] { false };
            final boolean[] derived = new boolean[] {false};
            
            JavaSource controllerJavaSource = JavaSource.forFileObject(controllerFileObject);
            //sometimes javasource isn't refreshed properly yet
            if(controllerJavaSource == null){
                if (!controllerFileObject.isValid()) {
                    controllerFileObject.getParent().refresh();	//Maybe fo.refresh() is enough
                    controllerFileObject = FileUtil.toFileObject(FileUtil.toFile(controllerFileObject));
                    if (controllerFileObject != null) {
                        controllerJavaSource = JavaSource.forFileObject(controllerFileObject);
                    }
                } 
                
                if(controllerJavaSource == null){
                    Logger.getLogger(JpaControllerGenerator.class.getName()).log(Level.WARNING, "Can''t find JavaSource for {0}", controllerFileObject.getPath());
                    return controllerFileObject;//don't need npe later
                }
            }
            controllerJavaSource.runModificationTask( (WorkingCopy workingCopy) -> {
                workingCopy.toPhase(JavaSource.Phase.RESOLVED);
                
                ExecutableElement idGetterElement = idGetter.resolve(workingCopy);
                idGetterName[0] = idGetterElement.getSimpleName().toString();
                TypeMirror idType = idGetterElement.getReturnType();
                TypeElement idClass = null;
                if (null == idType.getKind()) {
                    //instead of throwing exceptions later, just use Object
                    idPropertyType[0] = "java.lang.Object";//NOI18N
                } else {
                    switch (idType.getKind()) {
                        case DECLARED:
                            DeclaredType declaredType = (DeclaredType) idType;
                            idClass = (TypeElement) declaredType.asElement();
                            embeddable[0] = idClass != null && JpaControllerUtil.isEmbeddableClass(idClass);
                            idPropertyType[0] = idClass.getQualifiedName().toString();
                            if(!embeddable[0] && JpaControllerUtil.haveId(idClass)){//NOI18N
                                //handle derived id, case entity/relationship without composite keys
                                derived[0] =  JpaControllerUtil.isRelationship(idGetterElement ,JpaControllerUtil.isFieldAccess(idClass)) != JpaControllerUtil.REL_NONE;
                                if(derived[0]){
                                    ExecutableElement derivedIdGetterElement  = findPrimaryKeyGetter(workingCopy, idClass);
                                    derivedIdGetterName[0] = derivedIdGetterElement.getSimpleName().toString();
                                    TypeMirror derivedIdType = derivedIdGetterElement.getReturnType();
                                    TypeElement derivedIdClass;
                                    if (TypeKind.DECLARED == idType.getKind()) {
                                        DeclaredType derivedDeclaredType = (DeclaredType) derivedIdType;
                                        derivedIdClass = (TypeElement) derivedDeclaredType.asElement();
                                        derivedIdPropertyType[0] = derivedIdClass.getQualifiedName().toString();
                                    }
                                }
                            }
                            break;
                        case BOOLEAN:
                            idPropertyType[0] = "boolean";//NOI18N
                            break;
                        case BYTE:
                            idPropertyType[0] = "byte";//NOI18N
                            break;
                        case CHAR:
                            idPropertyType[0] = "char";//NOI18N
                            break;
                        case DOUBLE:
                            idPropertyType[0] = "double";//NOI18N
                            break;
                        case FLOAT:
                            idPropertyType[0] = "float";//NOI18N
                            break;
                        case INT:
                            idPropertyType[0] = "int";//NOI18N
                            break;
                        case LONG:
                            idPropertyType[0] = "long";//NOI18N
                            break;
                        case SHORT:
                            idPropertyType[0] = "short";//NOI18N
                            break;
                        default:
                            //instead of throwing exceptions later, just use Object
                            idPropertyType[0] = "java.lang.Object";//NOI18N
                            break;
                    }
                }
                String simpleIdPropertyType = JpaControllerUtil.simpleClassName(idPropertyType[0]);
                
                TypeElement controllerTypeElement = SourceUtils.getPublicTopLevelElement(workingCopy);
                ClassTree classTree = workingCopy.getTrees().getTree(controllerTypeElement);
                ClassTree modifiedClassTree = classTree;
                
                int privateModifier = java.lang.reflect.Modifier.PRIVATE;
                int publicModifier = java.lang.reflect.Modifier.PUBLIC;
                
                CompilationUnitTree modifiedImportCut = null;
                
                List<String> parameterTypes = new ArrayList<>();
                List<String> parameterNames = new ArrayList<>();
                String body = "";   //NOI18N
                boolean isUserTransaction =
                        workingCopy.getClasspathInfo().getClassPath(ClasspathInfo.PathKind.COMPILE).findResource("jakarta/transaction/UserTransaction.class") != null //NOI18N
                        || workingCopy.getClasspathInfo().getClassPath(ClasspathInfo.PathKind.COMPILE).findResource("javax/transaction/UserTransaction.class") != null;  //NOI18N
                if (isUserTransaction && isInjection) {
                    if (jakartaPersistencePackages) {
                        modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addVariable(modifiedClassTree, workingCopy, "utx", "jakarta.transaction.UserTransaction", privateModifier, null, null);   //NOI18N
                        parameterTypes.add("jakarta.transaction.UserTransaction");   //NOI18N
                    } else {
                        modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addVariable(modifiedClassTree, workingCopy, "utx", "javax.transaction.UserTransaction", privateModifier, null, null);   //NOI18N
                        parameterTypes.add("javax.transaction.UserTransaction");   //NOI18N
                    }
                    parameterNames.add("utx");   //NOI18N
                    body = "this.utx = utx;\n";   //NOI18N
                    
                }
                if (jakartaPersistencePackages) {
                    modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addVariable(modifiedClassTree, workingCopy, "emf", "jakarta.persistence.EntityManagerFactory", privateModifier, null, null);   //NOI18N
                    parameterTypes.add("jakarta.persistence.EntityManagerFactory");   //NOI18N
                } else {
                    modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addVariable(modifiedClassTree, workingCopy, "emf", "javax.persistence.EntityManagerFactory", privateModifier, null, null);   //NOI18N
                    parameterTypes.add("javax.persistence.EntityManagerFactory");   //NOI18N
                }
                parameterNames.add("emf");   //NOI18N
                body += "this.emf = emf;";   //NOI18N
                MethodInfo mi = new MethodInfo("<init>", publicModifier, "void", null, parameterTypes.toArray(new String[0]),   //NOI18N
                parameterNames.toArray(new String[0]), body, null, null);
                modifiedClassTree = JpaControllerUtil.TreeMakerUtils.modifyDefaultConstructor(classTree, modifiedClassTree, workingCopy, mi);
                
                MethodInfo methodInfo;
                if (jakartaPersistencePackages) {
                    methodInfo = new MethodInfo("getEntityManager", publicModifier, "jakarta.persistence.EntityManager", null, null, null, "return emf.createEntityManager();", null, null);
                } else {
                    methodInfo = new MethodInfo("getEntityManager", publicModifier, "javax.persistence.EntityManager", null, null, null, "return emf.createEntityManager();", null, null);
                }
                modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addMethod(modifiedClassTree, workingCopy, methodInfo);
                
                String bodyText;
                StringBuilder updateRelatedInCreate = new StringBuilder();
                StringBuilder updateRelatedInEditPre = new StringBuilder();
                StringBuilder attachRelatedInEdit = new StringBuilder();
                StringBuilder updateRelatedInEditPost = new StringBuilder();
                StringBuilder updateRelatedInDestroy = new StringBuilder();
                StringBuilder initRelatedInCreate = new StringBuilder();
                StringBuilder illegalOrphansInCreate = new StringBuilder();
                StringBuilder illegalOrphansInEdit = new StringBuilder();
                StringBuilder illegalOrphansInDestroy = new StringBuilder();
                StringBuilder initCollectionsInCreate = new StringBuilder();  //useful in case user removes listbox from New.jsp
                
                List<ElementHandle<ExecutableElement>> allRelMethods = new ArrayList<>(toOneRelMethods);
                allRelMethods.addAll(toManyRelMethods);
                
                List<String> importFqs = new ArrayList<>();

                if(jakartaPersistencePackages) {
                    importFqs.add("jakarta.persistence.Query");
                    importFqs.add("jakarta.persistence.EntityNotFoundException");
                    importFqs.add("jakarta.persistence.criteria.CriteriaQuery");
                    importFqs.add("jakarta.persistence.criteria.Root");
                } else {
                    importFqs.add("javax.persistence.Query");
                    importFqs.add("javax.persistence.EntityNotFoundException");
                    if(version!=null && !Persistence.VERSION_1_0.equals(version)){//add criteria classes if appropriate
                        modifiedImportCut = JpaControllerUtil.TreeMakerUtils.createImport(workingCopy, modifiedImportCut, "javax.persistence.criteria.CriteriaQuery");
                        modifiedImportCut = JpaControllerUtil.TreeMakerUtils.createImport(workingCopy, modifiedImportCut, "javax.persistence.criteria.Root");
                    }
                }

                for (String importFq : importFqs) {
                    modifiedImportCut = JpaControllerUtil.TreeMakerUtils.createImport(workingCopy, modifiedImportCut, importFq);
                }

                String oldMe = null;
                
                // <editor-fold desc=" all relations ">
                for(Iterator<ElementHandle<ExecutableElement>> it = allRelMethods.iterator(); it.hasNext();) {
                    ElementHandle<ExecutableElement> handle = it.next();
                    ExecutableElement m = handle.resolve(workingCopy);
                    int multiplicity = JpaControllerUtil.isRelationship(m, isFieldAccess);
                    ExecutableElement otherSide = JpaControllerUtil.getOtherSideOfRelation(workingCopy, m, isFieldAccess);
                    
                    if (otherSide != null) {
                        TypeElement relClass = (TypeElement)otherSide.getEnclosingElement();
                        boolean isRelFieldAccess = JpaControllerUtil.isFieldAccess(relClass);
                        int otherSideMultiplicity = JpaControllerUtil.isRelationship(otherSide, isRelFieldAccess);
                        TypeMirror t = m.getReturnType();
                        Types types = workingCopy.getTypes();
                        TypeMirror tstripped = JpaControllerUtil.stripCollection(t, types);
                        boolean isCollection = t != tstripped;
                        String simpleCollectionTypeName = null;
                        String collectionTypeClass = null;
                        if (isCollection) {
                            TypeElement tAsElement = (TypeElement) types.asElement(t);
                            simpleCollectionTypeName = tAsElement.getSimpleName().toString();
                            collectionTypeClass = tAsElement.getQualifiedName().toString();
                        }
                        String simpleCollectionImplementationTypeName = "ArrayList";    //NOI18N
                        String collectionImplementationTypeClass = "java.util.ArrayList";    //NOI18N
                        Class collectionTypeAsClass = null;
                        if (isCollection) {
                            try {
                                collectionTypeAsClass = Class.forName(collectionTypeClass);
                            } catch (ClassNotFoundException cfne) {
                                //let collectionTypeAsClass be null
                            }
                            if (collectionTypeAsClass != null && Set.class.isAssignableFrom(collectionTypeAsClass)) {
                                simpleCollectionImplementationTypeName = "HashSet";    //NOI18N
                                collectionImplementationTypeClass = "java.util.HashSet";    //NOI18N
                            }
                        }
                        String relType = tstripped.toString();
                        String simpleRelType = JpaControllerUtil.simpleClassName(relType); //just "Pavilion"
                        String relTypeReference = simpleRelType;
                        String mName = m.getSimpleName().toString();
                        String otherName = otherSide.getSimpleName().toString();
                        String otherType = otherSide.getReturnType().toString();
                        String relFieldName = JpaControllerUtil.getPropNameFromMethod(mName);
                        String otherFieldName = JpaControllerUtil.getPropNameFromMethod(otherName);
                        
                        boolean columnNullable = JpaControllerUtil.isFieldOptionalAndNullable(m, isFieldAccess);
                        boolean relColumnNullable = JpaControllerUtil.isFieldOptionalAndNullable(otherSide, isFieldAccess);
                        
                        String relFieldToAttach = isCollection ? relFieldName + relTypeReference + "ToAttach" : relFieldName;
                        String scalarRelFieldName = isCollection ? relFieldName + relTypeReference : relFieldName;
                        
                        if(fieldName.equals(scalarRelFieldName)){
                            scalarRelFieldName  = scalarRelFieldName + "Rel";//if entity have references to itself (i.e. tree/chain etc of entities), need to make name different from entity field name
                        }
                        
                        if (!controllerClass.startsWith(entityClass + "JpaController")) {
                            modifiedImportCut = JpaControllerUtil.TreeMakerUtils.createImport(workingCopy, modifiedImportCut, relType);
                        }
                        
                        ExecutableElement relIdGetterElement = JpaControllerUtil.getIdGetter(isFieldAccess, relClass);
                        String refOrMergeString;
                        
                        if (isCollection) {
                            refOrMergeString = getRefOrMergeString(relIdGetterElement, relFieldToAttach);
                            initCollectionsInCreate.append("if (" + fieldName + "." + mName + "() == null) {\n" +
                                    fieldName + ".s" + mName.substring(1) + "(new " + simpleCollectionImplementationTypeName + "<" + relTypeReference + ">());\n" +
                                            "}\n");
                            
                            
                            modifiedImportCut = JpaControllerUtil.TreeMakerUtils.createImport(workingCopy, modifiedImportCut, collectionImplementationTypeClass);
                            
                            initRelatedInCreate.append(simpleCollectionTypeName + "<" + relTypeReference + "> attached" + mName.substring(3) + " = new " + simpleCollectionImplementationTypeName + "<" + relTypeReference + ">();\n" +
                                    "for (" + relTypeReference + " " + relFieldToAttach + " : " + fieldName + "." + mName + "()) {\n" +
                                    relFieldToAttach + " = " + refOrMergeString +
                                    "attached" + mName.substring(3) + ".add(" + relFieldToAttach + ");\n" +
                                            "}\n" +
                                    fieldName + ".s" + mName.substring(1) + "(attached" + mName.substring(3) + ");\n"
                            );
                        }
                        else {
                            refOrMergeString = getRefOrMergeString(relIdGetterElement, scalarRelFieldName);
                            initRelatedInCreate.append(relTypeReference + " " + scalarRelFieldName + " = " + fieldName + "." + mName +"();\n" +
                                    "if (" + scalarRelFieldName + " != null) {\n" +
                                    scalarRelFieldName + " = " + refOrMergeString +
                                    fieldName + ".s" + mName.substring(1) + "(" + scalarRelFieldName + ");\n" +
                                            "}\n");
                        }
                        
                        String relrelInstanceName = "old" + otherName.substring(3) + "Of" + scalarRelFieldName.substring(0, 1).toUpperCase() + (scalarRelFieldName.length() > 1 ? scalarRelFieldName.substring(1) : "");
                        String relrelGetterName = otherName;
                        
                        if (!columnNullable && otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE && multiplicity == JpaControllerUtil.REL_TO_ONE) {
                            illegalOrphansInCreate.append(
                                    relTypeReference + " " + scalarRelFieldName + "OrphanCheck = " + fieldName + "." + mName +"();\n" +
                                            "if (" + scalarRelFieldName + "OrphanCheck != null) {\n");
                            illegalOrphansInCreate.append(simpleEntityName + " " + relrelInstanceName + " = " + scalarRelFieldName + "OrphanCheck." + relrelGetterName + "();\n");
                            illegalOrphansInCreate.append("if (" + relrelInstanceName + " != null) {\n" +
                                    "if (illegalOrphanMessages == null) {\n" +
                                    "illegalOrphanMessages = new ArrayList<String>();\n" +
                                    "}\n" +
                                    "illegalOrphanMessages.add(\"The " + relTypeReference + " \" + " + scalarRelFieldName + "OrphanCheck + \" already has an item of type " + simpleEntityName + " whose " + scalarRelFieldName + " column cannot be null. Please make another selection for the " + scalarRelFieldName + " field.\");\n" +
                                            "}\n");
                            illegalOrphansInCreate.append("}\n");
                        }
                        
                        updateRelatedInCreate.append( (isCollection ? "for(" + relTypeReference + " " + scalarRelFieldName + " : " + fieldName + "." + mName + "()){\n" :
                                "if (" + scalarRelFieldName + " != null) {\n"));
                        //if 1:1, be sure to orphan the related entity's current related entity
                        if (otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE){
                            if (multiplicity != JpaControllerUtil.REL_TO_ONE || columnNullable) { //no need to declare relrelInstanceName if we have already examined it in the 1:1 orphan check
                                String retType = simpleEntityName;
                                if(!otherType.equals(entityClass)){
                                    retType = otherType;
                                }
                                updateRelatedInCreate.append(retType + " " + relrelInstanceName + " = " + scalarRelFieldName + "." + relrelGetterName + "();\n");
                            }
                            if (multiplicity == JpaControllerUtil.REL_TO_ONE) {
                                if (columnNullable) {
                                    updateRelatedInCreate.append("if (" + relrelInstanceName + " != null) {\n" +
                                            relrelInstanceName + ".s" + mName.substring(1) + "(null);\n" +
                                            relrelInstanceName + " = em.merge(" + relrelInstanceName + ");\n" +
                                                    "}\n");
                                }
                            }
                        }
                        
                        updateRelatedInCreate.append( ((otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE) ? scalarRelFieldName + ".s" + otherName.substring(1) + "(" + fieldName+ ");\n" :
                                scalarRelFieldName + "." + otherName + "().add(" + fieldName +");\n") +
                                scalarRelFieldName + " = em.merge(" + scalarRelFieldName +");\n");
                        if (multiplicity == JpaControllerUtil.REL_TO_MANY && otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE){
                            updateRelatedInCreate.append("if " + relrelInstanceName + " != null) {\n" +
                                    relrelInstanceName + "." + mName + "().remove(" + scalarRelFieldName + ");\n" +
                                    relrelInstanceName + " = em.merge(" + relrelInstanceName + ");\n" +
                                            "}\n");
                        }
                        updateRelatedInCreate.append("}\n");
                        
                        if (oldMe == null) {
                            oldMe = "persistent" + simpleEntityName;
                            String oldMeStatement = simpleEntityName + " " + oldMe + " = em.find(" +
                                    simpleEntityName + ".class, " + fieldName + "." + idGetterName[0] + "());\n";
                            updateRelatedInEditPre.append("\n " + oldMeStatement);
                        }
                        
                        if (isCollection) {
                            String relFieldOld = relFieldName + "Old";
                            String relFieldNew = relFieldName + "New";
                            String oldScalarRelFieldName = relFieldOld + relTypeReference;
                            String newScalarRelFieldName = relFieldNew + relTypeReference;
                            String oldOfNew = "old" + otherName.substring(3) + "Of" + newScalarRelFieldName.substring(0, 1).toUpperCase() + newScalarRelFieldName.substring(1);
                            updateRelatedInEditPre.append("\n " + simpleCollectionTypeName + "<" + relTypeReference + "> " + relFieldOld + " = " + oldMe + "." + mName + "();\n");
                            updateRelatedInEditPre.append(simpleCollectionTypeName + " <" + relTypeReference + "> " + relFieldNew + " = " + fieldName + "." + mName + "();\n");
                            if (!relColumnNullable && otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE) {
                                illegalOrphansInEdit.append(
                                        "for(" + relTypeReference + " " + oldScalarRelFieldName + " : " + relFieldOld + ") {\n" +
                                                "if (!" + relFieldNew + ".contains(" + oldScalarRelFieldName + ")) {\n" +
                                                        "if (illegalOrphanMessages == null) {\n" +
                                                        "illegalOrphanMessages = new ArrayList<String>();\n" +
                                                        "}\n" +
                                                        "illegalOrphanMessages.add(\"You must retain " + relTypeReference + " \" + " + oldScalarRelFieldName + " + \" since its " + otherFieldName + " field is not nullable.\");\n" +
                                                                "}\n" +
                                                                "}\n");
                            }
                            String relFieldToAttachInEdit = newScalarRelFieldName + "ToAttach";
                            String refOrMergeStringInEdit = getRefOrMergeString(relIdGetterElement, relFieldToAttachInEdit);
                            String attachedRelFieldNew = "attached" + mName.substring(3) + "New";
                            attachRelatedInEdit.append(simpleCollectionTypeName + "<" + relTypeReference + "> " + attachedRelFieldNew + " = new " + simpleCollectionImplementationTypeName + "<" + relTypeReference + ">();\n" +
                                    "for (" + relTypeReference + " " + relFieldToAttachInEdit + " : " + relFieldNew + ") {\n" +
                                    relFieldToAttachInEdit + " = " + refOrMergeStringInEdit +
                                    attachedRelFieldNew + ".add(" + relFieldToAttachInEdit + ");\n" +
                                            "}\n" +
                                    relFieldNew + " = " + attachedRelFieldNew + ";\n" +
                                    fieldName + ".s" + mName.substring(1) + "(" + relFieldNew + ");\n"
                            );
                            if (otherSideMultiplicity == JpaControllerUtil.REL_TO_MANY || relColumnNullable) {
                                updateRelatedInEditPost.append(
                                        "for (" + relTypeReference + " " + oldScalarRelFieldName + " : " + relFieldOld + ") {\n" +
                                                "if (!" + relFieldNew + ".contains(" + oldScalarRelFieldName + ")) {\n" +
                                                ((otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE) ? oldScalarRelFieldName + ".s" + otherName.substring(1) + "(null);\n" :
                                                        oldScalarRelFieldName + "." + otherName + "().remove(" + fieldName + ");\n") +
                                                oldScalarRelFieldName + " = em.merge(" + oldScalarRelFieldName + ");\n" +
                                                        "}\n" +
                                                        "}\n");
                            }
                            updateRelatedInEditPost.append("for (" + relTypeReference + " " + newScalarRelFieldName + " : " + relFieldNew + ") {\n" +
                                    "if (!" + relFieldOld + ".contains(" + newScalarRelFieldName + ")) {\n" +
                                    ((otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE) ? simpleEntityName + " " + oldOfNew + " = " + newScalarRelFieldName + "." + relrelGetterName + "();\n" +
                                            newScalarRelFieldName + ".s" + otherName.substring(1) + "(" + fieldName+ ");\n" :
                                            newScalarRelFieldName + "." + otherName + "().add(" + fieldName +");\n") +
                                    newScalarRelFieldName + " = em.merge(" + newScalarRelFieldName + ");\n");
                            if (otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE) {
                                updateRelatedInEditPost.append("if " + oldOfNew + " != null && !" + oldOfNew + ".equals(" + fieldName + ")) {\n" +
                                        oldOfNew + "." + mName + "().remove(" + newScalarRelFieldName + ");\n" +
                                        oldOfNew + " = em.merge(" + oldOfNew + ");\n" +
                                                "}\n");
                            }
                            updateRelatedInEditPost.append("}\n}\n");
                        } else {
                            updateRelatedInEditPre.append("\n" + relTypeReference + " " + scalarRelFieldName + "Old = " + oldMe + "." + mName + "();\n");
                            updateRelatedInEditPre.append(relTypeReference + " " + scalarRelFieldName + "New = " + fieldName + "." + mName +"();\n");
                            if (!relColumnNullable && otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE) {
                                illegalOrphansInEdit.append(
                                        "if(" + scalarRelFieldName + "Old != null && !" + scalarRelFieldName + "Old.equals(" + scalarRelFieldName + "New)) {\n" +
                                                "if (illegalOrphanMessages == null) {\n" +
                                                "illegalOrphanMessages = new ArrayList<String>();\n" +
                                                "}\n" +
                                                "illegalOrphanMessages.add(\"You must retain " + relTypeReference + " \" + " + scalarRelFieldName + "Old + \" since its " + otherFieldName + " field is not nullable.\");\n" +
                                                        "}\n");
                            }
                            String refOrMergeStringInEdit = getRefOrMergeString(relIdGetterElement, scalarRelFieldName + "New");
                            attachRelatedInEdit.append("if (" + scalarRelFieldName + "New != null) {\n" +
                                    scalarRelFieldName + "New = " + refOrMergeStringInEdit +
                                    fieldName + ".s" + mName.substring(1) + "(" + scalarRelFieldName + "New);\n" +
                                            "}\n");
                            if (otherSideMultiplicity == JpaControllerUtil.REL_TO_MANY || relColumnNullable) {
                                updateRelatedInEditPost.append(   
                                        "if(" + scalarRelFieldName + "Old != null && !" + scalarRelFieldName + "Old.equals(" + scalarRelFieldName + "New)) {\n" +
                                                ((otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE) ? scalarRelFieldName + "Old.s" + otherName.substring(1) + "(null);\n" :
                                                        scalarRelFieldName + "Old." + otherName + "().remove(" + fieldName +");\n") +
                                                scalarRelFieldName + "Old = em.merge(" + scalarRelFieldName +"Old);\n}\n");
                            }
                            if (multiplicity == JpaControllerUtil.REL_TO_ONE && otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE && !columnNullable) {
                                illegalOrphansInEdit.append(
                                        "if(" + scalarRelFieldName + "New != null && !" + scalarRelFieldName + "New.equals(" + scalarRelFieldName + "Old)) {\n");
                                illegalOrphansInEdit.append(simpleEntityName + " " + relrelInstanceName + " = " + scalarRelFieldName + "New." + relrelGetterName + "();\n" +
                                        "if (" + relrelInstanceName + " != null) {\n" + 
                                                "if (illegalOrphanMessages == null) {\n" +
                                                "illegalOrphanMessages = new ArrayList<String>();\n" +
                                                "}\n" +
                                                "illegalOrphanMessages.add(\"The " + relTypeReference + " \" + " + scalarRelFieldName + "New + \" already has an item of type " + simpleEntityName + " whose " + scalarRelFieldName + " column cannot be null. Please make another selection for the " + scalarRelFieldName + " field.\");\n" +
                                                        "}\n");
                                illegalOrphansInEdit.append("}\n");
                            }
                            updateRelatedInEditPost.append(
                                    "if(" + scalarRelFieldName + "New != null && !" + scalarRelFieldName + "New.equals(" + scalarRelFieldName + "Old)) {\n");
                            if (multiplicity == JpaControllerUtil.REL_TO_ONE && otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE && columnNullable) {
                                String tmpType = simpleEntityName;
                                if(!otherType.equals(entityClass)){
                                    tmpType = otherType;
                                }
                                updateRelatedInEditPost.append(tmpType + " " + relrelInstanceName + " = " + scalarRelFieldName + "New." + relrelGetterName + "();\n" +
                                        "if (" + relrelInstanceName + " != null) {\n" +
                                        relrelInstanceName + ".s" + mName.substring(1) + "(null);\n" +
                                        relrelInstanceName + " = em.merge(" + relrelInstanceName + ");\n" +
                                                "}\n");
                            }
                            updateRelatedInEditPost.append(
                                    ((otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE) ? scalarRelFieldName + "New.s" + otherName.substring(1) + "(" + fieldName + ");\n" :
                                            scalarRelFieldName + "New." + otherName + "().add(" + fieldName +");\n") +
                                            scalarRelFieldName + "New = em.merge(" + scalarRelFieldName + "New);\n}\n"
                            );
                        }
                        
                        if (otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE && !relColumnNullable) {
                            String orphanCheckCollection = relFieldName + "OrphanCheck";
                            String orphanCheckScalar = isCollection ? orphanCheckCollection + relTypeReference : relFieldName + "OrphanCheck";
                            illegalOrphansInDestroy.append(
                                    (isCollection ? simpleCollectionTypeName + "<" + relTypeReference + "> " + orphanCheckCollection : relTypeReference + " " + orphanCheckScalar) + " = " + fieldName + "." + mName +"();\n" +
                                            (isCollection ? "for(" + relTypeReference + " " + orphanCheckScalar + " : " + orphanCheckCollection : "if (" + orphanCheckScalar + " != null") + ") {\n" +
                                                    "if (illegalOrphanMessages == null) {\n" +
                                                    "illegalOrphanMessages = new ArrayList<String>();\n" +
                                                    "}\n" +
                                                    "illegalOrphanMessages.add(\"This " + simpleEntityName + " (\" + " +  fieldName + " + \") cannot be destroyed since the " + relTypeReference + " \" + " + orphanCheckScalar + " + \" in its " + relFieldName + " field has a non-nullable " + otherFieldName + " field.\");\n" +
                                                            "}\n");
                        }
                        if (otherSideMultiplicity == JpaControllerUtil.REL_TO_MANY || relColumnNullable) {
                            updateRelatedInDestroy.append( (isCollection ? simpleCollectionTypeName + "<" + relTypeReference + "> " + relFieldName : relTypeReference + " " + scalarRelFieldName) + " = " + fieldName + "." + mName +"();\n" +
                                    (isCollection ? "for(" + relTypeReference + " " + scalarRelFieldName + " : " + relFieldName : "if (" + scalarRelFieldName + " != null") + ") {\n" +
                                    ((otherSideMultiplicity == JpaControllerUtil.REL_TO_ONE) ? scalarRelFieldName + ".s" + otherName.substring(1) + "(null);\n" :
                                            scalarRelFieldName + "." + otherName + "().remove(" + fieldName +");\n") +
                                    scalarRelFieldName + " = em.merge(" + scalarRelFieldName +");\n}\n\n");
                        }
                        
                        if (collectionTypeClass != null) { //(multiplicity == JpaControllerUtil.REL_TO_MANY) {
                            modifiedImportCut = JpaControllerUtil.TreeMakerUtils.createImport(workingCopy, modifiedImportCut, collectionTypeClass);
                        }

                    } else {
                        ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, "Cannot detect other side of a relationship.");
                    }
                    
                }
                // </editor-fold>
                
                String BEGIN = isInjection ? "utx.begin();\nem = getEntityManager();" : "em = getEntityManager();\nem.getTransaction().begin();";
                String COMMIT = isInjection ? "utx.commit();" : "em.getTransaction().commit();";
                String ROLLBACK = isInjection ? "try {\n" +
                        "utx.rollback();" +
                        "\n} catch (Exception re) {\n" +
                        "throw new RollbackFailureException(\"An error occurred attempting to roll back the transaction.\", re);\n" +
                        "}\n"
                        : "";
                
                if (illegalOrphansInCreate.length() > 0 || illegalOrphansInEdit.length() > 0 || illegalOrphansInDestroy.length() > 0) {
                    modifiedImportCut = JpaControllerUtil.TreeMakerUtils.createImport(workingCopy, modifiedImportCut, "java.util.ArrayList");
                }
                
                if (illegalOrphansInCreate.length() > 0) {
                    illegalOrphansInCreate.insert(0, "List<String> illegalOrphanMessages = null;\n");
                    illegalOrphansInCreate.append("if (illegalOrphanMessages != null) {\n" +
                            "throw new IllegalOrphanException(illegalOrphanMessages);\n" +
                            "}\n");
                }
                
                TypeElement entityType = workingCopy.getElements().getTypeElement(entityClass);
                StringBuilder codeToPopulatePkFields = new StringBuilder();
                if (embeddable[0]) {
                    for (ExecutableElement pkMethod : embeddedPkSupport.getPkAccessorMethods(entityType)) {
                        if (embeddedPkSupport.isRedundantWithRelationshipField(entityType, pkMethod)) {
                            codeToPopulatePkFields.append(fieldName + "." +idGetterName[0] + "().s" + pkMethod.getSimpleName().toString().substring(1) + "(" +  //NOI18N
                                    fieldName + "." + embeddedPkSupport.getCodeToPopulatePkField(entityType, pkMethod) + ");\n");
                        }
                    }
                }
                
                boolean isGenerated = JpaControllerUtil.isGenerated(idGetterElement, isFieldAccess);
                bodyText = (embeddable[0] ? "if (" + fieldName + "." + idGetterName[0] + "() == null) {\n" +
                        fieldName + ".s" + idGetterName[0].substring(1) + "(new " + idClass.getSimpleName() + "());\n" +
                        "}\n" : "") +
                        initCollectionsInCreate.toString() +
                        codeToPopulatePkFields.toString() +
                        illegalOrphansInCreate.toString() +
                        "EntityManager em = null;\n" +
                        "try {\n " + BEGIN + "\n " +
                        initRelatedInCreate.toString() + "em.persist(" + fieldName + ");\n" + updateRelatedInCreate.toString() + COMMIT + "\n" +   //NOI18N
                        (isInjection || !isGenerated ? "} catch (Exception ex) {\n" : "") +
                        ROLLBACK +
                        (!isGenerated ? "if (find" + simpleEntityName + "(" + fieldName + "." + idGetterName[0] + "()) != null) {\n" +
                        "throw new PreexistingEntityException(\"" + simpleEntityName + " \" + " + fieldName + " + \" already exists.\", ex);\n" +
                        "}\n" : "") +
                        (isInjection || !isGenerated ? "throw ex;\n" : "") +
                        "} finally {\n if (em != null) {\nem.close();\n}\n}";
                
                List<String> methodExceptionTypeList = new ArrayList<>();
                if (illegalOrphansInCreate.length() > 0) {
                    methodExceptionTypeList.add(exceptionPackage + ".IllegalOrphanException");
                }
                if (!isGenerated) {
                    methodExceptionTypeList.add(exceptionPackage + ".PreexistingEntityException");
                }
                if (isInjection) {
                    methodExceptionTypeList.add(exceptionPackage + ".RollbackFailureException");
                }
                if (isInjection || !isGenerated) {
                    methodExceptionTypeList.add("java.lang.Exception");
                }
                String[] createExceptionTypes = methodExceptionTypeList.toArray(new String[0]);
                methodInfo = new MethodInfo("create", publicModifier, "void", createExceptionTypes, new String[]{entityClass}, new String[]{fieldName}, bodyText, null, null);
                modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addMethod(modifiedClassTree, workingCopy, methodInfo);
                
                if (illegalOrphansInEdit.length() > 0) {
                    illegalOrphansInEdit.insert(0, "List<String> illegalOrphanMessages = null;\n");
                    illegalOrphansInEdit.append("if (illegalOrphanMessages != null) {\n" +
                            "throw new IllegalOrphanException(illegalOrphanMessages);\n" +
                            "}\n");
                }
                
                bodyText = codeToPopulatePkFields.toString() +
                        "EntityManager em = null;\n" + 
                        "try {\n " + BEGIN + "\n" +
                        updateRelatedInEditPre.toString() + illegalOrphansInEdit.toString() + attachRelatedInEdit.toString() +
                        fieldName + " = em.merge(" + fieldName + ");\n " + 
                        updateRelatedInEditPost.toString() + COMMIT + "\n" +   //NOI18N
                        "} catch (Exception ex) {\n" +
                        ROLLBACK +
                        "String msg = ex.getLocalizedMessage();\n" + 
                        "if (msg == null || msg.length() == 0) {\n" +
                        simpleIdPropertyType + " id = " + fieldName + "." + idGetterName[0] + "();\n" +
                        "if (find" + simpleEntityName + "(id) == null) {\n" +
                        "throw new NonexistentEntityException(\"The " + simpleEntityName.substring(0, 1).toLowerCase() + simpleEntityName.substring(1) + " with id \" + id + \" no longer exists.\");\n" +
                        "}\n" +
                        "}\n" +
                        "throw ex;\n} " +   //NOI18N
                        "finally {\n if (em != null) {\nem.close();\n}\n }";
                methodExceptionTypeList.clear();
                if (illegalOrphansInEdit.length() > 0) {
                    methodExceptionTypeList.add(exceptionPackage + ".IllegalOrphanException");
                }
                methodExceptionTypeList.add(exceptionPackage + ".NonexistentEntityException");
                if (isInjection) {
                    methodExceptionTypeList.add(exceptionPackage + ".RollbackFailureException");
                }
                methodExceptionTypeList.add("java.lang.Exception");
                String[] editExceptionTypes = methodExceptionTypeList.toArray(new String[0]);
                methodInfo = new MethodInfo("edit", publicModifier, "void", editExceptionTypes, new String[]{entityClass}, new String[]{fieldName}, bodyText, null, null);
                modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addMethod(modifiedClassTree, workingCopy, methodInfo);
                
                if (illegalOrphansInDestroy.length() > 0) {
                    illegalOrphansInDestroy.insert(0, "List<String> illegalOrphanMessages = null;\n");
                    illegalOrphansInDestroy.append("if (illegalOrphanMessages != null) {\n" +
                            "throw new IllegalOrphanException(illegalOrphanMessages);\n" +
                            "}\n");
                }
                
                String refOrMergeStringInDestroy = "em.merge(" + fieldName + ");\n";
                if (idGetterElement != null) {
                    refOrMergeStringInDestroy = "em.getReference(" + simpleEntityName + ".class, id);\n";
                }
                bodyText = "EntityManager em = null;\n" +
                        "try {\n " + BEGIN + "\n" + 
                        simpleEntityName + " " + fieldName + ";\n" +
                        "try {\n " +
                        fieldName + " = " + refOrMergeStringInDestroy + 
                        fieldName + "." + idGetterName[0] + "();\n" +
                        "} catch (EntityNotFoundException enfe) {\n" +
                        "throw new NonexistentEntityException(\"The " + fieldName + " with id \" + id + \" no longer exists.\", enfe);\n" +
                        "}\n" + 
                        illegalOrphansInDestroy.toString() +
                        updateRelatedInDestroy.toString() + 
                        "em.remove(" + fieldName + ");\n " + COMMIT + "\n" +   //NOI18N
                        (isInjection ? "} catch (Exception ex) {\n" : "") +
                        ROLLBACK + 
                        (isInjection ? "throw ex;\n" : "") +
                        "} finally {\n if (em != null) {\nem.close();\n}\n }";  //NOI18N
                methodExceptionTypeList.clear();
                if (illegalOrphansInDestroy.length() > 0) {
                    methodExceptionTypeList.add(exceptionPackage + ".IllegalOrphanException");
                }
                methodExceptionTypeList.add(exceptionPackage + ".NonexistentEntityException");
                if (isInjection) {
                    methodExceptionTypeList.add(exceptionPackage + ".RollbackFailureException");
                    methodExceptionTypeList.add("java.lang.Exception");
                }
                String[] destroyExceptionTypes = methodExceptionTypeList.toArray(new String[0]);
                String[] findDestroyType = derived[0] && derivedIdPropertyType[0]!=null ? derivedIdPropertyType : idPropertyType;
                methodInfo = new MethodInfo("destroy", publicModifier, "void", destroyExceptionTypes, findDestroyType, new String[]{"id"}, bodyText, null, null);
                modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addMethod(modifiedClassTree, workingCopy, methodInfo);
                
                //secondary destroy with derived type (entity type id)
                if(derived[0] && derivedIdPropertyType[0]!=null && !derivedIdPropertyType[0].equals(idPropertyType[0])){
                    bodyText = "destroy( id." + derivedIdGetterName[0] + "() );";
                    methodInfo = new MethodInfo("destroy", publicModifier, "void", destroyExceptionTypes, idPropertyType, new String[]{"id"}, bodyText, null, null);
                    modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addMethod(modifiedClassTree, workingCopy, methodInfo);
                }
                //
                
                TypeInfo listOfEntityType = new TypeInfo("java.util.List", new String[]{entityClass});
                
                bodyText = "return find" + simpleEntityName + "Entities(true, -1, -1);";
                methodInfo = new MethodInfo("find" + simpleEntityName + "Entities", publicModifier, listOfEntityType, null, null, null, bodyText, null, null);
                modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addMethod(modifiedClassTree, workingCopy, methodInfo);
                
                bodyText = "return find" + simpleEntityName + "Entities(false, maxResults, firstResult);";
                methodInfo = new MethodInfo("find" + simpleEntityName + "Entities", publicModifier, listOfEntityType, null, TypeInfo.fromStrings(new String[]{"int", "int"}), new String[]{"maxResults", "firstResult"}, bodyText, null, null);
                modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addMethod(modifiedClassTree, workingCopy, methodInfo);
                
                bodyText = "EntityManager em = getEntityManager();\n try{\n" +
                        (
                        version!=null && !Persistence.VERSION_1_0.equals(version) ?
                        "CriteriaQuery cq = em.getCriteriaBuilder().createQuery();\n"+
                        "cq.select(cq.from("+simpleEntityName+".class));\n"+
                        "Query q = em.createQuery(cq);\n"
                        :
                        "Query q = em.createQuery(\"select object(o) from " + simpleEntityName +" as o\");\n"
                        )
                        +
                        "if (!all) {\n" +
                        "q.setMaxResults(maxResults);\n" +
                        "q.setFirstResult(firstResult);\n" + 
                        "}\n" +
                        "return q.getResultList();\n" + 
                        "} finally {\n em.close();\n}\n";
                methodInfo = new MethodInfo("find" + simpleEntityName + "Entities", privateModifier, listOfEntityType, null, TypeInfo.fromStrings(new String[]{"boolean", "int", "int"}), new String[]{"all", "maxResults", "firstResult"}, bodyText, null, null);
                modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addMethod(modifiedClassTree, workingCopy, methodInfo);
                
                
                //getter for converter
                bodyText = "EntityManager em = getEntityManager();\n try{\n" +
                        "return em.find(" + simpleEntityName + ".class, id);\n" + 
                        "} finally {\n em.close();\n}\n";
                methodInfo = new MethodInfo("find" + simpleEntityName, publicModifier, entityClass, null, findDestroyType, new String[]{"id"}, bodyText, null, null);
                modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addMethod(modifiedClassTree, workingCopy, methodInfo);
                
                //secondary find with derived type (entity type id), first one above is with derived (i.e. column) type.
                if(derived[0] && derivedIdPropertyType[0]!=null && !derivedIdPropertyType[0].equals(idPropertyType[0])){
                    bodyText = "return find" + simpleEntityName + "( id." + derivedIdGetterName[0] + "() );";
                    methodInfo = new MethodInfo("find" + simpleEntityName, publicModifier, entityClass, null, idPropertyType, new String[]{"id"}, bodyText, null, null);
                    modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addMethod(modifiedClassTree, workingCopy, methodInfo);
                }
                
                bodyText = "EntityManager em = getEntityManager();\n try{\n" + 
                        (
                        version!=null && !Persistence.VERSION_1_0.equals(version) ?
                        "CriteriaQuery cq = em.getCriteriaBuilder().createQuery();\n"+
                        "Root<"+simpleEntityName+"> rt = cq.from("+simpleEntityName+".class); "+
                        "cq.select(em.getCriteriaBuilder().count(rt));\n"+
                        "Query q = em.createQuery(cq);\n"
                        :
                        "Query q = em.createQuery(\"select count(o) from " + simpleEntityName + " as o\");\n"
                        )
                        +
                        "return ((Long) q.getSingleResult()).intValue();\n" +
                        "} finally {\n em.close();\n}";
                methodInfo = new MethodInfo("get" + simpleEntityName + "Count", publicModifier, "int", null, null, null, bodyText, null, null);
                modifiedClassTree = JpaControllerUtil.TreeMakerUtils.addMethod(modifiedClassTree, workingCopy, methodInfo);
                
                workingCopy.rewrite(classTree, modifiedClassTree);
            }).commit();
    
        return controllerFileObject;
    }