Detecting Class object equivalence for classes loaded by different ClassLoaders - java

My Task is to write a unit test for a method findSubClassImplementation that returns an instance for a given Class object. The method signature looks like this:
public <T extends SuperClass> T findSubClassImplementation(Class<T> cls) throws Exception
Internally the method checks wether the supplied Class object belongs to a set of known classes and then returns an instance of that class:
if (Subclass.class.equals(cls))
return (T) new Subclass(args);
If the class is not known, an Exception is thrown. This code is given
I tried to load all Classes inheriting from SuperClass via Reflection and then pass them as argument to findSubClassImplementation:
Set<Class<? extends SuperClass>> subTypesOf = reflections.getSubTypesOf(SuperClass.class);
Class<? extends SuperClass> clazz = subTypesOf.iterator().next();
SuperClass instance = findSubClassImplementation(clazz);
I then use a Debugger to step into the method, and I can see the line of code where
if (Subclass.class.equals(cls))
returns false, although cls = Subclass.class
I assume what happens is this: Class does not implement equals, thus equals of Object is used, that compares with "==". As reflection uses a different ClassLoader than is used in findSubClassImplementation the two class Objects are different. Is this assumption correct?
Is it possible to get the other Class object for a class that I have loaded with Reflection? Do you have another idea how to deal with this problem?
ANSWER:
Turns out I am not very good at reading: The hirarchy is in 3 levels: SuperClass --> IntermediateAbstractClass--> Subclass. The comparison is always to the intermediate abstract class:
if (IntermediateAbstractClass.class.equals(cls)) return (T) new Subclass(args);
Thus my question wasn't very accurate or precise - I am sorry if you feel like I wasted your time. I'll mark Michael Wiles answer as the correct one, because his advice pushed my to discover my missunderstanding. Thank you!

There must be something that is different about the classes...
You say that Subclass.equals(otherSubclass) returns false we need to ascertain why this is the case.
Check the name of each class for equality and then check the classloader of each class for equality.
Based on your provided code to do the reflection there is nothing here to sugggest that these classes loaded by "Reflection" are in fact loaded from different classloaders.
Furthermore try all sorts of classes, maybe there is something unique about that particular class that causes the behaviour.
One suggestion to try would be to add Integer to the subclass set and then pass in Number to the method...

Maybe you don't need to check what class is cls, since cls already contains all the information you need. Try simply with
public <T extends SuperClass> T findSubClassImplementation(Class<T> cls) throws Exception {
// ... retrieve args
final Class<?>[] constructorParamTypes = new Class<?>[args.length];
for (int i = 0; i < args.length; i++) {
constructorParamTypes[i] = args[i].getClass();
}
return cls.getConstructor(constructorParamTypes).newInstance(args);
}
Or in the Java 8 way:
public <T extends SuperClass> T findSubClassImplementation(Class<T> cls) throws Exception {
// ... retrieve args
final Class<?>[] constructorParamTypes = Arrays.stream(args).map(Object::getClass)
.toArray(size -> new Class<?>[size]);
return cls.getConstructor(constructorParamTypes).newInstance(args);
}

Related

Cast class to unknown subclass by name?

First off, sorry for the confusing title. It even confuses me so I don't wat to think about a better title any more.
Though, let's get to my problem. I have a class Classss. That class has some variables and a doSomething() void.
Now, that class has lots of classes extending that class, with different values of the variables and a different doSomething void. Now, I have the name of a class, something like "com.cool.cool.Cool".
So, I know that that class is a subclass of Classss and I have the name. Is there any way I can load that class by its name and be able to treat it as a Classss?
Thanks in advance.
It seems to me like this the classic case of polymorphism. Where you want to treat all subclasses the same way as the top class.
Basically, you can do this:
Classs c1 = new Cool(); // This works
Classs c2 = new SubClass(); // This works
c1.doSomething(); // Will call the Cool.doSomething() method;
c2.doSomething(); // Will call the SubClass.doSomething method;
You can also use List<Classs> and put subClass object in it...
Maybe something along the lines of:
static Bar getSubclass(String name) throws Exception{
Class<?> c = Class.forName(name);
Constructor<?> con = c.getConstructor();
return (Bar)con.newInstance();
}
This should work, provided name is the fully qualified name of a class that extends Bar and has a no-arg constructor.
class Bar{}
class Foo extends Bar{ public Foo(){} }
This is pretty prone to breaking.
Since your question mentions “load that class by its name” I assume you are using the Class.forName method.
java.lang.Class has an asSubclass method which I believe will do what you want:
Class<?> loadedClass = Class.forName(name);
Class<? extends Classss> type = loadedClass.asSubclass(Classss.class);
Your example name of “Classss” makes the above rather confusing, so I’ll repeat it using the name ExampleService:
Class<?> loadedClass = Class.forName(name);
Class<? extends ExampleService> type = loadedClass.asSubclass(ExampleService.class);
Alternatively, you may want to make use of the service provider facility, which is designed to dynamically search for “plugins,” that is, foreign implementations of an interface or abstract class:
for (ExampleService service : ServiceLoader.load(ExampleService.class)) {
System.out.println("Found subclass: " + service.getClass());
}

Iterating over heterogeneous container

I am using a heterogeneous container similar to this one. I can put and receive objects from the container with ease:
Favorites f = new Favorites();
f.putFavorite(String.class, "Java");
String someString = f.getFavorite(String.class);
But there seem to be no easy way to iterate over such container. I can add a keySet() method to the Favorites class and simply return the key set of the internal Map object:
public Set<Class<?>> keySet() {
return favorites.keySet();
}
Now, I would like to iterate over the keys, use the keys to get the associated values, and call some methods on the received objects:
for (Class<?> klass : f.keySet()) {
// f.getFavorite(klass).<SOME_METHOD_SPECIFIC_TO_THE_CLASS-KEY>
}
I thought that I could access the methods of the objects held in my container by calling klass.cast(f.getFavorite(klass)).SOME_METHOD(), but it doesn't work either (meaning, I cannot access any methods except for the Object-related methods).
Let's say, that in my use case I would like to inspect the interfaces of all these objects I iterate over and act accordingly to the detected interface. Let's also assume that I may have dozens of objects of various classes and all of them implement one of three interfaces.
The only solution I can think of is to stuff my code with dozens of isinstance checks, but I would prefer a less cumbersome approach (i.e. checking if a given object implements one of three interfaces).
By trying to call a specific method on each entry, you are basically saying that you know better than the compiler, and that you know each entry has a specific super class.
If you know that's the case, you can use Class#asSubclass to type klass as Class<? extends KnownSuper> so that getFavorite will then return a subclass of KnownSuper (and therefore expose the method):
Class<KnownSuper> superClass = KnownSuper.class; //class with callMethod()
for (Class<?> klass : f.keySet()) {
f.getFavorite(klass.asSubClass(superClass)).callMethod()
}
However, this will obviously give a runtime exception if one of the key classes does not extend KnownSuper. So if the above would be safe, you should parameterize your heterogeneous container to only accept key classes that extend from KnownSuper in the first place.
If not all entries will be of this type, you could also check first if the key is suitable when iterating:
Class<KnownSuper> superClass = KnownSuper.class; //class with callMethod()
for (Class<?> klass : f.keySet()) {
if (superClass.isAssignableFrom(klass)) {
f.getFavorite(klass.asSubClass(superClass)).callMethod()
}
}
Just go through this simple example
Say you have below Favorites class definition
public class Favorites extends HashMap<String, String> {
}
Here is the test class
public class TestGeneric {
public static void main(String[] args) {
Favorites f = new Favorites();
f.put("test", "test");
for (String test1 : f.keySet()) {
f.get("").charAt(index)// you will see all string specific method as compiler knows in advance what object map going to contain
}
}
The moment you change Favorites extends HashMap<String, String> to Favorites extends HashMap you will just object specific methods as compiler does not know in advance which object Favorites is going to put in map

Approach doing the same stuff on different objects

I am currently making a library which is an utility for me to handle something which is not associated with the question (I am implicitly not saying the subject because it is not really important), however it does use reflection.
I am retrieving all declared and inherited methods from a class, which currently works fine and is not the issue. But the thing is, I need to do this as well for sub-classes since those inherit over like methods do (however you cannot override those like methods).
The problem that I am facing that it will use the same algorithm but there will be on difference, instead of calling clazz.getDeclaredMethods() I need to call clazz.getMethods. What is the best way too approach this, and I kind of need to return Class[] and Method[] in the method signature as well.
Normally I would look for a shared superclass, but in this case I prefer to the have Class[] and Method[] accordingly. For starters, I did some research and found some shared superclasses:
GenericDeclaration
AnnotatedElement
Since I need both Class[] and Method[] arrays I am thinking something
like generics, so the method would look like:
public static <T extends GenericDecleration> T[] getT () {
}
As mentioned by dasblinkenlight this will not work since the method doesn't take any arguments and cannot check whether to retrieve Class or Method objects.
But how would I detect whether I need to call getDeclaredMethods or getDeclaredClasses?
What is the best approach on how to do this without duplicating a lot of code? I really tried to explain myself here, but if it is still unclear what I am doing please feel free to ask away!
Thank you very much in advance!
After messing around with this, I have found a solution that totally fits my needs. This is a combination of generics and #dasblinkenlight's solution, like so:
public interface DeclExtractor<T extends GenericDecleration> {
public T[] extract (Class clazz);
public Class<? extends T[]) getGenericClass ();
DeclExtractor<Method> methodExtractor = new DeclExtractor<Method>() {
#Override
public Method[] extract (Class clazz) {
return clazz.getDeclaredMethods();
}
#Override
public Class<? extends Method[]> getGenericClass () {
return Method[].class;
}
}
// Same for Class
}
Now the method which also will return the correct type so you dont have to manually cast all GenericDeclaration to your original object type. My issue was that I used a collection for it and not the correct array:
public <T> T[] getAll (final DeclExtractor<T> extractor, Class<?> clazz) {
T[] declaration = extractor.extract (clazz);
//.. The algorithm..
// Return an instance of a collection as array (I use a set in my implementation)
final Object[] objects = myCollection.toArray();
return Arrays.copyOf(objects, objects.length, extractor.getGenericClass());
}
Technically you do not need the getGenericClass method in the interface, but I am using extract directly in a loop so I cannot pull the class of that, however, you can.
Hopefully this helps someone in the future :) Thanks again to #dasblinkenlight for the inspiration!
Your getT needs to get some input in order to decide what to do.
What about a method which can takes an enum as argument to determine whether it needs to get classes or methods? (from a comment)
There is a better approach: define an interface that performs the appropriate extraction, and make two instances of it - one for extracting classes, and one for extracting methods:
public interface DeclExtractor {
GenericDecleration[] extract(Class cl);
final DeclExtractor forClasses = new DeclExtractor() {
public GenericDecleration[] extract(Class cl) {
// make an array of GenericDecleration from extracted classes
}
};
final DeclExtractor forMethods = new DeclExtractor() {
public GenericDecleration[] extract(Class cl) {
// make an array of GenericDecleration from extracted methods
}
};
}
Now you can rewrite your getT to take an "extractor", like this:
public static GenericDecleration[] getT (DeclExtractor extractor, Class cl) {
...
// When it's time to get components of the class, make this call:
GenericDecleration[] components = extractor.extract(cl);
...
}
To initiate a call to getT, pass DeclExtractor.forClasses or DeclExtractor.forMethods:
GenericDecleration[] c = getT(DeclExtractor.forClasses);
GenericDecleration[] m = getT(DeclExtractor.forMethods);

new <T> in Java

I have this problem
a method which is cutting unwanted details from one class and returning collection of objects with wanted ones. the matter is I want this metod to be able to work with different classes ( which are based on one abstract, though), so I use generic type. the problem is that in one point I need to create an instance of , which is impossible. I looked for some way out, but it doesn't seem to work for my case.
So, code is following
private <T extends RestMandate> List<T> toRestMandate(List<CardMandate> mandates ) {
List<T> restMandates = new ArrayList<>(mandates == null ? 0
: mandates.size());
if (mandates != null) {
for (CardMandate mandate : mandates) {
restMandates.add(new T(mandate));
}
}
return restMandates;
}
RestMandate is base class, CardMandate were I take the info. Any ideas?
Since the generic type arguments are erased at runtime, there is no way you can refer to it like you are trying to do. The only way out is a type tag argument + reflective instantiation.
A better choice is to redesign your solution to solve this without relying on generics and type tags. Leverage dynamic method dispatch instead: add a method to RestMandate which will return the object converted to the desired type.
Because of Type Erasure, T becomes Object at runtime. You don't know its real type anymore.
You can still instantiate the object by reflection if you have its class. In order to do that, you must give the class to your method:
private <T extends RestMandate> List<T> toRestMandate(List<CardMandate> mandates, Class<T> clazz ) {
...
for (CardMandate mandate : mandates) {
/*
* I get the constructor which needs one CardMandate and call it.
* Note : I do not recommend this solution (no check at compile-time!).
* Like Marko Topolnik, I advise to redesign the solution.
*/
restMandates.add(clazz.getConstructor(CardMandate.class).newInstance(mandate));
}
...
}
To create an instance you require Class<T> object too
private <T extends RestMandate> List<T> toRestMandate(List<CardMandate> mandates, Class<T> clazz) {
//....
T newInst = clazz.newInstance();
//....
}

Java run time class reflection

Say if I have a class named Car I can use the following line of code in certain situations.
Car.class
My question is there a way I can make the same type of call if a user supplies a class name at run time. Have tried something similar to the below but no joy, is there a way i can do it.
String className = "Car";
Class.forName(className ).class;
Also I need to be able to cast dynamically, if the user specifies a list of objects I need to be able to dynamically cast.
e.g. instead of Car myCar = (Car) object
I need to be able to have to the user specify the name/type of class at run time so that I need to be able to do something along the lines of ClassName myObj = (ClassName) object.
Class.forName("Car") already returns the same as Car.class.
For casting, you can then use Class.forName("Car").cast(object), which would return a Car object. Take a look at the API, mostly the java.lang.Class part of it.
Also, since you're casting # runtime, there's no type safety, and you should check whether object extends or implements Car before doing it, otherwise you'll get an exception. A question I asked ~ a year ago and the answers there may be relevant to you as well.
Though, as others already said, this smells & you could probably redesign it in a better way, also note that this type of casting will typically be pretty slow because Java needs to examine the type hierarchy (it needs to throw a ClassCastException if it can't cast to Car).
Given the nature of the question, most of the answers to this are straight from the Reflection API documentation. I would suggest you take a look at this: http://docs.oracle.com/javase/tutorial/reflect/class/index.html. If this does not help and you need help with something specific, we can look at that.
What you are looking for is a feature called Reflection in the Java programming language.
It allows an executing Java program to examine or "introspect" upon itself, and manipulate internal properties of the program. For example, it's possible for a Java class to obtain the names of all its members and display them.
A Simple Example from http://java.sun.com
import java.lang.reflect.*;
public class DumpMethods {
public static void main(String args[])
{
try {
Class c = Class.forName(args[0]);
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
}
catch (Throwable e) {
System.err.println(e);
}
}
}
For an invocation of:
java DumpMethods java.util.Stack
the output is:
public java.lang.Object java.util.Stack.push(
java.lang.Object)
public synchronized
java.lang.Object java.util.Stack.pop()
public synchronized
java.lang.Object java.util.Stack.peek()
public boolean java.util.Stack.empty()
public synchronized
int java.util.Stack.search(java.lang.Object)
Here is an example of creating objects at runtime:
import java.lang.reflect.*;
public class constructor2 {
public constructor2()
{
}
public constructor2(int a, int b)
{
System.out.println(
"a = " + a + " b = " + b);
}
public static void main(String args[])
{
try {
Class cls = Class.forName("constructor2");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Constructor ct
= cls.getConstructor(partypes);
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj = ct.newInstance(arglist);
}
catch (Throwable e) {
System.err.println(e);
}
}
}
You can read more about it here and here - for indepth view
Also look here:
What is reflection and why is it useful?
You want to interact with myObj, so rather than going through these gymnastics, think about adding an interface that models the interactions you want to have with the objects, then use that interface in the code. The classes supplied by the user can then be validated to implement the necessary interface and errors raised appropriately.
The expression Car.class returns the java.lang.Class object for class Car.
A statement Class.forName("Car") will also return the java.lang.Class object for class Car (assuming that class Car is in the default package). Note: No need to append .class; that would give you the Class object of class Class itself, which is not what you want.
Class Class has methods to check if an object is an instance of the class that the Class instance represents (hope this is not too confusing...). Since you don't know the name of class Car at compile time, you're not going to have any kind of compile time type safety.
Lookup the API documentation of java.lang.Class.

Categories

Resources