Search in sources :

Example 1 with PropertyMetaData

use of org.datanucleus.metadata.PropertyMetaData in project datanucleus-core by datanucleus.

the class EnhancerClassAdapter method visitEnd.

/**
 * Method called at the end of the class.
 */
public void visitEnd() {
    AbstractClassMetaData cmd = enhancer.getClassMetaData();
    if (cmd.getPersistenceModifier() == ClassPersistenceModifier.PERSISTENCE_CAPABLE) {
        // Add any new fields
        List fields = enhancer.getFieldsList();
        Iterator fieldsIter = fields.iterator();
        while (fieldsIter.hasNext()) {
            ClassField field = (ClassField) fieldsIter.next();
            if (field.getName().equals(enhancer.getNamer().getDetachedStateFieldName()) && hasDetachedState) {
                // No need to add this field since exists
                continue;
            }
            if (DataNucleusEnhancer.LOGGER.isDebugEnabled()) {
                DataNucleusEnhancer.LOGGER.debug(Localiser.msg("005021", ((Class) field.getType()).getName() + " " + field.getName()));
            }
            cv.visitField(field.getAccess(), field.getName(), Type.getDescriptor((Class) field.getType()), null, null);
        }
        if (!hasStaticInitialisation) {
            // Add a static initialisation block for the class since nothing added yet
            InitClass method = InitClass.getInstance(enhancer);
            method.initialise(cv);
            method.execute();
            method.close();
        }
        if (!hasDefaultConstructor && enhancer.hasOption(ClassEnhancer.OPTION_GENERATE_DEFAULT_CONSTRUCTOR)) {
            // Add a default constructor
            DefaultConstructor ctr = DefaultConstructor.getInstance(enhancer);
            ctr.initialise(cv);
            ctr.execute();
            ctr.close();
        }
        // Add any new methods
        List methods = enhancer.getMethodsList();
        Iterator<ClassMethod> methodsIter = methods.iterator();
        while (methodsIter.hasNext()) {
            ClassMethod method = methodsIter.next();
            method.initialise(cv);
            method.execute();
            method.close();
        }
        if (Serializable.class.isAssignableFrom(enhancer.getClassBeingEnhanced())) {
            // Class is Serializable
            if (!hasSerialVersionUID) {
                // Needs "serialVersionUID" field
                Long uid = null;
                try {
                    uid = (Long) AccessController.doPrivileged(new PrivilegedAction() {

                        public Object run() {
                            return Long.valueOf(ObjectStreamClass.lookup(enhancer.getClassBeingEnhanced()).getSerialVersionUID());
                        }
                    });
                } catch (Throwable e) {
                    DataNucleusEnhancer.LOGGER.warn(StringUtils.getStringFromStackTrace(e));
                }
                ClassField cf = new ClassField(enhancer, enhancer.getNamer().getSerialVersionUidFieldName(), Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, long.class, uid);
                if (DataNucleusEnhancer.LOGGER.isDebugEnabled()) {
                    DataNucleusEnhancer.LOGGER.debug(Localiser.msg("005021", ((Class) cf.getType()).getName() + " " + cf.getName()));
                }
                cv.visitField(cf.getAccess(), cf.getName(), Type.getDescriptor((Class) cf.getType()), null, cf.getInitialValue());
            }
            // pc class that implements Serializable in the inheritance hierarchy needs to be modified or generated to call it.
            if (cmd.getSuperAbstractClassMetaData() == null && !hasWriteObject) {
                // User hasn't provided their own writeObject, so provide the default but with a call to dnPreSerialize first
                ClassMethod method = WriteObject.getInstance(enhancer);
                method.initialise(cv);
                method.execute();
                method.close();
            }
        }
        // Add dnGetXXX, dnSetXXX for each of the (managed) fields/properties
        for (AbstractMemberMetaData mmd : cmd.getManagedMembers()) {
            if (mmd.getPersistenceModifier() == FieldPersistenceModifier.NONE) {
                // Field/Property is not persistent so ignore
                continue;
            }
            ClassMethod getMethod = null;
            ClassMethod setMethod = null;
            if (mmd instanceof PropertyMetaData) {
            // dnGetXXX, dnSetXXX for property are typically generated when processing existing getXXX, setXXX methods
            // TODO What if the user overrode the getter and not the setter? or vice-versa?
            } else {
                // Generate dnGetXXX, dnSetXXX for field
                byte persistenceFlags = mmd.getPersistenceFlags();
                if ((persistenceFlags & Persistable.MEDIATE_READ) == Persistable.MEDIATE_READ) {
                    getMethod = new GetViaMediate(enhancer, mmd);
                } else if ((persistenceFlags & Persistable.CHECK_READ) == Persistable.CHECK_READ) {
                    getMethod = new GetViaCheck(enhancer, mmd);
                } else {
                    getMethod = new GetNormal(enhancer, mmd);
                }
                if ((persistenceFlags & Persistable.MEDIATE_WRITE) == Persistable.MEDIATE_WRITE) {
                    setMethod = new SetViaMediate(enhancer, mmd);
                } else if ((persistenceFlags & Persistable.CHECK_WRITE) == Persistable.CHECK_WRITE) {
                    setMethod = new SetViaCheck(enhancer, mmd);
                } else {
                    setMethod = new SetNormal(enhancer, mmd);
                }
            }
            if (getMethod != null) {
                getMethod.initialise(cv);
                getMethod.execute();
                getMethod.close();
            }
            if (setMethod != null) {
                setMethod.initialise(cv);
                setMethod.execute();
                setMethod.close();
            }
        }
    }
    cv.visitEnd();
}
Also used : InitClass(org.datanucleus.enhancer.methods.InitClass) SetViaCheck(org.datanucleus.enhancer.methods.SetViaCheck) SetViaMediate(org.datanucleus.enhancer.methods.SetViaMediate) PropertyMetaData(org.datanucleus.metadata.PropertyMetaData) SetNormal(org.datanucleus.enhancer.methods.SetNormal) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) GetNormal(org.datanucleus.enhancer.methods.GetNormal) GetViaCheck(org.datanucleus.enhancer.methods.GetViaCheck) GetViaMediate(org.datanucleus.enhancer.methods.GetViaMediate) PrivilegedAction(java.security.PrivilegedAction) Iterator(java.util.Iterator) List(java.util.List) ObjectStreamClass(java.io.ObjectStreamClass) InitClass(org.datanucleus.enhancer.methods.InitClass) WriteObject(org.datanucleus.enhancer.methods.WriteObject) DefaultConstructor(org.datanucleus.enhancer.methods.DefaultConstructor) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 2 with PropertyMetaData

use of org.datanucleus.metadata.PropertyMetaData in project datanucleus-core by datanucleus.

the class EnhancerClassAdapter method visitMethod.

/**
 * Method called when a method of the class is visited.
 * @param access Access for the method
 * @param name Name of the method
 * @param desc Descriptor
 * @param signature Signature
 * @param exceptions Exceptions that this method is declared to throw
 * @return Visitor to visit this (or null if not wanting to visit it)
 */
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
    if (name.equals("<init>") && desc != null && desc.equals("()V")) {
        // Check for default constructor
        hasDefaultConstructor = true;
    }
    if (name.equals("writeObject") && desc != null && desc.equals("(Ljava/io/ObjectOutputStream;)V")) {
        // Has writeObject() for use in serialisation
        hasWriteObject = true;
    }
    if (name.equals("<clinit>") && desc != null && desc.equals("()V")) {
        hasStaticInitialisation = true;
    }
    MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
    if (mv == null) {
        return null;
    }
    if (name.equals("jdoPreClear") || name.equals("jdoPostLoad")) {
        // jdoPreClear/jdoPostLoad should not be enhanced (JDO spec [10.1, 10.3]
        return mv;
    } else if (name.equals("readObject") && desc != null && (desc.equals("(Ljava/io/ObjectOutputStream;)V") || desc.equals("(Ljava/io/ObjectInputStream;)V"))) {
        // readObject(ObjectInputStream), readObject(ObjectOutputStream) should not be enhanced (JDO spec [21.6])
        return mv;
    }
    String propGetterName = ClassUtils.getFieldNameForJavaBeanGetter(name);
    String propSetterName = ClassUtils.getFieldNameForJavaBeanSetter(name);
    if (// Ignore bridge methods and treat as normal methods
    (access & Opcodes.ACC_BRIDGE) != Opcodes.ACC_BRIDGE) {
        if (propGetterName != null) {
            AbstractMemberMetaData mmd = enhancer.getClassMetaData().getMetaDataForMember(propGetterName);
            if (mmd != null && mmd instanceof PropertyMetaData && mmd.getPersistenceModifier() != FieldPersistenceModifier.NONE) {
                // Property getter method "getXXX" - generated dnGetXXX
                return new EnhancerPropertyGetterAdapter(mv, enhancer, name, desc, mmd, cv);
            }
        } else if (propSetterName != null) {
            AbstractMemberMetaData mmd = enhancer.getClassMetaData().getMetaDataForMember(propSetterName);
            if (mmd != null && mmd instanceof PropertyMetaData && mmd.getPersistenceModifier() != FieldPersistenceModifier.NONE) {
                // Property setter method "setXXX" - generates dnSetXXX
                return new EnhancerPropertySetterAdapter(mv, enhancer, name, desc, mmd, cv);
            }
        }
    }
    // normal method, so just enhance it
    return new EnhancerMethodAdapter(mv, enhancer, name, desc);
}
Also used : PropertyMetaData(org.datanucleus.metadata.PropertyMetaData) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) MethodVisitor(org.datanucleus.enhancer.asm.MethodVisitor)

Example 3 with PropertyMetaData

use of org.datanucleus.metadata.PropertyMetaData in project datanucleus-core by datanucleus.

the class EnhancerPropertyGetterAdapter method visitMethodInsn.

public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
    if (mmd instanceof PropertyMetaData) {
        // Check for any calls to getters/setters of properties that are from superclass(es)
        String ownerClassName = owner.replace('/', '.');
        AbstractClassMetaData cmd = enhancer.getClassMetaData();
        if (!enhancer.getASMClassName().equals(owner)) {
            String propName = ClassUtils.getFieldNameForJavaBeanGetter(name);
            if (propName != null) {
                boolean callingOverriddenSuperclassMethod = false;
                while (cmd.getSuperAbstractClassMetaData() != null) {
                    cmd = cmd.getSuperAbstractClassMetaData();
                    if (cmd.getFullClassName().equals(ownerClassName)) {
                        AbstractMemberMetaData theMmd = cmd.getMetaDataForMember(mmd.getName());
                        if (theMmd != null) {
                            callingOverriddenSuperclassMethod = true;
                            break;
                        }
                    }
                }
                if (callingOverriddenSuperclassMethod) {
                    // Call dnGet{propName} in owner instead of "get{propName}"
                    String redirectMethodName = enhancer.getNamer().getGetMethodPrefixMethodName() + propName;
                    visitor.visitMethodInsn(opcode, owner, redirectMethodName, desc, itf);
                    return;
                }
            }
        }
    }
    visitor.visitMethodInsn(opcode, owner, name, desc, itf);
}
Also used : PropertyMetaData(org.datanucleus.metadata.PropertyMetaData) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData)

Example 4 with PropertyMetaData

use of org.datanucleus.metadata.PropertyMetaData in project datanucleus-core by datanucleus.

the class ClassEnhancerImpl method enhance.

/**
 * Method to enhance a classes definition.
 * @return Whether it was enhanced with no errors
 */
public boolean enhance() {
    if (cmd.getPersistenceModifier() != ClassPersistenceModifier.PERSISTENCE_CAPABLE && cmd.getPersistenceModifier() != ClassPersistenceModifier.PERSISTENCE_AWARE) {
        return false;
    }
    initialise();
    if (checkClassIsEnhanced(false)) {
        // Already enhanced
        DataNucleusEnhancer.LOGGER.info(Localiser.msg("005014", className));
        return true;
    }
    try {
        // Check for generation of PK
        if (cmd.getIdentityType() == IdentityType.APPLICATION && cmd.getObjectidClass() == null && cmd.getNoOfPrimaryKeyMembers() > 1) {
            if (hasOption(OPTION_GENERATE_PK)) {
                int[] pkMemberPositions = cmd.getPKMemberPositions();
                AbstractMemberMetaData pkMmd0 = cmd.getMetaDataForManagedMemberAtAbsolutePosition(pkMemberPositions[0]);
                if (pkMmd0 instanceof PropertyMetaData) {
                    // Throw exception for invalid metadata
                    throw new InvalidMetaDataException("044136", cmd.getFullClassName());
                }
                String pkClassName = cmd.getFullClassName() + AbstractClassMetaData.GENERATED_PK_SUFFIX;
                if (DataNucleusEnhancer.LOGGER.isDebugEnabled()) {
                    DataNucleusEnhancer.LOGGER.debug(Localiser.msg("005016", cmd.getFullClassName(), pkClassName));
                }
                cmd.setObjectIdClass(pkClassName);
                PrimaryKeyGenerator pkGen = new PrimaryKeyGenerator(cmd, this);
                pkClassBytes = pkGen.generate();
            } else {
                // Throw exception for invalid metadata
                throw new InvalidMetaDataException("044065", cmd.getFullClassName(), cmd.getNoOfPrimaryKeyMembers());
            }
        }
        // Create an adapter using a writer
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        EnhancerClassAdapter cv = new EnhancerClassAdapter(cw, this);
        ClassReader cr = null;
        InputStream classReaderInputStream = null;
        try {
            // Create a reader for the class and tell it to visit the adapter, performing the changes
            if (inputBytes != null) {
                cr = new ClassReader(inputBytes);
            } else {
                classReaderInputStream = clr.getResource(inputResourceName, null).openStream();
                cr = new ClassReader(classReaderInputStream);
            }
            cr.accept(cv, 0);
            // Save the bytes
            classBytes = cw.toByteArray();
        } finally {
            if (classReaderInputStream != null) {
                classReaderInputStream.close();
            }
        }
    } catch (Exception e) {
        DataNucleusEnhancer.LOGGER.error("Error thrown enhancing with ASMClassEnhancer", e);
        return false;
    }
    update = true;
    return true;
}
Also used : InvalidMetaDataException(org.datanucleus.metadata.InvalidMetaDataException) EnhancerClassAdapter(org.datanucleus.enhancer.EnhancerClassAdapter) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) ClassReader(org.datanucleus.enhancer.asm.ClassReader) PropertyMetaData(org.datanucleus.metadata.PropertyMetaData) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) ClassWriter(org.datanucleus.enhancer.asm.ClassWriter) InvalidMetaDataException(org.datanucleus.metadata.InvalidMetaDataException) IOException(java.io.IOException)

Example 5 with PropertyMetaData

use of org.datanucleus.metadata.PropertyMetaData in project datanucleus-core by datanucleus.

the class CopyKeyFieldsFromObjectId2 method execute.

/**
 * Method to add the contents of the class method.
 */
public void execute() {
    visitor.visitCode();
    ClassMetaData cmd = enhancer.getClassMetaData();
    if (cmd.getIdentityType() == IdentityType.APPLICATION) {
        // application identity
        if (!cmd.isInstantiable()) {
            // Application identity but mapped-superclass with no PK defined, so just "return"
            Label startLabel = new Label();
            visitor.visitLabel(startLabel);
            visitor.visitInsn(Opcodes.RETURN);
            Label endLabel = new Label();
            visitor.visitLabel(endLabel);
            visitor.visitLocalVariable("this", getClassEnhancer().getClassDescriptor(), null, startLabel, endLabel, 0);
            visitor.visitLocalVariable(argNames[0], EnhanceUtils.CD_Object, null, startLabel, endLabel, 1);
            visitor.visitMaxs(0, 2);
        } else {
            String objectIdClass = cmd.getObjectidClass();
            String ACN_objectIdClass = objectIdClass.replace('.', '/');
            int[] pkFieldNums = enhancer.getClassMetaData().getPKMemberPositions();
            if (IdentityUtils.isSingleFieldIdentityClass(objectIdClass)) {
                // SingleFieldIdentity
                Label startLabel = new Label();
                visitor.visitLabel(startLabel);
                // if (!(oid instanceof LongIdentity)) throw new ClassCastException("...")
                visitor.visitVarInsn(Opcodes.ALOAD, 1);
                visitor.visitTypeInsn(Opcodes.INSTANCEOF, ACN_objectIdClass);
                Label l1 = new Label();
                visitor.visitJumpInsn(Opcodes.IFNE, l1);
                visitor.visitTypeInsn(Opcodes.NEW, "java/lang/ClassCastException");
                visitor.visitInsn(Opcodes.DUP);
                visitor.visitLdcInsn("key class is not " + objectIdClass + " or null");
                visitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/ClassCastException", "<init>", "(Ljava/lang/String;)V");
                visitor.visitInsn(Opcodes.ATHROW);
                // XXXIdentity o = (XXXIdentity) oid;
                visitor.visitLabel(l1);
                visitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
                visitor.visitVarInsn(Opcodes.ALOAD, 1);
                visitor.visitTypeInsn(Opcodes.CHECKCAST, ACN_objectIdClass);
                visitor.visitVarInsn(Opcodes.ASTORE, 2);
                // id = o.getKey();
                Label l5 = new Label();
                visitor.visitLabel(l5);
                visitor.visitVarInsn(Opcodes.ALOAD, 0);
                AbstractMemberMetaData fmd = enhancer.getClassMetaData().getMetaDataForManagedMemberAtAbsolutePosition(pkFieldNums[0]);
                Class primitiveType = ClassUtils.getPrimitiveTypeForType(fmd.getType());
                if (primitiveType != null) {
                    // The PK field is a primitive wrapper so create wrapper from getKey()
                    String ACN_fieldType = fmd.getTypeName().replace('.', '/');
                    String getKeyReturnDesc = Type.getDescriptor(primitiveType);
                    visitor.visitVarInsn(Opcodes.ALOAD, 2);
                    visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, ACN_objectIdClass, "getKey", "()" + getKeyReturnDesc);
                    visitor.visitMethodInsn(Opcodes.INVOKESTATIC, ACN_fieldType, "valueOf", "(" + getKeyReturnDesc + ")L" + ACN_fieldType + ";");
                } else {
                    // PK field isn't a primitive wrapper
                    visitor.visitVarInsn(Opcodes.ALOAD, 2);
                    visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, ACN_objectIdClass, "getKey", "()" + getNamer().getTypeDescriptorForSingleFieldIdentityGetKey(objectIdClass));
                    if (objectIdClass.equals(getNamer().getObjectIdentityClass().getName())) {
                        // Cast to the right type
                        visitor.visitTypeInsn(Opcodes.CHECKCAST, fmd.getTypeName().replace('.', '/'));
                    }
                }
                if (fmd instanceof PropertyMetaData) {
                    // Persistent property so use dnSetXXX(...)
                    visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getClassEnhancer().getASMClassName(), getNamer().getSetMethodPrefixMethodName() + fmd.getName(), "(" + Type.getDescriptor(fmd.getType()) + ")V");
                } else {
                    // Persistent field so use xxx = ...
                    visitor.visitFieldInsn(Opcodes.PUTFIELD, getClassEnhancer().getASMClassName(), fmd.getName(), Type.getDescriptor(fmd.getType()));
                }
                visitor.visitInsn(Opcodes.RETURN);
                Label l7 = new Label();
                visitor.visitLabel(l7);
                visitor.visitLocalVariable("this", getClassEnhancer().getClassDescriptor(), null, startLabel, l7, 0);
                visitor.visitLocalVariable(argNames[0], EnhanceUtils.CD_Object, null, startLabel, l7, 1);
                visitor.visitLocalVariable("o", getNamer().getSingleFieldIdentityDescriptor(objectIdClass), null, l5, l7, 2);
                visitor.visitMaxs(3, 3);
            } else {
                // User-provided app identity, and compound identity
                // Put try-catch around the field setting (for reflection cases)
                Label l0 = new Label();
                Label l1 = new Label();
                Label l2 = new Label();
                visitor.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception");
                Label startLabel = new Label();
                visitor.visitLabel(startLabel);
                visitor.visitVarInsn(Opcodes.ALOAD, 1);
                visitor.visitTypeInsn(Opcodes.INSTANCEOF, ACN_objectIdClass);
                Label l4 = new Label();
                visitor.visitJumpInsn(Opcodes.IFNE, l4);
                visitor.visitTypeInsn(Opcodes.NEW, "java/lang/ClassCastException");
                visitor.visitInsn(Opcodes.DUP);
                visitor.visitLdcInsn("key class is not " + objectIdClass + " or null");
                visitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/ClassCastException", "<init>", "(Ljava/lang/String;)V");
                visitor.visitInsn(Opcodes.ATHROW);
                visitor.visitLabel(l4);
                visitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
                visitor.visitVarInsn(Opcodes.ALOAD, 1);
                visitor.visitTypeInsn(Opcodes.CHECKCAST, ACN_objectIdClass);
                visitor.visitVarInsn(Opcodes.ASTORE, 2);
                visitor.visitLabel(l0);
                // Copy the PK members using the appropriate method for each field/property
                Label reflectionFieldStart = null;
                for (int i = 0; i < pkFieldNums.length; i++) {
                    AbstractMemberMetaData fmd = enhancer.getClassMetaData().getMetaDataForManagedMemberAtAbsolutePosition(pkFieldNums[i]);
                    String fieldTypeDesc = Type.getDescriptor(fmd.getType());
                    String fieldTypeName = fmd.getTypeName().replace('.', '/');
                    int pkFieldModifiers = ClassUtils.getModifiersForFieldOfClass(enhancer.getClassLoaderResolver(), objectIdClass, fmd.getName());
                    // Check if the PK field type is a PC (CompoundIdentity)
                    AbstractClassMetaData acmd = enhancer.getMetaDataManager().getMetaDataForClass(fmd.getType(), enhancer.getClassLoaderResolver());
                    if (acmd != null && acmd.getIdentityType() != IdentityType.NONDURABLE) {
                        // CompoundIdentity, this field of the PK is a PC
                        visitor.visitVarInsn(Opcodes.ALOAD, 0);
                        visitor.visitVarInsn(Opcodes.ALOAD, 0);
                        visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getClassEnhancer().getASMClassName(), getNamer().getGetExecutionContextMethodName(), "()L" + getNamer().getExecutionContextAsmClassName() + ";");
                        visitor.visitVarInsn(Opcodes.ALOAD, 2);
                        // TODO Cater for property/private field cases
                        visitor.visitFieldInsn(Opcodes.GETFIELD, ACN_objectIdClass, fmd.getName(), "L" + acmd.getObjectidClass().replace('.', '/') + ";");
                        visitor.visitInsn(Opcodes.ICONST_0);
                        visitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, getNamer().getExecutionContextAsmClassName(), "findObject", "(Ljava/lang/Object;Z)Ljava/lang/Object;");
                        visitor.visitTypeInsn(Opcodes.CHECKCAST, fieldTypeName);
                        if (fmd instanceof PropertyMetaData) {
                            // Persistent property so use dnSetXXX(...)
                            visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getClassEnhancer().getASMClassName(), getNamer().getSetMethodPrefixMethodName() + fmd.getName(), "(" + Type.getDescriptor(fmd.getType()) + ")V");
                        } else if (Modifier.isPublic(pkFieldModifiers)) {
                            // Persistent field that is public so use "xxx = ..."
                            visitor.visitFieldInsn(Opcodes.PUTFIELD, getClassEnhancer().getASMClassName(), fmd.getName(), Type.getDescriptor(fmd.getType()));
                        } else {
                            // Persistent field that is protected/private so use reflection
                            // TODO Use reflection rather than "xxx = ..."
                            visitor.visitFieldInsn(Opcodes.PUTFIELD, getClassEnhancer().getASMClassName(), fmd.getName(), Type.getDescriptor(fmd.getType()));
                        }
                    } else {
                        // Standard application-identity
                        if (fmd instanceof PropertyMetaData) {
                            // Field in PK is property, hence use getXXX in PK to access value
                            visitor.visitVarInsn(Opcodes.ALOAD, 0);
                            visitor.visitVarInsn(Opcodes.ALOAD, 2);
                            visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, ACN_objectIdClass, ClassUtils.getJavaBeanGetterName(fmd.getName(), fmd.getTypeName().equals("boolean")), "()" + Type.getDescriptor(fmd.getType()));
                            visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getClassEnhancer().getASMClassName(), getNamer().getSetMethodPrefixMethodName() + fmd.getName(), "(" + Type.getDescriptor(fmd.getType()) + ")V");
                        } else if (Modifier.isPublic(pkFieldModifiers)) {
                            // Field in PK is public so access directly
                            visitor.visitVarInsn(Opcodes.ALOAD, 0);
                            visitor.visitVarInsn(Opcodes.ALOAD, 2);
                            visitor.visitFieldInsn(Opcodes.GETFIELD, ACN_objectIdClass, fmd.getName(), fieldTypeDesc);
                            visitor.visitFieldInsn(Opcodes.PUTFIELD, getClassEnhancer().getASMClassName(), fmd.getName(), fieldTypeDesc);
                        } else {
                            // Field in PK is protected/private so use reflection, generating
                            // "Field field = o.getClass().getDeclaredField("pmIDFloat");"
                            // "field.setAccessible(true);"
                            // "pmIDFloat = (Float) field.get(o);"
                            visitor.visitVarInsn(Opcodes.ALOAD, 2);
                            visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;");
                            visitor.visitLdcInsn(fmd.getName());
                            visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;");
                            visitor.visitVarInsn(Opcodes.ASTORE, 3);
                            if (reflectionFieldStart == null) {
                                reflectionFieldStart = new Label();
                                visitor.visitLabel(reflectionFieldStart);
                            }
                            visitor.visitVarInsn(Opcodes.ALOAD, 3);
                            visitor.visitInsn(Opcodes.ICONST_1);
                            visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "setAccessible", "(Z)V");
                            visitor.visitVarInsn(Opcodes.ALOAD, 0);
                            visitor.visitVarInsn(Opcodes.ALOAD, 3);
                            visitor.visitVarInsn(Opcodes.ALOAD, 2);
                            if (fmd.getTypeName().equals("boolean")) {
                                visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getBoolean", "(Ljava/lang/Object;)Z");
                            } else if (fmd.getTypeName().equals("byte")) {
                                visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getByte", "(Ljava/lang/Object;)B");
                            } else if (fmd.getTypeName().equals("char")) {
                                visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getChar", "(Ljava/lang/Object;)C");
                            } else if (fmd.getTypeName().equals("double")) {
                                visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getDouble", "(Ljava/lang/Object;)D");
                            } else if (fmd.getTypeName().equals("float")) {
                                visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getFloat", "(Ljava/lang/Object;)F");
                            } else if (fmd.getTypeName().equals("int")) {
                                visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getInt", "(Ljava/lang/Object;)I");
                            } else if (fmd.getTypeName().equals("long")) {
                                visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getLong", "(Ljava/lang/Object;)L");
                            } else if (fmd.getTypeName().equals("short")) {
                                visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getShort", "(Ljava/lang/Object;)S");
                            } else if (fmd.getTypeName().equals("java.lang.String")) {
                                visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
                                visitor.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
                            } else {
                                visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
                                visitor.visitTypeInsn(Opcodes.CHECKCAST, fieldTypeName);
                            }
                            visitor.visitFieldInsn(Opcodes.PUTFIELD, getClassEnhancer().getASMClassName(), fmd.getName(), fieldTypeDesc);
                        }
                    }
                }
                // catch of the try-catch
                visitor.visitLabel(l1);
                Label l16 = new Label();
                visitor.visitJumpInsn(Opcodes.GOTO, l16);
                visitor.visitLabel(l2);
                visitor.visitFrame(Opcodes.F_FULL, 3, new Object[] { getClassEnhancer().getASMClassName(), "java/lang/Object", ACN_objectIdClass }, 1, new Object[] { "java/lang/Exception" });
                visitor.visitVarInsn(Opcodes.ASTORE, 3);
                visitor.visitLabel(l16);
                visitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
                visitor.visitInsn(Opcodes.RETURN);
                Label endLabel = new Label();
                visitor.visitLabel(endLabel);
                visitor.visitLocalVariable("this", getClassEnhancer().getClassDescriptor(), null, startLabel, endLabel, 0);
                visitor.visitLocalVariable(argNames[0], EnhanceUtils.CD_Object, null, startLabel, endLabel, 1);
                visitor.visitLocalVariable("o", "L" + ACN_objectIdClass + ";", null, l0, endLabel, 2);
                if (reflectionFieldStart != null) {
                    visitor.visitLocalVariable("field", "Ljava/lang/reflect/Field;", null, reflectionFieldStart, l2, 3);
                    visitor.visitMaxs(3, 4);
                } else {
                    visitor.visitMaxs(3, 3);
                }
            }
        }
    } else {
        // datastore/nondurable identity
        Label startLabel = new Label();
        visitor.visitLabel(startLabel);
        visitor.visitInsn(Opcodes.RETURN);
        Label l1 = new Label();
        visitor.visitLabel(l1);
        visitor.visitLocalVariable("this", getClassEnhancer().getClassDescriptor(), null, startLabel, l1, 0);
        visitor.visitLocalVariable(argNames[0], EnhanceUtils.CD_Object, null, startLabel, l1, 1);
        visitor.visitMaxs(0, 2);
    }
    visitor.visitEnd();
}
Also used : Label(org.datanucleus.enhancer.asm.Label) PropertyMetaData(org.datanucleus.metadata.PropertyMetaData) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) ClassMetaData(org.datanucleus.metadata.ClassMetaData) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData)

Aggregations

PropertyMetaData (org.datanucleus.metadata.PropertyMetaData)26 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)18 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)9 Label (org.datanucleus.enhancer.asm.Label)8 ClassMetaData (org.datanucleus.metadata.ClassMetaData)6 FieldMetaData (org.datanucleus.metadata.FieldMetaData)5 AttributeConverter (javax.jdo.AttributeConverter)3 PersistenceNucleusContext (org.datanucleus.PersistenceNucleusContext)3 JDOTypeConverter (org.datanucleus.api.jdo.JDOTypeConverter)3 FieldPersistenceModifier (org.datanucleus.metadata.FieldPersistenceModifier)3 InvalidMetaDataException (org.datanucleus.metadata.InvalidMetaDataException)3 Iterator (java.util.Iterator)2 Column (javax.jdo.annotations.Column)2 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)2 ArrayMetaData (org.datanucleus.metadata.ArrayMetaData)2 CollectionMetaData (org.datanucleus.metadata.CollectionMetaData)2 ColumnMetaData (org.datanucleus.metadata.ColumnMetaData)2 InterfaceMetaData (org.datanucleus.metadata.InterfaceMetaData)2 MapMetaData (org.datanucleus.metadata.MapMetaData)2 TypeManager (org.datanucleus.store.types.TypeManager)2