private void addCopyKeyFieldsFromObjectIdMethod()

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


    private void addCopyKeyFieldsFromObjectIdMethod(boolean fieldManager) throws NoSuchMethodException {
        // public void pcCopyKeyFieldsFromObjectId (ObjectIdFieldConsumer fc, Object oid)
        String mDesc = fieldManager
                ? Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(OIDFCTYPE), AsmHelper.TYPE_OBJECT)
                : Type.getMethodDescriptor(Type.VOID_TYPE, AsmHelper.TYPE_OBJECT);
        MethodNode copyKFMeth = new MethodNode(Opcodes.ACC_PUBLIC,
                                               PRE + "CopyKeyFieldsFromObjectId",
                                               mDesc,
                                               null, null);
        final ClassNode classNode = pc.getClassNode();
        classNode.methods.add(copyKFMeth);
        InsnList instructions = copyKFMeth.instructions;


        // call superclass method
        if (_meta.getPCSuperclass() != null && !getCreateSubclass()) {
            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
            instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st parameter object
            if (fieldManager) {
                instructions.add(new VarInsnNode(Opcodes.ALOAD, 2)); // 2nd parameter object
            }
            instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
                                                Type.getInternalName(getType(_meta.getPCSuperclassMetaData())),
                                                PRE + "CopyKeyFieldsFromObjectId",
                                                mDesc));
        }

        // Object id = oid;
        if (fieldManager) {
            instructions.add(new VarInsnNode(Opcodes.ALOAD, 2)); // 2nd parameter object
        }
        else {
            instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st parameter object
        }

        if (!_meta.isOpenJPAIdentity() && _meta.isObjectIdTypeShared()) {
            // oid = ((ObjectId) id).getId ();
            instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, Type.getInternalName(ObjectId.class)));
            instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
                                                Type.getInternalName(ObjectId.class),
                                                "getId",
                                                Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT)));
        }

        // <oid type> id = (<oid type>) oid;
        int nextFreeVarPos = (fieldManager) ? 3 : 2;
        int idVarPos = nextFreeVarPos++;

        Class oidType = _meta.getObjectIdType();
        instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, Type.getInternalName(oidType)));
        instructions.add(new VarInsnNode(Opcodes.ASTORE, idVarPos));

        // fs.store<type>Field (<index>, id.<field>); or...
        // this.<field> = id.<field>
        // or for single field identity: id.getId ()
        FieldMetaData[] fmds = getCreateSubclass() ? _meta.getFields()
                : _meta.getDeclaredFields();
        for (int i = 0; i < fmds.length; i++) {
            if (!fmds[i].isPrimaryKey()) {
                continue;
            }

            String name = fmds[i].getName();
            Class<?> type = fmds[i].getObjectIdFieldType();

            if (!fieldManager && fmds[i].getDeclaredTypeCode() == JavaTypes.PC) {
                // if (sm == null) return;
                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
                instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));

                LabelNode lblEndIfNotNull = new LabelNode();
                instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblEndIfNotNull));
                instructions.add(new InsnNode(Opcodes.RETURN));

                instructions.add(lblEndIfNotNull);

                // sm.getPCPrimaryKey(oid, i + pcInheritedFieldCount);
                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
                instructions.add(new InsnNode(Opcodes.DUP)); // leave orig on stack to set value into
                instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));
                instructions.add(new VarInsnNode(Opcodes.ALOAD, idVarPos));
                instructions.add(AsmHelper.getLoadConstantInsn(i));
                instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, classNode.name, INHERIT, Type.INT_TYPE.getDescriptor()));
                instructions.add(new InsnNode(Opcodes.IADD));
                instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
                                                    Type.getInternalName(SMTYPE),
                                                    "getPCPrimaryKey",
                                                    Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT, AsmHelper.TYPE_OBJECT, Type.INT_TYPE)));
                instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, Type.getInternalName(fmds[i].getDeclaredType())));
            }
            else {
                Class<?> unwrapped = (fmds[i].getDeclaredTypeCode() == JavaTypes.PC) ? type : unwrapSingleFieldIdentity(fmds[i]);
                if (fieldManager) {
                    instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
                    instructions.add(AsmHelper.getLoadConstantInsn(i));
                    instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, classNode.name, INHERIT, Type.INT_TYPE.getDescriptor()));
                    instructions.add(new InsnNode(Opcodes.IADD));
                }
                else {
                    instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
                }

                if (unwrapped != type && type != Long.class) {
                    instructions.add(new TypeInsnNode(Opcodes.NEW, Type.getInternalName(type)));
                    instructions.add(new InsnNode(Opcodes.DUP));
                }

                instructions.add(new VarInsnNode(Opcodes.ALOAD, idVarPos));
                if (_meta.isOpenJPAIdentity()) {
                    if (oidType == ObjectId.class) {
                        instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
                                                            Type.getInternalName(oidType),
                                                            "getId",
                                                            Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT)));
                        if (!fieldManager && type != Object.class) {
                            instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, Type.getInternalName(fmds[i].getDeclaredType())));
                        }
                    }
                    else if (oidType == DateId.class) {
                        instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
                                                            Type.getInternalName(oidType),
                                                            "getId",
                                                            Type.getMethodDescriptor(Type.getType(Date.class))));
                        if (!fieldManager && type != Date.class) {
                            instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, Type.getInternalName(fmds[i].getDeclaredType())));
                        }
                    }
                    else {
                        instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
                                                            Type.getInternalName(oidType),
                                                            "getId",
                                                            Type.getMethodDescriptor(Type.getType(unwrapped))));
                        if (unwrapped != type) {
                            if (type == Long.class) {
                                instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC,
                                                                    Type.getInternalName(type),
                                                                    LONG_VALUE_OF.getName(),
                                                                    Type.getMethodDescriptor(LONG_VALUE_OF)));
                            } else {
                                instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
                                                                    Type.getInternalName(type),
                                                                    "<init>",
                                                                    Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(unwrapped))));
                            }
                        }
                    }
                }
                else if (isFieldAccess(fmds[i])) {
                    Field field = Reflection.findField(oidType, name, true);
                    if (Modifier.isPublic(field.getModifiers())) {
                        instructions.add(new FieldInsnNode(Opcodes.GETFIELD,
                                                           Type.getInternalName(field.getDeclaringClass()),
                                                           field.getName(),
                                                           Type.getDescriptor(field.getType())));
                    }
                    else {
                        boolean usedFastOid = false;
                        if (_optimizeIdCopy) {
                            // If fastOids, ignore access type and try to use a public getter
                            Method getter = Reflection.findGetter(oidType, name, false);
                            if (getter != null && Modifier.isPublic(getter.getModifiers())) {
                                usedFastOid = true;
                                instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
                                                                    Type.getInternalName(getter.getDeclaringClass()),
                                                                    getter.getName(),
                                                                    Type.getMethodDescriptor(getter)));
                            }
                        }
                        if (!usedFastOid) {
                            // Reflection.getXXX(oid, Reflection.findField(...));
                            instructions.add(AsmHelper.getLoadConstantInsn(oidType));
                            instructions.add(AsmHelper.getLoadConstantInsn(name));
                            instructions.add(AsmHelper.getLoadConstantInsn(true));
                            instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC,
                                                                Type.getInternalName(Reflection.class),
                                                                "findField",
                                                                Type.getMethodDescriptor(Type.getType(Field.class), Type.getType(Class.class),
                                                                                         Type.getType(String.class), Type.BOOLEAN_TYPE)));

                            final Method reflectionGetterMethod = getReflectionGetterMethod(type, Field.class);
                            instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC,
                                                                Type.getInternalName(reflectionGetterMethod.getDeclaringClass()),
                                                                reflectionGetterMethod.getName(),
                                                                Type.getMethodDescriptor(reflectionGetterMethod)));
                            if (!type.isPrimitive() && type != Object.class) {
                                instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, Type.getInternalName(type)));
                            }
                        }
                    }
                }
                else {
                    Method getter = Reflection.findGetter(oidType, name, true);
                    if (Modifier.isPublic(getter.getModifiers())) {
                        instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
                                                            Type.getInternalName(getter.getDeclaringClass()),
                                                            getter.getName(),
                                                            Type.getMethodDescriptor(getter)));
                    }
                    else {
                        // Reflection.getXXX(oid, Reflection.findGetter(...));
                        instructions.add(AsmHelper.getLoadConstantInsn(oidType));
                        instructions.add(AsmHelper.getLoadConstantInsn(name));
                        instructions.add(AsmHelper.getLoadConstantInsn(true));
                        instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC,
                                                            Type.getInternalName(Reflection.class),
                                                            "findGetter",
                                                            Type.getMethodDescriptor(Type.getType(Method.class), Type.getType(Class.class),
                                                                                     Type.getType(String.class), Type.BOOLEAN_TYPE)));

                        final Method reflectionGetterMethod = getReflectionGetterMethod(type, Method.class);
                        instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC,
                                                            Type.getInternalName(reflectionGetterMethod.getDeclaringClass()),
                                                            reflectionGetterMethod.getName(),
                                                            Type.getMethodDescriptor(reflectionGetterMethod)));
                        if (!type.isPrimitive() && type != Object.class) {
                            instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, Type.getInternalName(type)));
                        }
                    }
                }
            }

            if (fieldManager) {
                final Method fieldConsumerMethod = getFieldConsumerMethod(type);
                instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
                                                    Type.getInternalName(fieldConsumerMethod.getDeclaringClass()),
                                                    fieldConsumerMethod.getName(),
                                                    Type.getMethodDescriptor(fieldConsumerMethod)));
            }
            else {
                addSetManagedValueCode(classNode, instructions, fmds[i]);
            }
        }

        instructions.add(new InsnNode(Opcodes.RETURN));
    }