I have two generic classes
class Value<T>{...}
class Parameter<T>{...}
And i want to call a method from another class (Params)
public <T> void put(Parameter<T> key, Value<T> value) {
parameters.put(key, value);
}
And from my main class i want to call it with two objects Value and Parameter but with the Type in this way:
Value<Integer> v1 = new Value<Integer>(2);
Parameter<Integer> p1 = new Parameter<Integer>(3);
Params params = new Params();
params.put(p1,v1);
And i receive this error from Eclipse:
The method put(Parameter<T>, Value<T>) in the type Parameters is not applicable for the arguments (Parameter<Integer>, Value<Integer>)
Any hint of how can i call this method without having this error? This classes were not developed by me, so I'm trying to call them without success.
The compiler cannot derive what your class is, so you have to give it a hint:
params.<Integer>put(p1,v1);
Wouldn't it make sense to make the Params class generic?
Related
I want to generify method reference to trigger methods per type,
I save Map of Function Interfaces by key, the functions will call services method, but I have an issue that I can't define paramater using method reference, e.g.:
private Map<Type, Function<User, Boolean>> functionInterfaces = new HashMap<>();
{
functionInterfaces.put(Type.MY_TYPE1, MyService::myTypeMethod1);
functionInterfaces.put(Type.MY_TYPE2, MyService::myTypeMethod2);
functionInterfaces.put(Type.MY_TYPE3, MyService::myTypeMethod3);
}
Currently I need to create method per type
private boolean myTypeMethod1(Parameters parameters) {
return myGenericTypeMethod(parameters, Type.MY_TYPE1);
}
private boolean myTypeMethod2(Parameters parameters) {
return myGenericTypeMethod(parameters, Type.MY_TYPE2);
}
I call function using apply:
if (map.containsKey(key)) {
map.get(key).apply(new Parameters.Builder().build());
}
Can I refactor code to use single method?
The problem with this
functionInterfaces.put(Type.MY_TYPE1, MyService::myTypeMethod1);
is that MyService::myTypeMethod1 is an instance method. It must take a MyService, because that is the instance to be acted upon. You are trying assign it to Function<User, Boolean>, but where is the instance in this case?
I don't know whether it makes sense to because we don't have much context, but changing the declaration to
Map<Type, BiFunction<MyService, Parameters, Boolean>> functionInterfaces = ...
would at least solve the compiler's problem.
In this case, it acts upon MyService, takes a Parameter and returns a Boolean.
Alternatively - and, again, we have limited context - making the MyService methods static would be sufficient, but you can only do that if they don't require any state.
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
I have a generic class in java defined as:
public static class KeyCountMap<T>
{
private Map<T, MutableInt> map = new LinkedHashMap<T, MutableInt>();
// ... rest of the properties...
public KeyCountMap()
{ }
#SuppressWarnings({ "unchecked", "rawtypes" })
public KeyCountMap(Class<? extends Map> mapType) throws InstantiationException, IllegalAccessException
{
map = mapType.newInstance();
}
//... rest of the methods...
}
I have defined same class in .NET as:
public static class KeyCountMap<T>
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
// ... rest of properties...
public KeyCountMap()
{ }
public void KeyCountMap<T>(T obj) where T : Dictionary<T, MutableInt>
{
obj = new T(); // Unable to define new instance of T
map = obj; // Unable to convert T to base class
}
}
And then a method is defined to sort map of type KeyCountMap<T> by value in the descending order . The method is defined as:
public static KeyCountMap<T> SortMapByDescendValue<T>(KeyCountMap<T> _map)
{
List<KeyValuePair<T, MutableInt>> _list = new List<KeyValuePair<T, MutableInt>>(_map.EntrySet());
// whereas _map.EntrySet() return of type HashSet<KeyValuePair<T, MutableInt>>
_list = _list.OrderByDescending(_x => _x.Value).ToList();
KeyCountMap<T> _result = new KeyCountMap<T>();
foreach (KeyValuePair<T, MutableInt> _entry in _list)
{
_result.Put(_entry.Key, _entry.Value);
}
return _result;
}
How can I get corrected the class defined in .NET ?
I assume you know Java erases any generic type information after compiling (there's metadata for variables, but actual objects are void of generic type information). Moreover, your code is not type safe:
#SuppressWarnings({ "unchecked", "rawtypes" })
You're using this because you're creating a non-parameterized instance of Map.
In .NET, you don't get around the type system like this, because generic type information is kept and used at runtime.
Let's see your C# code:
public static class KeyCountMap<T>
A static class in C# is a class that cannot be instanced, it's used for its static members alone. I think you don't want this. Perhaps KeyCountMap is a static nested class in Java, as opposed to an inner class.
In C#, you don't have inner classes. Nested classes don't share data with an instance of the containing class, it's as if the name of the containing class is part of the namespace for the nested class. So, you don't need, and actually don't want, the static keyword here.
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
In .NET, Dictionary is a class. To keep the intent, you should use IDictionary, the corresponding interface, as the type for the map field.
// ... rest of properties...
public KeyCountMap()
{ }
public void KeyCountMap<T>(T obj) where T : Dictionary<T, MutableInt>
Why the void return type, isn't this a constructor?
In C#, constructors can't be generic. You probably want a Type.
Your C# code just doesn't make sense, so here's what you could do:
public KeyCountMap(Type dictionaryType)
{
if (!typeof(IDictionary<T, MutableInt>).IsAssignableFrom(dictionaryType))
{
throw new ArgumentException("Type must be a IDictionary<T, MutableInt>", nameof(dictionaryType));
}
map = (IDictionary<T, MutableInt>)Activator.CreateInstance(dictionaryType);
}
}
We're checking the type before creating an instance. If we didn't, we would create an instance, the cast would fail and the assignment wouldn't even happen, so the new instance would just be garbage.
It may be that the actual instance will be a proxy; if so, you may not want to check the type before creating an instance.
You can't just copy-paste Java as C# (or vice-versa) and expect to make just a few changes until it works, for some definition of works, e.g. it compiles. The languages are not that similar, and chances are that too many subtle things are wrong.
This approach might be fun at first, but you'll stumble so often it will soon stop being any fun at all. You should learn the basics and understand the way things are done in the target language before you start translating code line-by-line. Many times, you may find that something you had to do in one environment already exists in the other or vice-versa, or that something may take more or less steps to do in the other, etc.
In this particular case, Java made Class be a generic class, while .NET kept Type a non-generic class. In .NET only interfaces and delegates may state generic type covariance or contravariance. This is rather restrictive anyway, if Type was generic, the intended uses could be either covariant or contravariant. But remember that in Java, a generic Class<T> at runtime is as good as Class, it only has any value at compile time and you can tell the compiler you know better anyway, just like you did.
There are two problems. First, you need to tell the compiler that T has a parameterless constructor, so you can call new T(). You can do that by providing the new() argument to the class definition.
You also have to tell the compiler that T is actually the dictionary you are trying to assign, so we have to extend the class a little more:
public class KeyCountMap<K>
{
private Dictionary<K, MutableInt> map = new Dictionary<K, MutableInt>();
// ... rest of properties...
Note that K is the key type of the dictionary, which you didn't specify yet.
Second, the T in your method can be another T than in your class. Omitting that will do the trick:
public void Map()
{
var obj = new Dictionary<K, MutableInt>(); // Unable to define new instance of T
map = obj; // Unable to convert T to base class
}
Maybe this is what you want?
public class KeyCountMap<T>
where T : new()
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
// ... rest of properties...
public KeyCountMap()
{ }
public KeyCountMap(T obj)
{
obj = new T();
map = (Dictionary<T, MutableInt>)(object)obj;
}
}
I want to use a constructor, that is written in Java, in Scala.
The constructor is declared in that way:
public <SUBCLASS extends Node> NodeDock(Parent<? super Node> parent, Class<SUBCLASS> cls, LookupCriteria<SUBCLASS>[] criteria) {
this(parent, cls, 0, criteria);
}
So if i want to use it:
val task = new NodeDock(scene.asParent(), classOf[FXTaskStackElement].asInstanceOf[Class[_]], new LookupCriteria[FXTaskStackElement]() {...}
Scala is giving me always an error that he cannot find the appropriate constrcutor with these parameters.
So how can i get the SUBCLASS of FXTaskStackElement for the LookupCriteria?
Edit:
In Java i would call this constrcutor like that, which works fine:
task = new NodeDock(scene.asParent(), FXTaskStackElement.class, new LookupCriteria<FXTaskStackElement>() {...})
Why are you using classOf[FXTaskStackElement].asInstanceOf[Class[_]] instead of just classOf[FXTaskStackElement]? Since your second argument is a Class[_], there is no suitable SUBCLASS.
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?