Make a class extends another class at runtime - java

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();

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.

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

Changing all derived classes is a simple matter, provided you control their source code:
Create a new class in your project. Call it CBase, and put it in the same package as the library class.
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 ...
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.

Related

Prevent dependency on a class in Java / Kotlin, but allow extending

I wish to create a useful base Java class with a few protected methods and hooks so subclasses can be easily implemented.
However, I wish this class to ONLY be available for deriving a subclass, but not available as a dependency.
The reason is to prevent some junior/careless developers from coupling their code to this base class.
For example, if my base class is called BaseActivity.java, anyone can create their own
public class MyNewActivity extends BaseActivity
But no one can refer directly to BaseActivity with a field or method signature, for example this should not be allowed:
public void doSomethingOnBaseActivity(BaseActivity activity);
private BaseActivity someField;
public BaseActivity getActivity();
Is there any way to accomplish such a restriction in Java?
Maybe in Kotlin this would be possible?
EDIT:
This is NOT a duplicate of Kotlin: Can an abstract super class have an abstract constructor?.
I wish to prevent dependency on the base class, not just instantiation. "Abstract" doesn't help here.
No, this is not possible. This answer is true for all types, whether abstract or not, interface or class. When you are in the scope of a class (e.g. same package), and this class is not sealed then everybody in this scope can inherit it. As long you are inside the scope, you can reference this type. That's the point of access modifiers. It doesn't make sense to allow extension of a type but not referencing it. This contradicts the concept. Why would you want to do that? You can't remove that base class anyway because that would break the code of all inheritors. There is no point in allowing extension but disallowing referencing. What is the reason for this. Maybe there is a different way to accomplish your goal. The very moment somebody inherits from a type creates the dependency. This dependency is called inheritance. The subtype is a supertype. You can't hide this fact from the compiler.
If you want to omit a dependency but reuse code or provide a template of the code then don't use a type. You could use file templates or a code generator to generate the reusable code (like code snippets).
First off, let's address the why. Why are you looking for this? You're looking for a way to prevent the consumer from calling unwanted methods on a base class.
If you think you're looking for something else, think again. If you just want to hide it, think again. The end user will not care about implementation details at all.
If you created the base class, then don't publish an API that allows this in the first place. There was a chapter on this specifically in Clean Code.
If your base class extends another base class you're in trouble. You can't hide already published API, if you're extending and not encapsulating.
I wish this class to ONLY be available for deriving a subclass, but not available as a dependency. Is there any way to accomplish such a restriction in Java? Maybe in Kotlin this would be possible?
No. This is not an opinion, this is by design.
There may be a convoluted way to hide methods of parent classes but not on the class the consumer interacts with (extends).
You could have several layers of base classes each within its own Gradle module and setup implementation type dependency but then If you can extend the class, if you can see it, reference it, you can also use it anywhere.
Imagine this:
consumer module -> ConsumerActivity extends ExtensibleActivity
your library module -> ExtensibleActivity extends BaseActivity
your base library module -> BaseActivity extends Activity
Android SDK -> Activity
Consumer module only sees what's inside "your library module". It knows about ExtensibleActivity but it can't see any of its super types. The consumer can still reference ExtensibleActivity and its methods. The side effect is because the superclasses are not known from consumer's point of view, you can't pass an instance of ExtensibleActivity as an Activity because the type system doesn't know it extends an Activity, because it doesn't see the BaseActivity intermediary type. Here's a graph of what the consumer sees:
ConsumerActivity -> ExtensibleActivity -> BaseActivity (doesn't exist) -> ??? (don't know)
At this point you just have to ask yourself "should this have extended Activity in the first place?".
This is just terrible to work with. Lot of wasted effort for something that you shouldn't need to worry about.
If you want to conceal something, use composition over inheritance. Put your logic inside a Fragment or, better yet, put your logic inside a custom lifecycle aware component. That way you're in total control over the API. Make it so you don't have to worry about where it gets called from.
Write good documentation for your code and a usage manual.
And kindly allow me to break your damn library if I choose to use it incorrectly.
Do you have multiple methods in your API? Great! Nobody will prevent me from calling them out of order. You can write in your manual how it's supposed to be used, but ultimately, I'm writing my program, using your library, and if I do it wrong, then it's my fault when it breaks. This is fine.

Hiding Package Name using Proguard but keeping certain Methods in a class public

I'm trying to create an Android Library that is kept simple in that whoever implements it only sees one class of that library. I've gotten ProGuard to hide most everything I need hidden, but some package names still appear even after the class names are obfuscated. Example:
com.app.parsers
com.app.camera
com.app
These are my packages, and when I export my .aar into another project, I can still see the package names. However, once I get there, there is no other need for it. Most of the classes are protected, with a a Public class and a Public interface that the public class extends.
For reference, in my project view, the following is visible:
com.app.parsers.jsonParser
com.app.parsers.xmlParser
com.app.parsers.csvParser
com.app.parsers.ManagerInterface(public)
com.app.parsers.ParserManager(public)
Essentially the reason I have parser manager public (and it's interface) is because it acts as an entry point (or proxy) to my various different parsers.So I keep it organized this way. So when I use proguard I don't see anything here I just see an empty package that says com.app.parsers and then a list of just generic cast, instanof or what have you. I want to hide this so that it's not distracting for anyone to use or they wonder why it exist or whats in there.
I don't think it's a huge deal having them exposed, as long as your code is well documented.
But you could try either using either
#hide annotation
or the Facade pattern

Make a Java class have higher compile priority than one inside a library in IDEA

We have some portion of functionality packed in an external library and it is attached to our project. That library can't be changed in any way. Amongst others there are two classes lying inside it: com.myorg.Grandpa and com.myorg.Dad that extends com.myorg.Grandpa. Also there are com.myorg.Grandson extending com.myorg.Dad and a few other classes outside of the library extending com.myorg.Grandpa.
I decompile com.myorg.Grandpa class and add a new method new_method() to it.
Then I try to use new_method() in com.myorg.Grandson but IDEA won't let me do it cause Grandson extends Dad which extends library's Grandpa which doesn't contain new_method().
I tried to delete Grandpa from library and surprisingly IDEA didn't say a word and successfully compiled a project despite of the fact that in the boundaries of a library Dad extends non existing class.
The question is how to force Dad to extend a new Grandpa without deleting the one inside a library?
You could
Add an abstract class between Dad and GrandSon: Extend Dad, and add your method in the sub class. Then derive GrandSon from that sub class.
Put an instance of Dad in a new class, and let your IDE create delegate methods to the aggregated Dad instance. Again add your new method to the new class.
There is another possibility:
If you have to modify classes in place, use aspectj to weave in code: aspectj changes the byte-code (it does not need source code) at run-time. This way you can add methods or fields.
The fact is that you are duplicating classes with full package signature, so you will get the one that the classloader loads first. I know that in Websphere you can tweak classloader priorities, but couldn't say in your case.
Anyway, why not just do it without decompiling? You are causing yourself hard coupling to an external library and bad practices (maybe copyright issues) by decompiling/customizing. Besides, if the library gets updated, you will run into trouble having to reconstruct your customized classes.
Options:
Create your own implementation, for instance:
Create an Interface that replicates all methods in Grandpa plus the one you need.
Extend Grandpa class and implement the added method from your interface, all other methods will be left intact.
Extend all other extending classes from your own class hierarchie.
Instead of using the libraries common class, use your Interface as naming
This way you are kind of creating your own interface to the library, if it changes, you know where to make changes.
You could even do it without the interface, it's kind of wrapping the functionality, it would depend on what you need to achieve.
Anyway, I would try to solve it by own code and not by messing up with the library, it is just not worth it to do such tricks, if a new Programmer takes the project, they will need a lot of time to find out why and how it behaves.
Now, there might be variations in how to structure the class hierarchie, but it would depend on the specific implementation you need, so you would have to post more detailed data on what the library is and what you're trying to add to it if you expect some more specific answer...
Regards
It has to appear first to the class loader.
IDEA should load your class first if is in your project. You may also try to create a separate library for your class and include it in your project.
See also: http://www.jetbrains.com/idea/webhelp/configuring-module-dependencies-and-libraries.html

Providing Java library, but hiding some classes

I am developing an application in Java ME that I want to provide as a library. Is there no way to hide classes that I don't want everyone to use, but is essential still in order for the library to work?
UPDATE:
I get that I can omit the public specifier, but how can I structure the library itself while developing without creating different packages? I like to view different packages as different folders simply which allows me to structure the code in a good way. However, in some cases I might need to access classes in other packages so this is rather tricky. What does packages really represents? One idea might be to create "interfaces", but these has to be declared public so that means that foreigners might also implement the interfaces intended only for some processes inside the library, correct?
For setting up your library API you'll want to protect anything you
don't want exposed. Do do this just omit the access modifier:
class fooBar {
// do stuff here
}
This will set the class access as 'default' which allows access from
within the same package as well as from any classes which subclass
fooBar.
Within your classes you will also want to lock down any access on your methods and members by marking them either private, protected or omitting the modifier so that they are 'default' as required.
private will allow access from the containing class only;
'default' (no modifier) allows from within the containing class and containing package; and
protected will allow access from within the same class, package and any subclasses.
For anything that you have exposed (public) it is also good practice to mark it as final if it's not designed to be overridden.
Basically, lock down everything as much as you can. Smaller API's are easier to use and harder to break. If you find something needs to be exposed in the future, do it in the future. It's much easier to expand an API rather than deprecate parts of it.
If Java 9 is possible, use Jigsaw modules. If not, put every class on the same package, with package-level access for hidden classes, and use Maven modules to organize them.
I've done exactly that in my project called coronata, a Wii Remote java library. Almost all classes are in package com.github.awvalenti.bauhinia.coronata, but on different modules (which appear as projects on the IDE).
Visible classes are public. They are in modules:
coronata-api
coronata-builder
coronata-demos
coronata-lib
Hidden classes have package-level acesss. They are in modules:
coronata-common
coronata-implementation-bluecove
coronata-implementation-wiiusej
You can make the classes package protected which only other classes in the same package can see.
If this isn't feasible, then you can use ProGuard to mangle the classes and hide their implementations.
Lets consider an Example:
If you have a class A, that you want to hide, and a class B, that uses the functionality of class A, then you can do this:
class B{
//Attribute and Methods
//Inner class A
class A{
//Methods and Attributes.
}
}
After doing this, you can create an Object of class A inside a method of class B and hence use it. Though the class will be hidden from other classes, it could still be used.
Yes, there is.
Simply don't declare those classes public. In other words, omit the public keyword like so:
class Internal { // rather than "public class Internal"
...
}
By default, classes are only accessible within the package where they are defined.
You need to make the classes that you don't want exposed protected. This will make them non usable from client code. Read more in the official docs

How can I run my code upon class load?

Is there a feasible way to get my own code run whenever any class is loaded in Java, without forcing the user explicitly and manually loading all classes with a custom classloader?
Without going too much into the details, whenever a class implementing a certain interface read its annotation that links it with another class, and give the pair to a third class.
Edit: Heck, I'll go to details: I'm doing an event handling library. What I'm doing is having the client code do their own Listener / Event pairs, which need to be registered with my library as a pair. (hm, that wasn't that long after all).
Further Edit: Currently the client code needs to register the pair of classes/interfaces manually, which works pretty well. My intent is to automate this away, and I thought that linking the two classes with annotations would help. Next, I want to get rid of the client code needing to keeping the list of registrations up to date always.
PS: The static block won't do, since my interface is bundled into a library, and the client code will create further interfaces. Thus, abstract classes won't do either, since it must be an interface.
If you want to base the behavior on an interface, you could use a static initializer in that interface.
public interface Foo{
static{
// do initializing here
}
}
I'm not saying it's good practice, but it will definitely initialize the first time one of the implementing classes is loaded.
Update: static blocks in interfaces are illegal. Use abstract classes instead!
Reference:
Initializers (Sun Java Tutorial)
But if I understand you right, you want the initialization to happen once per implementing class. That will be tricky. You definitely can't do that with an interface based solution. You could do it with an abstract base class that has a dynamic initializer (or constructor), that checks whether the requested mapping already exists and adds it if it doesn't, but doing such things in constructors is quite a hack.
I'd say you cleanest options are either to generate Code at build time (through annotation processing with apt or through bytecode analysis with a tool like asm) or to use an agent at class load time to dynamically create the mapping.
Ah, more input. Very good. So clients use your library and provide mappings based on annotations. Then I'd say your library should provide an initializer method, where client code can register classes. Something like this:
YourLibrary.getInstance().registerMappedClasses(
CustomClass1.class,
CustomClass2.class,
CustomClass3.class,
CustomClass4.class
)
Or, even better, a package scanning mechanism (example code to implement this can be found at this question):
YourLibrary.getInstance().registerMappedClassesFromPackages(
"com.mycompany.myclientcode.abc",
"com.mycompany.myclientcode.def"
)
Anyway, there is basically no way to avoid having your clients do that kind of work, because you can't control their build process nor their classloader for them (but you could of course provide guides for classloader or build configuration).
If you want some piece of code to be run on any class loading, you should:
overwrite the ClassLoader, adding your own custom code at the loadClass methods (don't forget forwarding to the parent ClassLoader after or before your custom code).
Define this custom ClassLoader as the default for your system (here you got how to do it: How to set my custom class loader to be the default?).
Run and check it.
Depending on what kind of environment you are, there are chances that not all the classes be loaded trouugh your custom ClassLoader (some utility packages use their own CL, some Java EE containers handle some spacific areas with specific classLoaders, etc.), but it's a kind of aproximation to what you are asking.

Categories

Resources