I code java with BlueJ for Mac. I have added the stdlib.jar library (From princeton http://introcs.cs.princeton.edu/java/stdlib/). Before added this library I had my own class named StdDraw.java (The specific class I was using on the project) and copy/pasted the code. I also adjusted some of the code and added some new lines. Since I cannot edit the libraries code, how may I override or extend library classes to add additional functionality?
Since the library classes are final, you can't extend them. Another option is to wrap them in your own classes. For example, you can create your own drawing class that has an instance of StdDraw that it delegates to. For many of your methods you can call the corresponding method of the StdDraw instance, or you can simulate overriding by implementing methods yourself.
Just simply extend the class,
public MyClass extends ClassFromLib
make sure the library jar file is on the classpath. If the author of that class declared it as final indicating that it's not suitable for subclassing. then the best alternative is to use the delegate pattern.
I wrote the code below in this editor so no promises that it complies, but hopefully you get the idea.
public Myclass {
private ClassFromLib cfl = new ClassFromLib();
public void methodA(){
//Do whatever you need here
cfl.methodA(); //Doesn't have to be the same name.
//Do whatever you need here
}
}
Related
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
I am using the StdDraw.java library and I can't edit the file. I want to add various items to the JFrame such as JMenu, buttons and others without compromising the canvas and the Jframe.
I have tried something like
StdDraw.class.getMethods"
Yet I can't seem to get it to work. It seems I can only use the methods inside the class and don't add some of my own or edit the ones already in.
The file is available online. How would I be able to achieve the above?
StdDraw.java is a final class, if I am not mistaken. A final class cannot be extended. So you have two options:
You can directly use source then add your own attributes and compile it yourself, if the license permits this kind of usage.
You can encapsulate StdDraw.java class, with your own wrapper class and direct method calls using Java Reflection.
Use inheritance.
class MyClass extends JFrame {
String myField = ""; //--- This is my own field!
}
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
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.
In a Java source, I don't want use some package. For instance, I don't want any reference to swing, or io, or other.
Is there a system to check that, at compile time, or at test time?
For instance, with supposed annotation
#NoPackage("javax.swing")
class Foo
{
private JFrame fram; // NOT OK.
}
Why I need this? Because I have an application with swing, and I want refactor it with a part which uses swing, and other which doesn't, because I want to port it to other ui stuff (web, pda, etc).
I am not aware of such a tool, but it is not that complex to create one. References to all used classes are coded in classfile. Using some classfile library, classfiles can be inspected, and all used classes (or packages) listed. If annotations like #NoPaquage inserted, then the tool could just check if the class really dosent use that packages.
I can think of one rather hacky way to do this. However, you need to have a list of such forbidden classes, not just packages. Say, you want to forbid the usage of javax.swing.JFrame.
Just create the below fake class.
package javax.swing;
class JFrame {
}
Notice that the class isn't public, so any attempt to import it leads to the compilation error "The type javax.swing.JFrame is not visible."
You could create a JAR file out of all such forbidden classes and make sure they get loaded last by the classloader. This ensures that a compiler error definitely occurs. You can simply choose to include/exlude this JAR file whenever you want to run this test - a trivial task if using ant.
I think that this would be very difficult, since there is also the possibility of a class using reflection to get at what it wants.
If I was attempting to do this, I would write my own custom classloader, but I'm not sure if the classloader interface known which class is actually trying to load. I think you could use a custom classloader if you want to forbid all the code from using a certain package, but if you want it more class specific, you may need something manual like grep-ing the code?
Something like this:
$ find srcTree -name \*.java | xargs grep javax\\.swing
You can't have the JVM filter the code you are writing. However, you could use generics to restrict the classes that are allowed in all public APIs. You can also restrict inheritance like this:
class Parent {
public Parent() throws Exception {
if (this instanceof Child)
throw new Exception("It's a child");
}
}
public class Child extends Parent {
public Child() throws Exception {
super();
}
}
You can choose the packaqe you want to use in the import area.
In Eclipse you can choose the package your class come from.
You have to delete the import line for choose the class in another package.