Get class based on variable generic class - java

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) {
...
}

Related

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 array class of generic type

I have a class with a generic type.
import java.lang.reflect.Array;
public abstract class MyClass<T> {
private Class<T> clazz;
private Class<?> arrayClazz;
public MyClass() {
clazz = ClassUtils.getParameterizedClass(getClass());
arrayClazz = Array.newInstance(clazz, 0).getClass();
}
}
The Utils method reads the generic type of the given class so I don't have to pass the same class as a constructor parameter. What I'm trying to achieve is getting the array class of clazz.
For example if T is String then
clazz = String.class;
arrayClazz = String[].class;
I currently solved it by creating a new instance of T[] and reading its class. I wanted to know if there's a better way or if there are any downsides with this method.
Update
What I'm trying to do: I have a generic DataProvider which requests JSON from a server. I use GSON to parse the response.
public abstract class DataProvider<T> {
private final Class<T> resourceClass;
private final Class arrayClass;
protected DataProvider() {
this.resourceRootPath = resourceRootPath;
this.resourceClass = ClassUtils.getParameterizedClass(getClass());
arrayClass = Array.newInstance(resourceClass, 0).getClass();
}
public void get(String id) {
...
T obj = gson.fromJson(response.body().charStream(), resourceClass)
...
}
public void list(String id) {
...
T[] objs = gson.fromJson(response.body().charStream(), arrayClass)
...
}
}
You should look up Type Erasure, which may prevent a clean way of doing what you're asking for. (Generics can't help you here.)
The problem is that in Java, generic type data is used at compile time to ensure everything looks good... and then Java forgets about it entirely. The types aren't compiled in in the way you'd hope, they're just gone.
Because of that, your approach is (I think!) the cleanest, even if it feels hacky. You need to instantiate one and use reflection to get it's type.

Instantiating a class with a generic type parameter in java

I am trying to write a factory class to return an instance of a class with a generic parameter type. I think this can be done using reflection but I am confused as to how.
Here is an example of what I am trying to do.
public class GenericObjectFactory {
public GenericObject<?> getGenericObject(Class clazz){
// I want to return a new instance here of the generic object with type parameter clazz. So something like this...
return new GenericObject<clazz>();
}
anyone any idea how it's done?
I know I can instantiate clazz with newInstance but I want GenericObject.
ie getGenericObject (string.getClass()) would return a new GenericObject < String >();
Sorry this post is a bit rambly. I hope it makes sense. Thanks in advance.
Tracey
Typical clear solution for your problem is the following:
public class GenericObjectFactory {
public <T> GenericObject<T> getGenericObject(Class<T> clazz){
return new GenericObject<T>();
}
}
Since T is erasure, so the new created instance of GenericObject even does not "know" what is the value of its parameter T, you will probably want to pass the clazz to constructor of GenericObject
public class GenericObjectFactory {
public <T> GenericObject<T> getGenericObject(Class<T> clazz){
return new GenericObject<T>(clazz);
}
}
Obviously you have to define such constructor.
EDIT
Here is the usage example:
GenericObjectFactory factory = new GenericObjectFactory();
GenericObject<String> gs = factory.getGenericObject(String.class);
GenericObject<Integer> gs = factory.getGenericObject(Integer.class);
I think you need the following:
public <T> GenericObject<T> getGenericObject(){
return new GenericObject<T>();
}
Example usage:
GenericObject<String> obj = genericObjectFactory.getGenericObject();

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

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.

Get the the type of the class of a generic type?

A class which has a method declared as this:
public class A{
public <T> T test(java.lang.Class<T> classOfT)
}
Normally it can be called against an object like this:
A a = new A()
String s = "test";
a.test(String.class); //I wrote this as s.class at first,which is wrong.Thanks Nick.
Now I would like to generalize the object passed to it, so I declare a class like this:
public class B <T>{
private A a = new A();
private T obj = null;
T test(){return a.test(obj.getClass()); }
}
But the code wont' compile.I am wondering is it possible to achieve my goal?
Thank you in advance Java gurus ;)
T obj = ...;
obj.getClass()
The last line returns Class<? extends T> -- but T is unbounded, so it is basically bounded by Object, which means it returns Class<? extends Object>, which is the same as Class<?>.
So doing this:
T test () { return a.test(obj.getClass()); }
Will actually invoke a.test with a parameter of type Class<?>, which returns an Object, and not a T.
Just cast the parameter to Class<T> or the return type to T and it should work -- although I am yet to understand why you need something like this. Also, there is this strange error in the original post:
String s = "test";
a.test(s.class);
Doing "test".class is wrong -- it should be String.class.
Class<T> clazz = (Class<T>) obj.getClass();
return a.test(clazz);
Try
#SuppressWarnings("unchecked")
T test() {
return (T) a.test(obj.getClass());
}
In complement of the other answers, when defining your function as
public class A{
public <T> T test(java.lang.Class<T> classOfT) { ... }
}
if you are using the classOfT parameter just to determine the type of T, you might be better off defining your method with no parameter at all. For instance, do this instead of the above declaration :
public class A{
public <T> T test() { ... }
}
That way you can just call it using this qualified method-call syntax. This is how I would rewrite your code:
public class A{
public <T> T test() {
// ...
}
public static void main(String[] args) {
A a = new A();
String result = a.<String>test();
}
}
public class B <T> {
private A a = new A();
T test() {
return this.a.<T>test();
}
}
This way you do not need to pass the generic A#test() function a class parameter, which would possibly have been unused at runtime.
Of course if you do use the classOfT at runtime, this solution may not be that much interesting for you...

Categories

Resources