2 Replies Latest reply on Nov 27, 2005 10:06 AM by johncoleman

    loading a modified class directly from a ClassFile

    johncoleman

      I got this to work, just that the classes subclasses now throw java.lang.AbstractMethodError exceptions!

      // get the class file as a resource
      InputStream is = getClass().getResourceAsStream(resourceName);
      DataInputStream dis = new DataInputStream(is);
      // create a class file object from the class file
      ClassFile cf = new ClassFile(dis);
      // modify the class
      cf.addInterface(interfaceName);
      // create an output stream for the new class
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      DataOutputStream dos = new DataOutputStream(baos);
      // write the new class into a byte array using the data output stream
      cf.write(dos);
      // close resources
      dos.close();
      baos.close();
      dis.close();
      // get the modified class and pass to this classes class loader
      is = new ByteArrayInputStream(baos.toByteArray());
      // make a class anonymously
      CtClass ptc = pool.makeClass(is);
      is.close();
      // force the class loader to load the modified class
      ptc.toClass(getClass().getClassLoader());

      At least the class loader gets your new version of the class.

        • 1. Re: loading a modified class directly from a ClassFile
          chiba

          I think it would be better to use ClassPool, CtClass, etc.
          Your problem is that you added an interface but did not
          change your class to be an abstract class (your class does
          not implement all methods from the interface.)

          • 2. Re: loading a modified class directly from a ClassFile
            johncoleman

             

            "chiba" wrote:
            I think it would be better to use ClassPool, CtClass, etc.
            Your problem is that you added an interface but did not
            change your class to be an abstract class (your class does
            not implement all methods from the interface.)


            You are correct. I tried using ClassPool before but kept getting duplicate class exceptions. I have tried again and have everything working perfectly. This is my code to implement an interface and create getters and setters to inherit from a superclass if required....

            CtClass ptc = pool.get(className);
            CtClass pti = pool.get(interfaceName);
            CtMethod[] ptims = pti.getDeclaredMethods();
            if (!pti.isInterface()) {
            log.fatal("The class " + interfaceName
            + " is not an interface.");
            return;
            }
            for (int m = 0; m < ptims.length; m++) {
            // see if class defines the method when method is get or set
            if (ptims[m].getMethodInfo().isMethod()
            && (ptims[m].getName().startsWith("get") || ptims[m]
            .getName().startsWith("set"))) {
            try {
            // see if method already declared in class
            CtMethod ptcm = ptc.getDeclaredMethod(ptims[m]
            .getName(), ptims[m].getParameterTypes());
            } catch (NotFoundException ex1) {
            // the method is not declared and needs to be added
            // if not in superclass then a problem!
            boolean inSuper;
            try {
            CtMethod ptcm = ptc.getMethod(ptims[m].getName(),
            ptims[m].getSignature());
            inSuper = true;
            } catch (NotFoundException ex2) {
            inSuper = false;
            }
            // quit if method unavailable from superclass
            if (!inSuper) {
            log.fatal("Method " + ptims[m].getName()
            + " not available in " + className
            + " class.");
            return;
            }
            // class does not define method so add it
            if (ptims[m].getName().startsWith("get")) {
            String body = "public "
            + ptims[m].getReturnType().getName() + " "
            + ptims[m].getName() + "() { return super."
            + ptims[m].getName() + "(); }";
            log.debug("add " + body + " to class " + className);
            CtMethod nm = CtNewMethod.make(body, ptc);
            ptc.addMethod(nm);

            }
            if (ptims[m].getName().startsWith("set")) {
            String type = ptims[m].getParameterTypes()[0]
            .getName();
            String body = "public void " + ptims[m].getName()
            + "(" + type + " x" + ") { super."
            + ptims[m].getName() + "(x); }";
            log.debug("add " + body + " to class " + className);
            CtMethod nm = CtNewMethod.make(body, ptc);
            ptc.addMethod(nm);
            }
            }
            }
            }
            ptc.addInterface(pti);
            // force the class loader to load the modified class
            ptc.toClass(getClass().getClassLoader());