How can I pass parameter class name in generic constructor - java

public class RestResponseDTO<T extends Object> {
private T result;
}
code where I am initializing this:
public RestResponseDTO getObject(String url,Class clz){
Class cv = clz.getClass();
RestResponseDTO<cv> restResponseDTO =restTemplate.getForObject(url,RestResponseDTO.class);
return restResponseDTO;
}
How can I initalize RestResponseDTO in my getObject function depending upon the clz type?
ps- getForObject is spring restTemplate's standard function- http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#getForObject-java.lang.String-java.lang.Class-java.lang.Object...-

You can add method like this:
void init(Class clazz) {
//you initializing logic
}
and call it
RestResponseDTO<cv> restResponseDTO =restTemplate.getForObject(url,RestResponseDTO.class);
restResponseDTO.init(clz);
return restResponseDTO;
PS: Your cv variable will always have same value.

Please try:
ResponseEntity responseEntity = restTemplate.getForObject(url,RestResponseDTO.class);
and
responseEntity.getBody()
will give you Object T.

You can not pass a class with generic parameter to a method that has the parametertype Class<?>, you need something like Type.
One way (the only i am aware of) around is: create a concrete type that includes the generic parameter.
class IntegerResponse extends RestResponse<Integer>{
...
}
That way you can pass IntegerResponse.class

Related

Java generic type not working in this case

This class displays informations:
// display line numbers from a file
display(getLineNumber(myFile));
// display users from DB
display(getUsersName(myDBRepository));
etc...
I wanted to make a generic interface, so I can externalize the code that display information.
Then I could do something like:
myInformationElements.stream().forEach(e -> display(e.getValue());
Here is what I have so far (not working):
public interface InformationElement {
public <T> String getValue (T param);
}
public class NbFileLineInformationElement implements InformationElement{
#Override
public <File> String getValue(File param) {
return *same code as in getLineNumber(myFile)*;
}
}
public class UserInformationElement implements InformationElement{
#Override
public <UserRepository> String getValue(UserRepository param) {
return *same code as in getUsersName(myDBRepository)*;
}
}
Here my generic type is not working: File is not reconize as java.io.File (same for my jpa repository) What am I doing wrong here ?
Is this the best practice for my needs ?
You've defined type parameters File and UserRepository that are shadowing the class names File and UserRepository. This is one of the surprises of naming type parameters the same as existing classes. The type parameters don't represent the classes, and they don't have bounds, so the compiler can only assume they have Object methods.
This is not the best practice. When implementing generic methods, the methods must remain generic and at least as wide-open with respect to bounds. To be able to restrict what the type parameter means later, define it on the class/interface, and let subclasses supply what it's supposed to mean for that specific implementation with a type argument.
The best solution here is to move InformationElement's type parameter to the class, and to supply type arguments in your subclasses. The methods are no longer generic, but they do use the type parameters defined on the interface/classes.
interface InformationElement<T> {
public String getValue (T param);
}
class NbFileLineInformationElement implements InformationElement<File>{
#Override
public String getValue(File param) {
return /*same code as in getLineNumber(myFile)*/;
}
}
class UserInformationElement implements InformationElement<UserRepository>{
#Override
public String getValue(UserRepository param) {
return /*same code as in getUsersName(myDBRepository)*/;
}
}

Cast to compiletime unknown generic type

So, I got a problem with casting to an unknown (at runtime) generic method argument.
ValueDescription<?> valueDesc = /* get the value description */;
Object value = /* get the value */;
valueDesc.gotAValue(valueDesc.getType().cast(value));
The abstract class ValueDescription looks like this:
public abstract class ValueDescription<T> {
public abstract Class<T> getType();
public void gotAValue(final T value) {
// do something
}
}
Eclipse allways gives the following error:
The method gotAValue(capture#1-of ?) in the type ValueDescription is not applicable for the arguments (capture#2-of ?)
Is it even possible to do something like this?
Put this code into a generic method:
<T> void doStuff(ValueDescription<T> valueDesc) {
Object value = /* get the value */;
valueDesc.gotAValue(valueDesc.getType().cast(value));
}
This allows the compiler to know that the getType() and gotAValue "?s" are the same type, even when you don't know the T directly:
ValueDescription<?> valueDesc = /* get the value description */;
doStuff(valueDesc); // Fine, even though you've only got ?.
If you are not supposed to know the actual generic type of ValueDescription, then you should let the class do it for you.
public abstract class ValueDescription<T> {
public abstract Class<T> getType();
public void gotAValue(final Object value) {
final T castedValue = getType().cast(value);
// Continue
}
}
If you do this, you may need to throw an appropriate exception if the Object type value cannot be casted to the actual type.
If it is possible to determine the type of valueDesc, then use Andy's solution.
Edit
Actually, if you do not know the type of ValueDescription, then it is likely that this class does not need to have generic at all. getType() can simply return a Class<?> and subclass just needs to override it to return the correct Class object.

Passing Class object to the method

I have a library method, which returns a collection of Objects by class name.
For example
Iterable x = RunState.getInstance().getMasterContext().getObjects(XAgent.class);
would return a list of all Objects in Context which are InstanceOf XAgent.class
If use it in that way, it work very well. How ever I need a method to pass the class-name to.
public Iterable getObjectsFromContext(Class clazz) {
return RunState.getInstance().getMasterContext().getObjects(clazz);
}
getObjectsFromContext(XAgent.class);
And then it does not work any more, it returns All objects of context... so why it does not pass my "clazz" variable into getObjects() ?
here is the linkt ot javadoc of getObjects();
http://repast.sourceforge.net/docs/api/repast_simphony/repast/simphony/context/Context.html#getObjects-java.lang.Class-
IndexedIterable<T> getObjects(java.lang.Class<?> clazz)
update: this works:
public Iterable getObjectsFromContext(Class<?> clazz) {
return RunState.getInstance().getMasterContext().getObjects(clazz);
}
getObjectsFromContext(XAgent.class)
this worked for me:
public Iterable getObjectsFromContext(Class<?> clazz) {
return RunState.getInstance().getMasterContext().getObjects(clazz);
}
getObjectsFromContext(XAgent.class)
There was a right answer suggested, but I do not see it anymore to accept, that's why I post it on my own.
This won't work because your wrapper function, getObjectsFromContext, explicitly takes in a type of "Class".
Whatever you pass in, it will be interpreted as type "Class" and thus get passed into the getObjects() function as "Class". That will explain why the function returns all objects.
You'll need make your wrapper function generic.
public Iterable<T> getObjectsFromContext(T clazz) {
return RunState.getInstance().getMasterContext().getObjects(clazz);
}

Creating generic method names in generic class?

Currently, I have something like this:-
public class MyHolder<T> {
private T value;
public MyHolder(T t) {
this.value = t;
}
public T getValue() {
return first;
}
public void setValue(T t) {
this.first = t;
}
}
With this, I can use it like this:-
MyBean bean = new MyBean();
MyHolder<MyBean> obj = new MyHolder<MyBean>(bean);
obj.getValue(); // returns bean
Instead of calling the getter/setter to be getValue() and setValue(..), is it possible to "generify" that too?
Essentially, it would be nice to have it getMyBean() and setMyBean(..), depending on the type passed in. Granted this is a very simple example, however if I create a generic holder class that takes N generic properties, then it would be nice to call it something meaningful instead of getValue1() or getValue2(), and so on.
Thanks.
No. There is no such feature in Java. I can't even imagine how it would look syntactically... void set<T>();? And how would the getter / setter for for instance MyHolder<? extends Number> look?
No, it's not possible unless you use some kind of source code generator to have the MyHolder class generated based on your input.
But on the other hand, even if you had this possibility, how it would be different from using a Map<String, T>? So the invocation would read:
MyBean bean = new MyBean();
MyHolder<MyBean> obj = new MyHolder<MyBean>(bean);
obj.get('value');
No, not possible. Java generics are based on type erasure, i.e. it's mostly syntactic sugar provided by the compiler. That means each generic class is actually implemented by a "raw type" where are type parameters are Object and which already contains all the methods. So it's fundamentally not possible to have different methods depending on type parameters.

Passing a class ("Country.class") as an argument in Java

I'm trying to make a method that takes an argument of Country.class, User.class etc, and returns argument.count().
All the possible classes that I would give to this method extend from Model and have the method count().
My code:
private static long <T> countModel(Model<T> clazz)
{
// there is other important stuff here, which prevents me from
// simply by-passing the method altogether.
return clazz.count();
}
Called by:
renderArgs.put("countryCount", countModel(Country.class));
However this just doesn't work at all.
How do I do this, please?
I think you want to do
private long countModel(Class<? extends Model> clazz) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException
{
Method countMethod = clazz.getDeclaredMethod("count", null);
return (Long) countMethod.invoke(null, null);
}
Hopefully something like this would work (my reflection skills are not really that good).
Don't fully understand what you are trying to achieve. Did you mean this?
private static long <T> countModel(Model<T> model)
{
return model.count();
}
renderArgs.put("countryCount", countModel(country));
EDIT: If count is a static method, it has nothing to do with model. The static method is not inherited. So all you have to do is to call it directly,
renderArgs.put("countryCount", Country.count());
Clarifying, you want a class (A) that is constrained to have a particular class method (B) and you want to pass that class as an argument to some other method (C) and have that method (C) invoke that class method on that class (A.B())?
The first part, the type constraint, that can't be done. Java's type system just does not work that way.
The second part, passing a class as an argument and invoking a class method on it, that can be done using reflection. This is how to do it, correcting from your code (though you should be more careful with the exceptions than I've been in this).
private static <T extends Model> long countModel(Class<T> clazz) throws Exception
{
return (Long) clazz.getMethod("count").invoke(null);
}
The null is the instance to invoke this on (no instance; it's a class method). The cast to Long is required as the result of invoke() is an Object. The type parameter must go before the result type. And the whole thing can take any class that is a subclass of Model as a parameter; it will just fail at runtime if the count method isn't present. Them's the breaks.
(Also note that if you wanted to pass arguments to count(), you'd have to specify the classes of those arguments to getMethod and the values themselves to invoke, in both cases as subsequent arguments. Both support Java5 variable argument lists.)
In the line
renderArgs.put("countryCount", countModel(Country.class));
you call countModel with a Class<Country>, but you have to call it with an instance of Country like this:
Country country = new Country();
renderArgs.put("countryCount", countModel( country );
In reply to your comment to ZZ Coder; a static method in Java is called in the namespace context of a class, like Model.count() for a static method count() in the class Model, but the method does not become part of Model.class, Model.class is an instance of Class describing the class Model. (I can see where the confusion originates, it would be logical to have a specialised Model.class that includes the static methods, but Java isn't desinged that way.)
Your way out is to use reflection to call the static count() for the class that you pass to your code.
You are not passing an instance of country here, you are passing a Class object:
renderArgs.put("countryCount", countModel(Country.class));
You need to instantiate A model and pass it as an argument:
Model model = new Country();
renderArgs.put("countryCount", countModel(model));
or
Country country = new Country();
renderArgs.put("countryCount", countModel(country));
In this case, Country.class is an object of the Class<Country> type.
You are passing Country.class which is a Class object. How is it a Model object?

Categories