/** * 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 (JDO2 spec [10.1, 10.3] return mv; } else if (name.equals("readObject") && (desc.equals("(Ljava/io/ObjectOutputStream;)V") || desc.equals("(Ljava/io/ObjectInputStream;)V"))) { // readObject(ObjectInputStream), readObject(ObjectOutputStream) should not be enhanced (JDO2 // spec [21.6]) return mv; } String propGetterName = ClassUtils.getFieldNameForJavaBeanGetter(name); String propSetterName = ClassUtils.getFieldNameForJavaBeanSetter(name); 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); }
/** * Method called when a field of the class is visited. * * @param access Access type * @param name Name of the field * @param desc Descriptor of the field * @param signature Signature of the field * @param value Value of the field * @return FieldVisitor */ public FieldVisitor visitField( int access, String name, String desc, String signature, Object value) { if (name.equals(enhancer.getNamer().getSerialVersionUidFieldName())) { // Has serialVersionUID field for use in serialisation hasSerialVersionUID = true; } else if (name.equals(enhancer.getNamer().getDetachedStateFieldName())) { // Has xxxDetachedState field hasDetachedState = true; } return super.visitField(access, name, desc, signature, value); }
/** Main entry for this transformer. */ public void doTransformInterface(ClassEnhancer ce, ClassGen cg) { String class_name = cg.getClassName(); ConstantPoolGen cpg = cg.getConstantPool(); checkReadClassAttributes(ce, cg, class_name, cpg); generateFieldAccessForCallout(ce, cg, class_name, cpg); generateSuperAccessors(ce, cg, class_name, cpg); HashSet<String> calloutBindings = CallinBindingManager.getCalloutBindings(class_name); if (calloutBindings == null) { if (logging) printLogMessage("\nClass " + class_name + " requires no callout adjustment."); return; } if (logging) printLogMessage("\nCallout bindings might be changing class " + class_name + ":"); HashSet<String> oldStyleBinding = new HashSet<String>(); // try new style decapsulation first (since 1.2.8): for (String calloutBinding : calloutBindings) { DecapsulationDescriptor desc = new DecapsulationDescriptor(); if (!desc.decode(calloutBinding, cg)) oldStyleBinding.add(calloutBinding); // old style attribute else if (!desc.existsAlready) ce.addMethod(desc.generate(class_name, cpg), cg); } if (oldStyleBinding.isEmpty()) return; // --> follows: old style decapsulation for remaining bindings: int pos = class_name.lastIndexOf('.'); String package_name = "NO_PACKAGE"; if (pos != -1) package_name = class_name.substring(0, pos); Method[] methods = cg.getMethods(); for (int i = 0; i < methods.length; i++) { Method m = methods[i]; String method_name = m.getName(); boolean requiresAdjustment = CallinBindingManager.requiresCalloutAdjustment( oldStyleBinding, method_name, m.getSignature()); if (requiresAdjustment) { ce.decapsulateMethod(m, cg, package_name, cpg); } } }
/** * Generates getter and setter methods for all fields of the class 'class_name' which are accessed * via callout. Informations are received via attributs (CallinBindingManager). * * @param cg the ClassGen of the appropriate class * @param class_name the name of the class * @param cpg the ConstantPoolGen of the class * @param es the ExtensionSet to add the new access methods */ private void generateFieldAccessForCallout( ClassEnhancer ce, ClassGen cg, String class_name, ConstantPoolGen cpg) { InstructionFactory factory = null; HashSet<String> addedAccessMethods = this.generatedFieldCalloutAccessors; List<FieldDescriptor> getter = CallinBindingManager.getCalloutGetFields(class_name); if (getter != null) { factory = new InstructionFactory(cg); Iterator<FieldDescriptor> it = getter.iterator(); while (it.hasNext()) { FieldDescriptor fd = it.next(); String key = "get_" + class_name + "." + fd.getFieldName() + fd.getFieldSignature(); if (logging) printLogMessage("Generating getter method " + key); if (addedAccessMethods == null) addedAccessMethods = new HashSet<String>(); if (addedAccessMethods.contains(key)) continue; // this getter has already been created ce.addMethod(generateGetter(cpg, class_name, fd, factory), cg); addedAccessMethods.add(key); } } List<FieldDescriptor> setter = CallinBindingManager.getCalloutSetFields(class_name); if (setter != null) { if (factory == null) factory = new InstructionFactory(cg); Iterator<FieldDescriptor> it = setter.iterator(); while (it.hasNext()) { FieldDescriptor fd = it.next(); String key = "set_" + class_name + "." + fd.getFieldName() + fd.getFieldSignature(); if (logging) printLogMessage("Generating setter method " + key); if (addedAccessMethods == null) addedAccessMethods = new HashSet<String>(); if (addedAccessMethods.contains(key)) continue; // this setter has already been created ce.addMethod(generateSetter(cpg, class_name, fd, factory), cg); addedAccessMethods.add(key); } } }
private void generateSuperAccessors( ClassEnhancer ce, ClassGen cg, String class_name, ConstantPoolGen cpg) { InstructionFactory factory = null; HashSet<String> addedAccessMethods = this.generatedSuperAccessors; List<SuperMethodDescriptor> methods = CallinBindingManager.getSuperAccesses(class_name); if (methods != null) { factory = new InstructionFactory(cg); for (SuperMethodDescriptor superMethod : methods) { String key = superMethod.methodName + '.' + superMethod.signature; if (logging) printLogMessage("Generating super access method " + key); if (addedAccessMethods == null) addedAccessMethods = new HashSet<String>(); if (addedAccessMethods.contains(key)) continue; // this accessor has already been created ce.addMethod(generateSuperAccessor(cpg, class_name, superMethod, factory), cg); addedAccessMethods.add(key); } } }
/** Enhances the given class. */ public byte[] enhance(JClass jClass) throws ClassNotFoundException { String className = jClass.getName().replace('/', '.'); String extClassName = className + "__ResinExt"; try { EnhancerPrepare prepare = new EnhancerPrepare(); prepare.setWorkPath(getWorkPath()); prepare.setClassLoader(_loader); for (ClassEnhancer enhancer : _classEnhancerList) { if (enhancer.shouldEnhance(className)) { prepare.addEnhancer(enhancer); } } // prepare.renameClass(className, extClassName); prepare.renameClass(className, className); } catch (Exception e) { log.log(Level.FINE, e.toString(), e); throw new ClassNotFoundException(e.toString()); } boolean hasEnhancer = false; GenClass genClass = new GenClass(extClassName); genClass.setSuperClassName(className); for (ClassEnhancer enhancer : _classEnhancerList) { if (enhancer.shouldEnhance(className)) { try { hasEnhancer = true; enhancer.enhance(genClass, jClass, extClassName); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } } // XXX: class-wide enhancements need to go first try { if (hasEnhancer) { _javaGen.setWorkDir(getPreWorkPath()); _javaGen.generate(genClass); _javaGen.compilePendingJava(); } EnhancerFixup fixup = new EnhancerFixup(); fixup.setJavaClassLoader(_jClassLoader); fixup.setClassLoader(_loader); fixup.setWorkPath(getWorkPath()); for (ClassEnhancer enhancer : _classEnhancerList) { if (enhancer.shouldEnhance(className)) { fixup.addEnhancer(enhancer); } } fixup.fixup(className, extClassName); return load(className); } catch (RuntimeException e) { throw e; } catch (Exception e) { log.log(Level.FINE, e.toString(), e); throw new ClassNotFoundException(e.getMessage()); } // return null; }
/** * Method called to visit the header of the class. * * @param version Version of this class * @param access Access for the class * @param name name of the class * @param signature Signature of the class * @param superName Superclass name (if any) * @param interfaces Interface(s) implemented */ public void visit( int version, int access, String name, String signature, String superName, String[] interfaces) { if (enhancer.getClassMetaData().getPersistenceModifier() == ClassPersistenceModifier.PERSISTENCE_CAPABLE) { // Check if the class already implements required interfaces boolean alreadyPersistable = false; boolean alreadyDetachable = false; boolean needsPersistable = false; boolean needsDetachable = false; int numInterfaces = 0; if (interfaces != null && interfaces.length > 0) { numInterfaces = interfaces.length; for (int i = 0; i < interfaces.length; i++) { if (interfaces[i].equals(enhancer.getNamer().getDetachableAsmClassName())) { alreadyDetachable = true; } if (interfaces[i].equals(enhancer.getNamer().getPersistableAsmClassName())) { alreadyPersistable = true; } } } if (!alreadyDetachable && enhancer.getClassMetaData().isDetachable()) { numInterfaces++; needsDetachable = true; } if (!alreadyPersistable) { numInterfaces++; needsPersistable = true; } String[] intfs = interfaces; if (needsDetachable || needsPersistable) { // Allocate updated array of interfaces intfs = new String[numInterfaces]; int position = 0; if (interfaces != null && interfaces.length > 0) { for (int i = 0; i < interfaces.length; i++) { intfs[position++] = interfaces[i]; } } if (needsDetachable) { intfs[position++] = enhancer.getNamer().getDetachableAsmClassName(); if (DataNucleusEnhancer.LOGGER.isDebugEnabled()) { DataNucleusEnhancer.LOGGER.debug( Localiser.msg("005022", enhancer.getNamer().getDetachableClass().getName())); } } if (needsPersistable) { intfs[position++] = enhancer.getNamer().getPersistableAsmClassName(); if (DataNucleusEnhancer.LOGGER.isDebugEnabled()) { DataNucleusEnhancer.LOGGER.debug( Localiser.msg("005022", enhancer.getNamer().getPersistableClass().getName())); } } } cv.visit(version, access, name, signature, superName, intfs); } else { cv.visit(version, access, name, signature, superName, interfaces); } }
/** 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()); } // The dnPreSerialize method need be called only once for a persistent instance. The // writeObject method in the least-derived // 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 AbstractMemberMetaData[] fmds = cmd.getManagedMembers(); for (int i = 0; i < fmds.length; i++) { if (fmds[i].getPersistenceModifier() == FieldPersistenceModifier.NONE) { // Field/Property is not persistent so ignore continue; } byte persistenceFlags = fmds[i].getPersistenceFlags(); ClassMethod getMethod = null; ClassMethod setMethod = null; if (fmds[i] instanceof PropertyMetaData) { // dnGetXXX, dnSetXXX for property are generated when processing existing getXXX, setXXX // methods } else { // Generate dnGetXXX, dnSetXXX for field if ((persistenceFlags & Persistable.MEDIATE_READ) == Persistable.MEDIATE_READ) { getMethod = new GetViaMediate(enhancer, fmds[i]); } else if ((persistenceFlags & Persistable.CHECK_READ) == Persistable.CHECK_READ) { getMethod = new GetViaCheck(enhancer, fmds[i]); } else { getMethod = new GetNormal(enhancer, fmds[i]); } if ((persistenceFlags & Persistable.MEDIATE_WRITE) == Persistable.MEDIATE_WRITE) { setMethod = new SetViaMediate(enhancer, fmds[i]); } else if ((persistenceFlags & Persistable.CHECK_WRITE) == Persistable.CHECK_WRITE) { setMethod = new SetViaCheck(enhancer, fmds[i]); } else { setMethod = new SetNormal(enhancer, fmds[i]); } } if (getMethod != null) { getMethod.initialise(cv); getMethod.execute(); getMethod.close(); } if (setMethod != null) { setMethod.initialise(cv); setMethod.execute(); setMethod.close(); } } } cv.visitEnd(); }