2

There is a library have a base class (let's call it CBase) that performs some tasks and one can create classes that extends this CBase class.

The behavior of the CBase is not enough for me, so I would like to create my own CBase class (let's call it MyCBase) that have the same methods and members but these methods don't do the same thing.

Until now everything is ok. But what blocks me is that I would like to replace CBase by MyCBase. However, I have a lot of classes that extend CBase and I don't want to change them all.

Is it possible to replace CBase by MyCBase at runtime ? So that

public class A extends CBase {}

becomes

public class A extends MyCBase {}

Can I perform this using code enhancement ? (like we do to add methods to a class at runtime. Is it also possible to change inheritance this way ?)

Thank you for your help !

EDIT

I would like to write a plugin for a framework, this is why I would like to change inheritance at runtime. This way users of the framework can use my plugin without changing their source code (changing the inheritance of their classes from CBase to MyCBase)

EDIT 2

Is it possible to do like this: ?

CtClass cc = CtClass.forName("pkg.AClass");
cc.setSuperclass(CtClass.forName("mylib.MyCBase"));
cc.compile();
Machavity
  • 30,841
  • 27
  • 92
  • 100
Fabien Henon
  • 783
  • 15
  • 37
  • 7
    Even if you could it would be a **terrible** idea. – Joachim Sauer Jul 25 '12 at 08:57
  • What is preventing you from simply editing the behaviour of CBase? – Duncan Jones Jul 25 '12 at 08:58
  • @DuncanJones I can't access the code of CBase because it's in an external library – Fabien Henon Jul 25 '12 at 09:01
  • 1
    @JoachimSauer why would it be so terrible ? I just want to replace the CBase class by the MyCBase class in a controlled set of classes – Fabien Henon Jul 25 '12 at 09:01
  • 1
    Can you use delegation to get around your problem? Also [this question](http://stackoverflow.com/questions/10046056/java-extending-class-at-runtime) – jpa Jul 25 '12 at 09:02
  • @FabienHenon: the direct base class is about the *most basic* property a class has in Java. Changing that at runtime would imply **lots** of changes (missing and different methods/fields, different access restrictions, different constructors, ...). Most of those things are closely checked by the *compiler* (which is why it must be defined at compilation time). Other languages take a much more dynamic approach to type hierarchies and are able to handle what you ask for, but Java was simply not built for this. – Joachim Sauer Jul 25 '12 at 09:03
  • @FabienHenon: If you want to change `CBase` to `MyCBase` in a controlled set of classes, then do it *before you compile*. – Joachim Sauer Jul 25 '12 at 09:04
  • @jpa I don't think so because I can't access the code of CBase. Or maybe there is another way to use delegation, do you have an idea on how to do that ? – Fabien Henon Jul 25 '12 at 09:05
  • @JoachimSauer But if MyCBase class has the exact same methods, members, etc... If everything is the same except the content of the methods ? – Fabien Henon Jul 25 '12 at 09:07
  • @FabienHenon Depends on your actual code, maybe you can wrap all your CBase manipulation inside some other classes and that way decide what to do in each situation. – jpa Jul 25 '12 at 09:09
  • @jpa I know what you mean. It's a solution, but what I wanted was just to make a script that automatically changes the inherited class – Fabien Henon Jul 25 '12 at 09:53

3 Answers3

1

I'm not expert. Probably you could extend ClassLoader. But I highly recommend don't do it. The replacement will touch many of your classes but it will be clear in code reading and app execution.

I think there is also room for architecture improvement since you have so many classes extend CBase. People are trying to remove dependencies from other libraries or keep it really small. Because in this case you could easily switch to another library or add your own functionality.

Eugen Martynov
  • 19,888
  • 10
  • 61
  • 114
  • That could be a good solution but the framework for which I would like to write a plugin already extends ClassLoader and I don't think I can change this – Fabien Henon Jul 25 '12 at 10:04
0

I dont think you can change the extends of a class at runtime. I would suggest to change the extends of the objects or build an interface, which contains all the things your need

Christian Lendel
  • 410
  • 1
  • 4
  • 13
0

Changing all derived classes is a simple matter, provided you control their source code:

  1. Create a new class in your project. Call it CBase, and put it in the same package as the library class.
  2. Use the rename/move refactoring of your IDE to rename CBase to MyBase. This will have the IDE rename all references to the renamed/moved class ...
  3. Write the code for MyBase, extending from CBase.

If you can not do this (for instance because some derived classes are in a library you do not control), you replace the implementation of CBase with your own. Simply create a class of the same package and name in your project (the classloader searches the classpath in order, and uses the first class of the proper package and name it finds). This approach however is very brittle, as the compiler can not check binary compability between the old and new version of CBase. The JVM will check this compatibility when classes are loaded, but since classes are only loaded when needed, its hard to test your changes. (Which is why I do not recommend this approach if there are other options).

You could also change the classes as they are loaded my manipulating the class file, that that's going to be even more brittle, and the compiler would allow you to use any additional features MyBase might have. ==> Definitely not a good idea.

meriton
  • 68,356
  • 14
  • 108
  • 175
  • Thank you for your answer but what I would like to do is to keep the actual source code (classes extend CBase), so that nothing changes for the other developpers (what I would like to do will be part of a plugin) and change the inheritance at runtime. Your other ideas are good but I would like something less brittle if it's possible – Fabien Henon Jul 25 '12 at 10:02
  • Any runtime manipulation of the class file will be brittle, as it is not checked by the compiler and problems are only discovered at runtime. Your fellow developers also might find it misleading if the code they see in their IDE is not the code that is executed. – meriton Jul 25 '12 at 11:54
  • I don't think they will find it misleading because my plugin must replace the existing one, so they know the behavior will be changed. Do you think using this code will do the job I want ? (and compile it): CtClass cc = CtClass.forName("pkg.AClass"); cc.setSuperclass(CtClass.forName("mylib.MyCBase")); cc.compile(); – Fabien Henon Jul 25 '12 at 12:01