I'm developing a web-app in Java language, which is composed by a system and some modules. All of them implement the IAppIdentifier interface and I have all the module references and the system itself stored in a List into the system.
The idea is to design that in such way that every module will be able to access the system itself or another modules if they have the required interface (extended from IAppIdentifier), so they have to ask the system for them.
I have this code which works:
#Override
public IAppIdentifier moduleByClass(Class<? extends IAppIdentifier> clazz) {
List<IAppIdentifier> iApps = this.get_Iapps();
for (IAppIdentifier iApp : iApps) {
if (clazz.isAssignableFrom(iApp.getClass())) {
return iApp;
}
}
return null;
}
Basically it's checking that each class from the array is assignable from the required interface and if it is it will return that instance. However the matter is that I have to cast it when it's returned by the method.
For example I have to implement something like that to obtain system's instance:
((ISystem) this.get_Service().moduleByClass(ISystem.class))
My question is, is there any way in java to avoid doing that casting again, ergo, to ensure it will return the same type I'm passing as argument at compile time?
Change method signature to this one :
public <T extends IAppIdenfitier> T moduleByClass(Class<T> clazz)
This should work.
Even if your interface isn't generic you can still use generics in methods for they own purpose. By this code you provide generic rule that T has to be IAppIdentifier itself or has to extend it. Your method now will return object of type T and take as param class as Class<T>.
Then in your code whenever you invoke method moduleByClass you don't have to cast it, for example:
ISystem = this.get_Service().moduleByClass(ISystem.class);
Cast won't be needed here and everything will compile.
There is more info needed according to #XtremeBiker good comment. Inside moduleByClass method it's needed to cast resulting type to T. So it was:
return iApp;
But now it should be:
return clazz.cast(iApp);
Anyway it's still less annoying to make cast in on place inside method body than doing it everytime when that method is invoke.
Related
Given the interface:
interface GenericInterface<T> {
Class<T> getGenericType();
}
and the following implementation "skeletons":
class GenericInterfaceImpl<T> implements GenericInterface<T> { /* impl */ }
class TypedInterfaceImpl implements GenericInterface<String> { /* impl */ }
define an implementation for getGenericType in a manner that it would pass the following assertions:
assertEquals(new GenericInterfaceImpl<String>().getGenericType(), String.class, "Type should resolve to String.class");
assertEquals(new TypedInterfaceImpl().getGenericType(), String.class, "Type should resolve to String.class");
I'm perfectly aware of a good implementation that solves this problem on the TypedInterfaceImpl "scenario". The following code passes the assertion for the second case:
#Override
#SuppressWarnings("unchecked")
Class<T> getGenericType() {
Type t = this.getClass().getGenericInterfaces()[0];
ParameterizedType pt = (ParameterizedType) t;
return (Class<T>) pt.getActualTypeArguments()[0];
}
But I can't find a way to get the same result if I'm working with the GenericInterfaceImpl version of this problem. When using the above implementation with GenericInterfaceImpl, the "type argument" resolves to a sun.reflect.generics.reflectiveObjects.TypeVariableImpl instead of java.lang.String like it does when handling TypedInterfaceImpl.
The Javadocs for getGenericInterfaces explicitly states that it will not resolve type parameters if it's not defined in the source code (for reference: https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getGenericInterfaces-- I'm using Java 11 in my particular case but it's the same nonetheless), so by definition, I understand that this particular method can't solve this problem.
Is there a way to solve this problem at all or is this a "core limitation" of the Java language?
assertEquals(new GenericInterfaceImpl<String>().getGenericType(), String.class, "Type should resolve to String.class");
impossible.
assertEquals(new TypedInterfaceImpl().getGenericType(), String.class, "Type should resolve to String.class");
Possible, but a bad idea; it would require you to document your interface with 'when implementing this interface, you must pick a concrete, non-type-parameterized type for T or nothing works right.', which is a weird caveat.
Class<T> getGenericType() {
Bad idea; the thing in the <> does not have to be a Class - for example, it could be List<String>, which is not representable as a class object (only List is, there is one object that represents all lists, there's no way to have an instance of j.l.Class that represents List<String>).
The Javadocs for getGenericInterfaces
getGenericInterfaces is a reflective tool, but it reflects on the definition of the type only. Given class Foo<T> implements Thingie<T>, getGenericInterfaces can only be executed on the entire Foo class, and you get back an object that presents Thingie<T>. Given an instance such as new Foo<String>() it is not possible to derive String.
Is there a way to solve this problem at all or is this a "core limitation" of the Java language?
It's a core limitation, so, no. Not directly.
One trick is to add a method:
public interface Foo<T> {
public Class<T> getType();
}
and let implementers worry about the problem. This is still a bad idea, for example, a Class object cannot represent List<String>, so you've effectively made it impossible for Foo to properly represent anything where you want the T to be anything that has type params.
Take a step back instead. What are you actually trying to do? Nobody wakes up and goes: I know! I'll build an interface that can report its own type parameter but reified! What did you want to build? A chat app? A plugin system for photoshop?
java.lang.Class, with the intent to invoke .newInstance() on it, is a piss poor factory. Thus, if that is what you intend to do, use factories instead.
Anotehr solution, but you probably don't want this, and before you got all excited, it's got plenty of limitations, are a concept called Super Type Tokens; you can search the web if you must know.
I'm having 2 classes, their internals doesn't matter at all.
class ClassA {
//...
}
class ClassB {
//...
}
And I'm having 2 predicates that use those classes, let's say they look like this
private Predicate<ClassA> classAPredicate() {
return Objects::nonNull;
}
private Predicate<ClassB> classBPredicate() {
return Objects::nonNull;
}
Now, I'm having generic method in external library that is already beeing used by many users and unfortunatelly, it has pretty generic input parameter which is Object which in 90% of cases is Predicate.
What I need to do, is to extend this method functionality by checking type of passed Predicate and based on that, perform some operations.
public void test(Object obj) {
Predicate predicate = (Predicate)obj;
if(predicate.getClass().isAssignableFrom(ClassA.class)) {
System.out.println(predicate.test(new ClassA()));
// logic specific to Predicate<ClassA>
} else {
System.out.println(predicate.test(new ClassB()));
// logic specific to Predicate<ClassB>
}
}
But, during tests I'm passing both Predicates and it fails with Exception in thread "main" java.lang.ClassCastException:
test(classAPredicate());
test(classBPredicate());
I've been debugging and isAssignableFrom() is always returning false so the error is obvious here. I'm not sure if that is the right approach, but I didn't came up with anything else yet. Is there any way to check what is the type of that Predicate?
I know that what I'm trying to implement isn't ideal, but that is current requirement...
In the above, the predicate class is not assignable from Class A.
if(predicate.getClass().isAssignableFrom(ClassA.class))
This causes the else condition to run which passes an instance of B to the Predicate for type A which causes a cast exception. Due to type erasure, it will not be easy to resolve whether an instance of A or B should be passed to the predicate. 3 options are:
Try each input type until one doesn't throw a ClassCastException.
Handle the expected behavior in a new method instead of the existing test function.
Define a more specific interface than Predicate which also has a method to get the type the predicate tests and use the test type in the condition instead. Ex:
public interface TypedPredicate<T> extends Predicate<T> { Class<T> getTestType(); }
Well,
I have been doing Java Generics for going on three years now. I can cite a dozen Stack Overflow posts about "Reifying Java Generics" here: SO1, SO2, SO3. Most importantly, if you are intending to write Java for years and years, you must know that the "Generic Type Parameter" are simply NOT ACCESSIBLE at Run-Time without fields, or extra methods to retrieve them. Java Generics (The syntax that looks like: STUFF<TYPE> with the greater-than, less-than symbols is STRICTLY A COMPILE-TIME FEATURE). At RunTime, the JRE simply has no idea what the Type of the Type-Parameter is - and all it can do is throw ClassCastException if an attempt to misuse occurs.
NOTE: 'Misuse' the generic type such that it throws ClassCastException should sound odd if you are thinking that the JRE does not know and does not care what the type of the type parameter is. Mostly, the way exceptions are thrown, is such that if the code you write inside of a generic makes presumptions, and if it has made faulty presumptions, then this exception will throw.
Read Sun / Oracle's "To Do" list about "Reifying Generic Type Parameters." Also, most importantly, this concept has a very real name that you should read about all the time in Java - and it is called "Run Time Type Erasure" The solution posted before this Stack Overflow Answer says to use try-catch (ClassCastException) blocks, which is, actually, a valid answer.
ALSO: The answer about creating this type of TypedPredicate<T> extends Predicate<T> is not the correct answer if you intend to use your TypedPredicate<T> in any way that expects to allow Java Lambda Syntax to work with it. When you add the following method:
public interface TypedPredicate extends Predicate { Class
getTestType(); }
You will not be able to use the syntax #FunctionalInterface - which is one of the primary benefits of the class java.util.function.Predicate<T> Furthermore, there is a more severe problem in that, the Type of T is not accessible to the programmer and is not known at RunTime by the JRE
You see this part right here (since the answer has a green check mark):
{ Class<T> getTestType(); }
// Can you answer what you would write inside the method body of this
// 'extra-method' that you have added to Predicate<T> ???
The following implementation of a class that extends "Predicate" cannot be instantiated without a constructor. It cannot be called a "#FunctionalInterface" and lambda-expression cannot be used to create them:
// #FunctionalInterface (Commented Out)
public class TypedPredicate<A> implements Predicate<A>
{
public boolean test(A a) { return pred.test(a); }
// This is how the "Class of A" becomes accessible. It this
// version it is a public (and final) field.
public final Class<A> className;
// NOTE: This is the most important part here, the class of
// Variable-Type Parameter 'A' must be passed as a parameter
// to the constructor. The programmer *LITERALLY* has to tell
// the code what type 'A' actually is! This is the *BANE* of
// what I call the Java-Erasure-Fiasco programming.
public TypedPredicate(Predicate<A> pred, Class<A> className)
{
this.pred = pred;
this.className = className;
}
// Again, because a constructor is necessary, this cannot be
// called a "Functional Interface" and it will not work very
// much like a java.util.function.Predicate<T>, but it will
// indeed implement the interface.
}
The best solution would realign whatever logic you have such that you do not need to guess what type a Predicate is! The next best thing would be to try the catch (ClassCastException) version that was suggested in the previous answer.
FINALLY: This idea regarding the java.lang.Class.isAssignableFrom(...) has the right idea behind it - but only if you actually have the Class<T> clazz as an instance in front of you, so to speak. The only way to get an instance of Class<T> would be to pass it to a constructor as in the example I have posted.
I am having some (philosophical?) problems with java's generics...
Consider the following
public interface ClassA<I> {}
public class Obj implements ClassA<String> {}
public interface ClassB<I, T extends ClassA<I>> {
public I getSomething();
public T getAnotherThing();
}
This compiles and works ok, if an object of ClassB is instantiated as:
ClassB<String, Obj<String>> o = new ClassB<>();
o.getSomething(); // <-- Returns String
I was wondering if there is a way to avoid instantiating a ClassB object without having to specify the String generic as well, since it's already inside ClassA. More specifically, I'd like to use it as:
public interface ClassB<T extends ClassA<I>> { // <-- Won't compile
public I getSomething();
}
ClassB<Obj> o = new ClassB<>();
o.getSomething(); // <-- Returns String from Obj declaration, which uses ClassA<String>
I know the "problem" can be easily gotten over with the first example, but I wanted to know if there's a way of reference the actual type of the generic in the implementing ClassA object without having to pass it again in ClassB's declaration, and if not, why.
Hope I was clear enough with my dilemma.
Thanks
I think the answer is "No". :)
Java doesn't provide a way to extract a type argument from a type itself, only from an argument having that type.
Eg:
class ClassB<T extends ClassA<?>> {
<I> I getSomething(ClassA<I>) { ... }
}
... works fine and could be passed an instance of T in order to extract I. But to remove the parameter from the method (which is used only to determine the type for I) you'd need a way to determine I from T itself, and there is no such way.
In general, type inference in Java is limited to establishing a relationship between parameter types and/or between parameter and return types.
The other way, then, would be to declare I and T together as part of one generic parameter, as you tried:
public interface ClassB<T extends ClassA<I>>
But then, as you noted, this is not accepted either. Java's syntax would need to be expanded in order to allow this.
I have a method which returns a complex generic type (which implements multiple interfaces)
protected abstract <BOB extends Stan & Jan<I>> BOB getStanAndJanItem();
This compiles fine, and i'm able to override it and return values. As soon as i call it i get compilation errors though (it doesn't even have to be assigned to anything). And i guess this makes sense, since BOB is only defined inside the method.
So, how do i define bob at a class level?
And YES, I know i can just split up the calls and have them return the same object, or introduce some additional inheritance (and i'll probably end up doing that) but can it be done this way as well?
Error Received:
Bound mismatch: The generic method getStanAndJanItem() of type MyAbstractClass<I> is not applicable for the arguments (). The inferred type Stan is not a valid substitute for the bounded parameter <BOB extends Stan & Jan<I>>
In order to call the method, you need to pass a generic type parameter that matches your constraint.
Even if your particular call doesn't need it, you still need to pass the type parameter.
Therefore, you can only call the method if you parameterize it with some class or interface that implements both of those types.
The real problem is the lack of support of intersection type. Suppose language support it directly, we can write intersection type like A&B etc, and your example would be like
Stan&Jan<I> getStanAndJanItem()
void setStanAndJanItem(Stan&Jan<I> item)
Stan&Jan<I> result = getStanAndJanItem();
result.doStanStuff();
result.doJanStuff();
setStanAndJanItem(result);
Without such support, we are stuck. Your generic declaration is probably wrong: it implies that the caller decides the BOB type, while you probably want the implementation to decide the BOB type. The implementation can return anything that implements both Stan and Jan<I>. Currently, that requirement cannot be expressed.
Most of the documentation regarding type erasure handling in Java assumes that the use case is handling a type like SomeType<ParamType>.
I am trying to process method parameter for the following method:
public void setOtherReferenceRanges(List<ReferenceRange<T>> referenceRanges)
When the container class is instantiated with a type DvQuantity, this signature should become
public void setOtherReferenceRanges(List<ReferenceRange<DvQuanitity>> referenceRanges) in runtime.
Using reflection one can see that the List has an actualTypeArgument which is ReferenceRange<T>. Since reflection uses class information, I would not expect it to give me ReferenceRange<DvQuantity>.
However, when I created the class containing this method, I passed the DvQuantity type as T. So the type filling in T should be available to Java runtime, but I could not find a way of getting it. I end up with a TypeVariableImpl object accessed via reflection, which does not seem to contain any useful data.
Can you think of any ways to discover this information in runtime?
When you say
when I created the class containing this method
I guess you mean when you create an object of that type, for example:
foo = new ContainerClass<DvQuantity>();
In that case, because of erasure, there is no way to recover the type DvQuantity.
However, if you create a class passing a type parameter to the superclass, like this
class DvQuantityContainerClass extends ContainerClass<DvQuantity> {...}
...
foo = new DvQuantityContainerClass();
Or, shorter, an inline anonymous subclass (which looks almost like the first example but with a subtle but important difference):
foo = new ContainerClass<DvQuantity>(){};
Then you can recover the type parameter, because you recover the type parameter used to extend a superclass at runtime. Unfortunately, Java itself doesn't provide an easy way to now get the type of the DvQuantityContainerClass.setOtherReferenceRanges method with the T filled in. For that, I've written gentyref, to do advanced reflection on generic types:
Method m = DvQuantityContainerClass.class.getMethod("setOtherReferenceRanges", List.class);
// this will return List<ReferenceRange<DvQuanity>>, like you are lookingn for
return GenericTypeReflector.getExactParameterTypes(m, DvQuantityContainerClass.class)
Generic type information is erased by the compiler and is not available at runtime. When I need to ensure a certain type at runtime I pass in a class argument:
public <T> void doSomething(T t, Class<T> c);
This is not always convenient or even possible, but for many cases it is possible.
So the type filling in T should be available to Java runtime, but I could not find a way of getting it.
Perhaps it's not entirely correct, but the way I think about it is that at runtime there is no actual class - just an object without a specific type which meets the interface of T. In other words, erasure happens not with objects, but instead with these nebulous (in the OOP world at least) type-things.
http://java.sun.com/docs/books/tutorial/java/generics/erasure.html
There are ways of capturing the type information inside the class itself (T types would need a method getUnderlyingType()... or something), but that's a bad idea. If you truly need to raw type of the object, I'd reconsider using generics.