private boolean writeIsDetachedMethod()

in openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java [3765:3995]


    private boolean writeIsDetachedMethod(ClassNode classNode, MethodNode meth) throws NoSuchMethodException {
        InsnList instructions = meth.instructions;
        // not detachable: return Boolean.FALSE
        if (!_meta.isDetachable()) {
            instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
                                               "FALSE", Type.getDescriptor(Boolean.class)));
            instructions.add(new InsnNode(Opcodes.ARETURN));
            return false;
        }

        // if (sm != null)
        //     return (sm.isDetached ()) ? Boolean.TRUE : Boolean.FALSE;
        instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
        instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));

        LabelNode lblEndIfNull = new LabelNode();
        instructions.add(new JumpInsnNode(Opcodes.IFNULL, lblEndIfNull));
        instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
        instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));
        instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
                                            Type.getInternalName(SMTYPE),
                                            "isDetached",
                                            Type.getMethodDescriptor(Type.BOOLEAN_TYPE)));

        LabelNode lblEndIfFalse = new LabelNode();
        instructions.add(new JumpInsnNode(Opcodes.IFEQ, lblEndIfFalse));
        instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
                                           "TRUE", Type.getDescriptor(Boolean.class)));
        instructions.add(new InsnNode(Opcodes.ARETURN));
        instructions.add(lblEndIfFalse);
        instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
                                           "FALSE", Type.getDescriptor(Boolean.class)));
        instructions.add(new InsnNode(Opcodes.ARETURN));
        // END - if (sm != null)


        // if we use detached state:
        // if (pcGetDetachedState () != null
        //     && pcGetDetachedState != DESERIALIZED)
        //     return Boolean.TRUE;
        Boolean state = _meta.usesDetachedState();
        LabelNode lblNotDeser = null;

        if (state != Boolean.FALSE) {
            instructions.add(lblEndIfNull);
            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
            instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
                                                classNode.name,
                                                PRE + "GetDetachedState",
                                                Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT)));

            lblEndIfNull = new LabelNode();
            instructions.add(new JumpInsnNode(Opcodes.IFNULL, lblEndIfNull));
            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
            instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
                                                classNode.name,
                                                PRE + "GetDetachedState",
                                                Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT)));
            instructions.add(new FieldInsnNode(Opcodes.GETSTATIC,
                                               Type.getInternalName(PersistenceCapable.class),
                                               "DESERIALIZED",
                                               AsmHelper.TYPE_OBJECT.getDescriptor()));

            lblNotDeser = new LabelNode();
            instructions.add(new JumpInsnNode(Opcodes.IF_ACMPEQ, lblNotDeser));
            instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
                                               "TRUE", Type.getDescriptor(Boolean.class)));
            instructions.add(new InsnNode(Opcodes.ARETURN));

            if (state == Boolean.TRUE) {
                // if we have to use detached state:
                // return Boolean.FALSE;
                instructions.add(lblEndIfNull);
                instructions.add(lblNotDeser);
                instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
                                                   "FALSE", Type.getDescriptor(Boolean.class)));
                instructions.add(new InsnNode(Opcodes.ARETURN));
                return false;
            }
        }

        instructions.add(lblEndIfNull);
        if (lblNotDeser != null) {
            instructions.add(lblNotDeser);
        }

        // allow users with version or auto-assigned pk fields to manually
        // construct a "detached" instance, so check these before taking into
        // account non-existent detached state

        // consider detached if version is non-default
        FieldMetaData version = _meta.getVersionField();
        if (state != Boolean.TRUE && version != null) {
            // if (<version> != <default>)
            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
            addGetManagedValueCode(classNode, instructions, version, true);
            LabelNode lblAfterDefault = ifDefaultValue(instructions, version);

            // return true
            instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
                                               "TRUE", Type.getDescriptor(Boolean.class)));
            instructions.add(new InsnNode(Opcodes.ARETURN));

            instructions.add(lblAfterDefault);

            if (!_addVersionInitFlag) {
                // else return false;
                instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
                                                   "FALSE", Type.getDescriptor(Boolean.class)));
                instructions.add(new InsnNode(Opcodes.ARETURN));
            }
            else {
                // if (pcVersionInit != false)
                // return true
                // else return null; //  (returning null because we don't know the correct answer)
                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
                getfield(classNode, instructions, null, VERSION_INIT_STR, boolean.class);
                LabelNode lblAfterEq = new LabelNode();
                instructions.add(new JumpInsnNode(Opcodes.IFEQ, lblAfterEq));
                instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
                                                   "TRUE", Type.getDescriptor(Boolean.class)));
                instructions.add(new InsnNode(Opcodes.ARETURN));

                instructions.add(lblAfterEq);
                instructions.add(AsmHelper.getLoadConstantInsn(null));
                instructions.add(new InsnNode(Opcodes.ARETURN));
            }

            return false;
        }

        // consider detached if auto-genned primary keys are non-default
        LabelNode ifIns = null;
        LabelNode ifIns2 = null;
        if (state != Boolean.TRUE && _meta.getIdentityType() == ClassMetaData.ID_APPLICATION) {
            // for each pk field:
            // if (<pk> != <default> [&& !"".equals (<pk>)])
            //        return Boolean.TRUE;
            FieldMetaData[] pks = _meta.getPrimaryKeyFields();
            for (FieldMetaData pk : pks) {
                if (pk.getValueStrategy() == ValueStrategies.NONE) {
                    continue;
                }

                if (ifIns != null) {
                    instructions.add(ifIns);
                }
                if (ifIns2 != null) {
                    instructions.add(ifIns2);
                }
                ifIns2 = null;
                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this

                addGetManagedValueCode(classNode, instructions, pk, true);
                ifIns = ifDefaultValue(instructions, pk);
                if (pk.getDeclaredTypeCode() == JavaTypes.STRING) {
                    instructions.add(AsmHelper.getLoadConstantInsn(""));
                    instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
                    addGetManagedValueCode(classNode, instructions, pk, true);
                    instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
                                                        Type.getInternalName(String.class),
                                                        "equals",
                                                        Type.getMethodDescriptor(Type.BOOLEAN_TYPE, AsmHelper.TYPE_OBJECT)));
                    ifIns2 = new LabelNode();
                    instructions.add(new JumpInsnNode(Opcodes.IFNE, ifIns2));
                }

                instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
                                                   "TRUE", Type.getDescriptor(Boolean.class)));
                instructions.add(new InsnNode(Opcodes.ARETURN));
            }
        }
        if (ifIns != null) {
            instructions.add(ifIns);
        }
        if (ifIns2 != null) {
            instructions.add(ifIns2);
        }

        // if detached state is not definitive, just give up now and return
        // null so that the runtime will perform a DB lookup to determine
        // whether we're detached or new
        instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
        instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
                                            classNode.name,
                                            ISDETACHEDSTATEDEFINITIVE,
                                            Type.getMethodDescriptor(Type.BOOLEAN_TYPE)));
        LabelNode lblAfterNe = new LabelNode();
        instructions.add(new JumpInsnNode(Opcodes.IFNE, lblAfterNe));
        instructions.add(AsmHelper.getLoadConstantInsn(null));
        instructions.add(new InsnNode(Opcodes.ARETURN));
        instructions.add(lblAfterNe);

        // no detached state: if instance uses detached state and it's not
        // synthetic or the instance is not serializable or the state isn't
        // transient, must not be detached
        if (state == null
                && (!ClassMetaData.SYNTHETIC.equals(_meta.getDetachedState())
                || !Serializable.class.isAssignableFrom(_meta.getDescribedType())
                || !_repos.getConfiguration().getDetachStateInstance().isDetachedStateTransient())) {
            // return Boolean.FALSE
            instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
                                               "FALSE", Type.getDescriptor(Boolean.class)));
            instructions.add(new InsnNode(Opcodes.ARETURN));
            return true;
        }

        // no detached state: if instance uses detached state (and must be
        // synthetic and transient in serializable instance at this point),
        // not detached if state not set to DESERIALIZED
        if (state == null) {
            // if (pcGetDetachedState () == null) // instead of DESERIALIZED
            //     return Boolean.FALSE;
            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
            instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
                                                classNode.name,
                                                PRE + "GetDetachedState",
                                                Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT)));
            LabelNode lblIfNn = new LabelNode();
            instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblIfNn));
            instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
                                               "FALSE", Type.getDescriptor(Boolean.class)));
            instructions.add(new InsnNode(Opcodes.ARETURN));
            instructions.add(lblIfNn);
        }

        // give up; we just don't know
        instructions.add(AsmHelper.getLoadConstantInsn(null));
        instructions.add(new InsnNode(Opcodes.ARETURN));
        return true;
    }