Question

In a small framework I am building, I would like to change certain abstract classes to non-abstract using Javassist. I already transformed all the abstract methods in non-abstract ones implementing the dynamically generated code I need. But I have not yet succeed in making the class non-abstract. What I have tried is something similar to this:

Let's say c is the class I would like to make non abstract. So I have written:

public void instrument(Class c) {
    ...//some ignored exception management
    CtClass ctClass = ClassPool.getDefault().get(c.getName());
    ctClass.setModifiers(c.getModifiers() & ~Modifier.ABSTRACT);  
    return ctClass.toClass().newInstance();
}

However, the call to:

ctClass.toClass();

is raising the following CannotCompileException:

"attempted  duplicate class definition for name: <class_name>."

This is because the class has already been loaded, since I am invoking its getName method. It seems to me this is the only mechanism I have to get a CtClass from an existing class, but please someone tell me if that is not correct. Hardcoding the name of the class instead of calling its getName method is far from been an ideal solution, given that I need to apply this routine to many classes.

Any workaround to do this ?. If it is not possible at all I will dynamically generate a new class that extends the abstract class, implements its constructors, and the abstract method of all its ancestors (a bit more complicated, so I would be very happy if I succeed just making the original class non-abstrat instead).

Was it helpful?

Solution

The problem, as you described it, is that you have already loaded the Class you are attempting to redefine. It is illegal to attempt to redefine a class that is already loaded by a classloader.

One option might be to do a bit of classloader trickery: create a new classloader that doesn't have your existing classes loaded (parent is the system classloader) and have Javassist load through that (use aCtClass.toClass() method that takes a ClassLoader argument).

As it has suggested, there might be a better way to achieve your goal, and creating subclasses might be a better design. Is using interfaces instead of abstract classes an option? If so, dynamic proxies is an option as well, their advantage being you don't need any 3rd party libraries to create them.

OTHER TIPS

Have you tried creating an extending Class rather than changing the existing Class? So create a Class, implement all the methods and use setSuperClass() to make it extend your abstract Class.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top