/**
   * 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);
 }
Beispiel #3
0
  /** 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);
      }
    }
  }
Beispiel #4
0
  /**
   * 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);
      }
    }
  }
Beispiel #5
0
  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);
      }
    }
  }
Beispiel #6
0
  /** 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();
  }