I have a tricky question and I'm not sure if it is even possible in Java. I'm in the following
situation:
I got a class A that uses another class, let's call it B. Now, I'm trying to write a third class (and I don't call it C), I call it B again (to be sure which class 'B' I mean, I will call it B1 and B2 in the rest of this post, ok?). All three classes resides in three different JAR-files. So far, so good.
Normaly, class A finds class B(1) on the classpath and will use it. But now I'm putting the JAR-file that contains B(2) at the very beginning of the classpath, so class A will find this class instead of the old one. So my class B(2) can act like the old class B(1) (which is a library in reality, that I can't customize in any other way. that's why I am doing that...).
And here comes my problem: In my class B(2) I want to load the real class B(1) and use it. I can do this so far by using reflection. I can even invoke methods via reflection, but I can't cast an instance of the loaded class to B reference. Here is the exception:
java.lang.ClassCastException: my.a.ClassB incompatible with my.a.ClassB
Has anybody an idea how I can use class B(1) in class B(2)? I am happy with any workarround...
Thanx, Thomas.
You can only do this through reflection.
As far as the runtime system is concerned, your two ClassB classes are complete separate entities and cannot be cast to each-other.
This sometimes happens in OSGi environments (which have complex classloader setups) or if you somehow manage to pass data between web application contexts.
If you want a common interface to call methods on both without reflection, then you need to create just that: a common interface (or parent class). And that interface needs to reside in a jar file that both these ClassB can see.
Example:
first jar: interface I
second jar: class B implements I
third jar: class B implements I
Now you have two versions of class B, but they can both be cast to I.
Needless to say, you should find a better solution to whatever problem you have here.
Maybe you can use CDI to #Inject the desired class into class A. Doing so helps you to mock classes and provide alternatives. See also the #Alternative annotation of CDI. Basically you are using the interface methods, the implementation behind it is chosen at runtime or injectione time, resp.
Related
I have the main abstract class that is a base for bunch of classes. Some of them does not need all the fields and methods from the main abstract class, so I have created second abstract class and splitted main abstract class into two parts. The main abstract class contains, for example, a, x fields and their getters/setters, the second abstract class inherits from the main and contains additional b, c fields and their getter/setters. There are simple classes that are inheriting from the main class,and more complicated are inheriting from the second class. I want to create objects of each class as instances of the main class. Is it right way to do that? I have to type check and cast when I want to use methods from the second abstract class. It makes my code complicated. How can I solve this problem?
MainAbstractClass ---> SecondAbstractClass ---> MyComplicatedClasses
|
|
V
MySimpleClasses
One of the OO principles is Favor composition over inheritance.
This means that common behavior is not provided through base classes but via Component classes which are passed in via dependency injection (preferably as constructor parameters.
The answer depends on your actual needs.
You can instead choose to store the extended abstract class specific fields in a class that does not implement your base class and make it a member of more complicated classes.
You can choose to keep everything in a single base class and nothing forces you to use all the fields of an interface in every class that implemented your interface.
You can also keep using your approach but since you store the classes as an instance of the base class, it will be hard to read.
I believe that if you think code does not look very good, it is probably not good. However, there is usually no single answer to this kind of design questions and the best solution is relative to your preferences.
I think this need of type cast is a smell of fragile design. Here when we assume MyComplicatedClass ISA KIND OF MainAbstractClass as shown by TJ Crowder then object must behave as MainAbstractClass (meaning it can honor only API of MainAbstractClass). If it expects special treatment as MyComplicatedClass its false commitment and will need Casting. Such casting (by identifying type) goes against OO principles and kills polymorphism. Later this will end up in Ladder of InstanceOf and type casts as in the scenarios rightly pointed out by T.J. Crowder.
I would suggest readdress the design. e.g. though our all user defined type instances ARE KIND OF Object, but we use Object API only for methods defined in Object class. We do not use Object o = new MyClass(). There are occasions in frameworks or like Object.equals() method where type cast is needed as API is defined before even concrete extension is written. But it is not a good idea for such simple complete (without open hooks for extensions) Hierarchies.
Sorry if the question title is not clear but I needed more characters to fully explain myself.
Before people start jumping to conclusions, YES I know about isInstance and instanceof but hear me out first.
Let's say I generate a java ".class" file of an interface (called MyInterface) from a UML model. Then, lets say that there is a directory somewhere that contains two ".class" files where one represents an interface that is IDENTICAL to the generated one (same fully qualified name, both using the default package) and the other represents the concrete class that implements MyInterface.
In a separate program, I load in the generated interface and concrete class with separate classloaders (URLClassLoader). When I try to check if the concrete class implements the generated version of the interface, isInstance() returns False. I suspect this is because when the concrete class is loaded, the non-generated interface gets pulled in with it because it implements it. If I use Class.getInterfaces() on the concrete class and compare it's interface with the generated one using equals, this also fails.
Since isInstance() does not work does anyone know of a way to verify that a class implements an interface with the same fully qualified name and not necessarily the one it was compiled with?
Let's say I generate a java ".class" file of an interface (called MyInterface) from a UML model. Then, lets say that there is a directory somewhere that contains two ".class" files where one represents an interface that is IDENTICAL to the generated one (same fully qualified name, both using the default package) and the other represents the concrete class that implements MyInterface.
Why? This is poor practice. Don't do it.
In a separate program, I load in the generated interface and concrete class with separate classloaders (URLClassLoader). When I try to check if the concrete class implements the generated version of the interface, isInstance() returns False. I suspect this is because when the concrete class is loaded, the non-generated interface gets pulled in with it because it implements it.
No. It is because you are using two classloaders. Classes loaded by distinct classloaders are distinct.
If I use Class.getInterfaces() on the concrete class and compare it's interface with the generated one using equals, this also fails.
For the same reason.
Since isInstance() does not work does anyone know of a way to verify that a class implements an interface with the same fully qualified name and not necessarily the one it was compiled with?
You can't. The only way the class and the interface can coexist in the same same JVM is via distinct classloaders, which eliminates the implements-relation between them.
The solution is simply not to do this in the first place.
Since you don't seem to be too worried about whether this is good practice or not, you could simply compare against Class.getInterfaces() but with a custom comparison (name based, or more involved if you want to make sure operations are good too).
Just scan the interfaces and look for one that matches, but don't ask the default "equals" to work for you because of the way you're cheating with the classloader.
BTW, I'd definitely put code that catches the NoSuchMethod cleanly, it's bound to happen at some point the whole setup seems fragile.
I am trying to change an interface in Proj2.
However, Proj1 is already using this interface, and won't be compiled with my new version.
Looks like problems occur only if I change/delete existing methods but adding new methods seems to be not causing any issues.
So as long as I only "add" methods to the interface, I can expect Proj1 to be fine with the latest Jar of Proj2.
Is that a rock solid safe assumption?
Update:
Both the interface and impl reside in proj2. Proj1 has no implementation of that that interface.
By "using," you mean "references an object using the interface and invokes interface-defined methods using that reference," not "implements the interface" (yes, you've clarified in comments, but I just want to repeat, because all the other answers are about implementing the interface).
In that case, as long as you have not removed methods from the interface or change their signature, your existing code will work.
The reason that this will work is that the compiler translates the method calls into an invokeinterface bytecode, which references the interface class and method by name. At runtime, the JVM simply validates that the actual reference implements the interface, and invokes the method.
If you remove or change a referenced interface method, one of two things will happen: either the JVM will refuse to load the class in proj1, because the interface reference could not be resolved, or it will give a NoSuchMethodError (I believe it's the second). Same thing if you remove or change a referenced method in a concrete class.
No. Adding new methods to the interface or updating its current signature would require you to provide the implementation of those methods in classes where you have implemented the interface.
However, when you remove a particular method declaration from an interface, even though it is defined in the class implementing the interface, there would be no effect. The removed method would just serve to be a normal method of the class, no longer tied with the existing contract of the interface.
The only way that I can think of solving your issue is to take the advantage of Java letting you implement multiple interfaces for a given class. What you should try to do is create a new interface, define your new methods over here and let your classes in proj2 implement this interface as well. This way, when you package your new jar, your existing classes in proj1 would remain unaffected.
If you're just adding methods, create a second interface. Java classes can implement more than one interface. That way, the classes that implement Interface1 remain the same.
Your newer class(es) implement interfaces Interface1 and Interface2.
you will get the error:
The type XXXImpl must implement the inherited abstract method IXXX.method()
Using reflection you can get pretty much everything relating to a class. You can get all the declared methods, fields and classes (and possibly even more), but i couldn't find a way to reflect on a method so i could find out what classes that method might be using.
Essentially i would like to find out all dependencies to other classes that a given class has.
Example:
Given the following code:
import com.yada.yada.yada.SomeClass
public class MyClass
{
public MyClass
{
new SomeClass();
}
}
How can i find out that MyClass is using SomeClass in its constructor?
I was trying to think of a way to get all import statements defined in a class file but i couldn't find anything that way either. But, assuming there's a way to somehow dig up all import statements defined in a class file, how would one find out about classes defined in the same package, which do not require an import statement?
EDIT:
Scenario: The goal is to send the bytecode of this class (MyClass) to another process. This other process then takes in the bytecode and loads the class (MyClass) using class loaders, and so on. The problem is that when i try to create and run an instance of MyClass in the other process it fails because it cannot find a definition for SomeClass.
If SomeClass were a member of MyClass it wouldn't be a problem but since the only reference to it lies in a method, there's no way to get to it via reflection?
I think the closest you can come to getting all of a class's dependencies is by hooking into the class loader mechanism and recording what classes get loaded when the class you're examining is instantiated and its methods are called. Of yourse, you'd transitively also get all the classes that it indirectly depends on, but depending on what you want to do with the information, that may be what you actually need.
But it's impossible to do for all cases (just imagine a method that uses Class.forName() to ask for a random class name every time it's called).
how would one find out about classes defined in the same package
That's actually impossible to do in general, since the class loader concept really only allows asking for a fully qualified class name, and either getting that class or a ClassNotFoundException. Classes can be loaded from a webserver (in the case of applets) or generated on the fly, so you cannot know whether a specific class exists except by asking for it.
You can't (unless you decompile the bytecode). A local variable is not tied to any class instance, and it does not even exist for most of the lifetime of the class or its instances, so you can't access it via reflection.
What are you trying to achieve? Maybe if you tell us about your actual problem, rather than a perceived solution, we are better able to help.
Reflection does not help you here. The only way I can think of that you can achieve this is through a byte code tool like asm.
Create a ClassVisitor that gathers dependencies from
Class declarations
Annotations
Local variable declarations
Field declarations
Method declarations
Method invocations
(have I forgotten anything?)
I'm writing a functionality where it would be helpful to get the classes inside a certain package of my program. Also, I only want the classes that subclass a certain class.
I need the classes in order to call static methods on them.
Is there an automatic way to do this? If so, is it slow?
In case I was not clear, what I want is something like this:
ArrayList<Class<? extends MySuperClass>> classes = ;
classes.add(MyClass.class);
classes.add(MyClass2.class);
Instead of having to call add for each class, I would like to automatically get that class list.
The number of classes is small, so I would not mind declaring them manually if the automatic trick would be slow - this app is for a mobile platform.
In either way, I would also like to know how to call the static method for each method in the ArrayList:
// error The method nameOfStaticMethod is undefined for the type Class<capture#2-of ? extends MySuperClass>
classes.get(0).nameOfStaticMethod ();
Thanks for your comments.
Java doesn't provide this ability. There is no introspection at the package level. The classes could be records in a database, or on the other side of a network connection. There's no requirement for them to be stored and organized so as to facilitate enumerating them by package.
You could make a custom class loader and API to provide a method of listing the class names.
I too would like to list all classes in a package but so far the methods of doing this is pretty bad:
Like JOTN suggested - needs file access - not if it is a jar
Listing a JAR entries - well, also needs the jar file
Quoting a older SO question:
It isn't possible to query a Package for it's Classes (or even its subpackages). http://forums.sun.com/thread.jspa?threadID=341935&start=0&tstart=0 contains a very good discussion about why this is problematic, as well as a handful of solutions to your problem.
Anyways, here is how you invoke static methods on the class:
Method m = Integer.class.getMethod("toString", Integer.TYPE);
System.out.println(m.invoke(null, 123));