Java: How do I specify a class of a class method argument? - java

I have a method whose signature is:
public static <T> T isA(Class<T> clazz);
So I can do this:
String str = isA(String.class);
Where I'm having trouble is if I want T to be Class<String>:
Class<String> cls = isA(???);
I'm not sure how to formulate the argument to isA(). Can anyone offer guidence?
In case you're wondering why I want to do this, I'm using EasyMock to mock a class that takes a Class<T> argument.
EDIT: I was asked to add an example of what I'm trying to do.
I'm trying to use EasyMock to mock Solr's SolrCore class as part of a test case. The signature of one of SolrCore's methods is:
public <T extends Object> T createInitInstance(PluginInfo info, Class<T> cast, String msg, String defClassName);
With EasyMock I can set up an expectation for that method. The construct isA(PluginInfo.class), for example, tells EasyMock to match any object of class PluginInfo:
QueryParserPlugin queryPlugin = createNiceMock(QueryParserPlugin.class);
SolrCore core = createNiceMock(SolrCore.class);
expect(core.createInitInstance(
isA(PluginInfo.class), isA(xxx),
anyString(), anyString())).andReturn(queryPlugin);
My problem is telling isA() to match any object of class Class<T>, where T in this case is QueryParserPlugin.

The issue with reflection and java is type erasure. You just need to give the compiler a hint.
Since the object you are expecting is of type T, and the method itself is generic, you kinda have to
let java know what type you really are working with.
All it needs is a bit of a hint, something during runtime that can be passed through a compiled method that holds that type information.
So at compile time you have a method that takes in:
Class<String>
the compiler only knows the compiled type, so has no clue that the type itself is a class definition, making it impossible to assign if you don't tell java what the type of the assignment is.
So this works:
Class<String> myVar = String.class;
Or this works:
Class<String> myVar = isA(String.class);
Or this works
public <T> T myMethod(Class<T> object)
Class<String> class = myMethod(String.class)
but this doesn't work
public <T> void myMethod(Class<T> object);
since we have no assignment of T for the generic.
so how do you let the compiler know that T really is a class?
public <T> void myClassWrapper(Class<? super T> object);
myMethod(myClassWrapper(String.class));
so by passing it through a method that accepts you let the compiler know that at minimum that this thing is a class and that it represents T at some part of T's own hierarchy, thus letting the method compile.
or of course you could always just do
myMethod((Class<String>)string.class));
but I think thats kinda hackish personally. I am not a fan of casts that are not explcit and wrapped in a method.
Since you cannot control the signature of the test framework, you can however let java know your intentions.
I am not sure how easy mock works, but heres a test to kinda help explain whats going on.
#Test
public void testCreation(){
Object integer = 5;
String myString = "A String";
int five = typeTheObject(Integer.class, integer);
Class<String> stringClass = typeTheObject(myString);
Class<Integer> myInt = typeTheObject(five);
Class<?> myClass = typeTheObject(String.class);
TypeValidator typeValidator = new TypeValidator(stringClass);
typeValidator.isA(typeTheObject(String.class));
}
public static class TypeValidator{
private final Object objectToValidate;
public TypeValidator(Object object){
objectToValidate = object;
}
public <T> T isA(T type){
if(objectToValidate.getClass().isAssignableFrom(type.getClass())){
return type;
}else{
Assert.fail();
return null; //cuase
}
}
}
public static <T> Class<T> typeTheObject(Class<? super T> type){
return (Class<T>)type;
}
public static <T> T typeTheObject(Class<T> type, Object object){
if(object.getClass().isAssignableFrom(type)){
return (T)object;
}
return (T)object;
}
public static <T> Class<T> typeTheObject(Object object){
return (Class<T>)((T)object).getClass();
}
Though one big drawback is paramaterized types. But those can be solved using a guice type literal.
(new TypeLiteral<List<String>(){}).getRawType();
since its annon the type holds during runtime.

Related

Java valueOf method for generic class

Given a generic class Foo<T>, I would like to create a static method valueOf(String s). The String s should hold the name of a class (e.g. "java.lang.Integer"). A call to valueOf("java.lang.Integer") should then return a new object Foo<Integer>.
In my class (see code below), I want to store the Class<T>, which is passed as parameter to the constructor Foo(Class<T> clazz). But in the valueOf-method, I am not sure what parameter to pass to the constructor Foo(Class<T> clazz) of the object I like to return.
Since I am relatively new to java reflections, I am unsure how I can implement this logic to my generic class. I have learned that the Class.forName(String) method returns an object Class<?>, but I don't know how to find out the type that the wildcard ? stands for (in case that's possible using reflections), or am I wrong going into this direction?
public class Foo<T> {
private Class<T> clazz;
public Foo(Class<T> clazz) {
this.clazz = clazz;
}
public static <E> Foo<E> valueOf(String s) throws ClassNotFoundException {
Class<?> clazz = Class.forName(s);
// here i am stuck. I would like to return new Foo<E>,
// but what is E, E's class and therefore the parameter for the constructor?
}
}
You can't do this with generics. Generics are just casts the compiler puts in for you, statically. So, if you couldn't do this with casts you write in the code (that is, you can't have a different cast for different strings), you can't do it with generics either.
You need some sort of key instead of a String which conveys the type T/E. You can pass in the Class<E> directly:
public static <E> Foo<E> valueOf(Class<E> clazz) throws ClassNotFoundException {
// ...
}

Java get the second generic types

I'm struggling to get the type of second generic from an object.
The abstract class takes two Generic types T and S
abstract class Concept<T, S> {
public Concept() {
//do nothing
}
public final Class<?> getTypeParam() {
ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
Class<?> result = (Class<?>) parameterizedType.getActualTypeArguments()[0];
return result;
}
}
In this derivative class one (in this case T) generic is defined:
public class Decision<S> extends Concept<String, S>{
public Decision () {
super();
System.out.println(getTypeParam()); //returns the first parameterized type. How do I get the second one?
}
}
When I now run it I get the first parmerized generic back. Great. But how do I get out the second one?
public class Main {
public static void main(String[] args){
Decision<Boolean> myBooleanDecision = new Decision<>();
}
}
Your problem is based on the fact that you aren't clear on your requirements.
Your method signature looks like this: public final Class<?> getTypeParam()
But what you overlook: the number of type parameters with your classes isn't fixed. The base Concept class allows for two type parameters, but the Decision subclass "fixes" the first parameter to String.
Thus: you have to decide what you actually want/need. There are various solutions, like:
public final Class<?> getFirstParam() ... to return index 0, always
public final Class<?> getSecondParam() ... to return index 1, always (which obviously fails for classes that only have 1 generic type parameter)
public final List<Class<?>> getParams() ... to return a list with all entries
That is your option space. Which solution to pick solely depends on the purpose of that method (which we don't know anything about).
Personally, I would go for the third option, as that will work for 0, 1, ... n type parameters, without any changes.
Change the decleration:
Decision<Boolean> myBooleanDecision = new Decision<>("Binary Decision") {};
Now this will result in the second generic:
Class<?> result = (Class<?>) parameterizedType.getActualTypeArguments()[0];
Output is:
class java.lang.Boolean

Lambda generic type bounds

I have the following method:
public <T> T getObjectFromMessage(Class<T> clazz) {
return gson.fromJson(compressor.decompress(message.getJsonInputs(s3)), clazz);
}
I want to pass getObjectFromMessage as a parameter into a lambda that's supplied to me. The lambda can then supply the class of the object that it expects to find in the message, and get an instance of it back. Is there a way to do this without losing the type information?
I can force it to work with casting and some Object bounds, but I'd really like the consumer to know that if it passes in a Class<T> it will get a T back, much like any method with generic bounds.
In the consuming lambda, I'm currently forced to do declaration gymnastics like:
public void consume(Function<Class<Object>, Object> getInputs){
MyType type = (MyType)getInputs.apply(MyType.class);
}
but there are cases where I want to try to parse the inputs, and if I fail, try a different class. The generics really need to be inferred per-call, as a method would.
You can define a custom function interface with a generic method:
interface TypeFunction {
<T> T apply(Class<T> clazz);
}
public void consume(TypeFunction getInputs) {
MyType type = getInputs.apply(MyType.class);
}
Some thoughts on this... does a function that invokes another function add anything?
For example:
<T> T consume(ReadType<T> typeFunction) {
T type = typeFunction.read();
return type;
}
There are generic types being managed in at least 3 entities here:
The class that contains the message string.
The function that deserializes the message string to an object.
The function that calls the deserializer function.
I expect from the question that the Object that holds the message string is also responsible for deserialization? If so you could consider declaring the generic type there. That would prevent the need of passing the type to the deserializer function, for example this could be simplified further:
<T> ReadType<T> readObjectFromMessage(Class<T> clazz) {
return () -> readValue(clazz);
}
I've declared ReadType as:
interface ReadType<T> {
T read();
}
Also implemented a simple test to check outputs and visualise how this might be used:
#Test
public void consumeTypeTest() throws Exception {
String message = "{\"foo\":\"hello\",\"bar\":\"world\"}";
GenericFunctions genericFunctions = new GenericFunctions(message);
ReadType<MyType> myTypeFromMessage = genericFunctions.readObjectFromMessage(MyType.class);
MyType myType = genericFunctions.consume(myTypeFromMessage);
Assert.assertThat(myType, equalTo(new MyType().setFoo("hello").setBar("world")));
}

Get class based on variable generic class

I'm trying to get the solution to achieve the following:
public final static <T> Class<Set<T>> getSetClass(Class<T> cls) {
...
}
Where cls is for example String.class and the method then returns the Class<Set<String>> object. But of course, as cls is variable, it could also get Boolean.class and then return a Class<Set<Boolean>> object.
How can I achieve this?
This works for me:
#SuppressWarnings("unchecked")
public <T> Class<Set<T>> getSetClass(Class<T> cls) {
Set<T> set = new HashSet<>();
return (Class<Set<T>>) set.getClass();
}
Well, it compiles; how useful it is to solve your "real" problem; I can't tell yet. And obviously; that cls parameters goes unused here.
But it does something:
#Test
public void test() {
Class<Set<Integer>> setClass = new PartitionPropertiesTest().getSetClass(Integer.class);
System.out.println("whatever: " + setClass);
}
prints:
whatever: class java.util.HashSet
There is no Class<Set<String>> object.
Generic types are erased at runtime, so there is only an instance of Class<Set> (namely Set<?>.class) shared by all the Class<Set<?>>. There is no way to get back to String from this object.
For this very reason, your JSON library has a TypeRef class to capture the generic type information. You just use that instead of Class.
You mean, how to define that the return type depends on the parameter type?
Try this:
public final static <T> Class<Set<T>> getSetClass(Class<T> cls) {
...
}

How can a generic base type be cast via reflection in Java?

Let's say I have the following class:
public class MyClass<T> {
Class<T> type;
List<T> items;
public Class<T> getType() { return type; }
...
}
I need to store objects of the above class in a generic container:
public class MyContainer<T> {
Class<T> type;
List<MyClass<T>> myClasses;
public Class<T> getType() { return type; }
...
}
Let's say later in my code I'm given a generic object as an argument:
public class Main {
public static void main() {
List<MyContainer<?>> containers;
...
}
public void someMethod(MyClass<?> myClass){
...
}
}
I have type T as reflection. I need to cast MyClass<?> back to its intended type. So if it was declared as MyClass<String> I need to cast it back to MyClass<String>. I can't seem to do this with the reflection type because it is only capable of casting T, not MyClass<T>.
I could cast T by doing this for example:
myClass.getType().cast(myClass.getItem()); // Where getItem returns an object of the type T
But what I want is this:
myClass.getType().cast(myClass); // getType() returns T not MyClass<T>
So the question is, how do I cast a generic base type along with its reflection type, given the scenario above?
This is impossible due to type erasure. Reflection can't help you here because at runtime the generic type information isn't available. In other words at runtime there is no MyClass<String>, there is only MyClass. MyClass<String> is a pure compile-time creature.
If you have some piece of code that expects a certain type, declare that at compile time. This type expectation could be concrete or generic:
public void someMethod(MyClass<String> myClass)
or
public <T> void someMethod(MyClass<T> myClass)
If you know the type, you don't need cast(), you can just cast:
#SuppressWarnings("unchecked")
MyClass<String> myClassStr = (MyClass<String>)expression;
Since T doesn't exist at runtime, which you know, you can't use it. You also can't get a Class<List<T>>.
myClass.getType().cast(myClass.getItem()) doesn't really work for you because if you have a MyClass<?> then you also have a Class<?> which only returns Object. A Class<T> doesn't really help you either, because you need to actually know what T is.
You can pretty much do two things.
Use decisions:
if(myClass.getType() == String.class) {
#SuppressWarnings("unchecked")
final MyClass<String> myStrings = (MyClass<String>)myClass;
// use MyClass<String> ...
}
Use polymorphism:
MyClass<String> myClass = new MyClass<String>(...,
new BiConsumer<String, JTable>() { // (or lambda ...)
#Override
public void accept(String s, JTable table) {
// use String ...
// configure JTable ...
}
});
... elsewhere ...
public void someMethod(MyClass<?> myClass) {
someCaptureMethod(myClass);
}
private <T> void someCaptureMethod(MyClass<T> myClass) {
Consumer<T, JTable> consumer = myClass.getConsumer();
for(T theT : myClass.getList()) {
consumer.accept(theT, myTable);
}
}
Generally the second example is considered the "better" way but the code might be longer in versions of Java prior to 8.

Categories

Resources