I'm having trouble figuring out how to properly cast a generic object in java to a type that extends the generic object.
For example, say I some setup like the following:
public class Parameters extends SomeCustomMap<String, String>
{
...
}
public class SomeCustomMap<K, V> implements Map<K, V>
{
public SomeCustomMap<K, V> getSubSet(...)
{
SomeCustomMap<K, V> subset;
...
return subset;
}
}
class ExampleApp
{
private void someMethod()
{
Parameters params;
Parameters paramsSubSet;
try
{
...
paramsSubSet = (Parameters) params.getSubSet(...);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Running code similar to the above consistently throws a ClassCastException, the likes of which I do not fully understand. Any assitence for how to correctly set up a scenario similar to the above would be appreciated! Namely, how might I properly cast the the SomeCustomMap object that is returned from the params.getSubSet(...) method back to a Parameters object?
Thanks in advance!
Your Problem is that the Subset returned by getSubSet is a of instance SomeCustomMap and not of Parameters.
This problem does not deal with generics. You will get the same problem if you did not use generics.
I don't know how you create an instance of subset but maybe you could use the template desing pattern and some generics to fix your problem.
You can try something like this:
public <T extends SomeCustomMap<K, V>> T getSubSet(...){
T subset = (T)this.clone();
subset.clear();
return subset;
}
creation looks a little funny - feel free to change it to whatever you want :)
As a bonus you will not need to cast :)
paramsSubSet = params.getSubSet(...)
Though I've commented asking for more information, based on what you've posted so far, I think getSubSet is constructing a SomeCustomMap to return (with new SomeCustomMap) somewhere. If you don't override getSubSet in Parameters, then Parameters.getSubset will return a SomeCustomMap (the base class), not a Parameters, so your typecast to Parameters fails.
(Hot tip, if you override getSubSet in the Parameters class, you can change the return type to Parameters and avoid the typecast.)
Generics don't inherently have anything to do with casting (save that due to the nature of erasure, generic parameters cannot be checked during a cast).
If you're getting a ClassCastException in this case, it means that the object returned really is not an instance of Parameters. Just before you cast, try calling
System.out.println(params.getSubSet(...).getClass());
and see what the actual run-time class of the subset is. Chances are the problem lies elsewhere, as your expectation that the subset is a Parameters object is almost certainly not correct at runtime - it's a SomeCustomMap or some other subclass thereof.
As others have explained, the issue is that the actual object you are constructing in getSubSet() is not an instance of Parameters.
Here's one possible workaround. I don't love it, but it is a way to declare the method in SomeCustomMap but have its return value be typed correctly for any subclass.
public static <T extends SomeCustomMap<K, V>> getSubSet(T fullSet)
{
T subset;
... (use fullSet instead of this)
return subset;
}
Related
This question is more theoretical (what I want to do is more complicated but this is the part I'm stuck on), so apologies for the contrived example which may not make much sense.
Say I have some class that has methods that return its value in different forms:
public class MyObject {
public String getAsString() {...}
public int getAsInt() {...}
// and so on
}
I'm trying to create a single method to allow me to specify which MyObject method to call via its parameters. Something like:
public <T> T getValue(MyObject obj, Class<T> c) {
if (c == String.class) {
return obj.getAsString();
} else if (c == Integer.class) {
return obj.getAsInt();
} // and so on
}
So then I would like to call this method like this, assuming obj is a MyObject:
String s = getValue(obj, String.class);
int i = getValue(obj, Integer.class);
// and so on
I'm getting the compile error "Type mismatch: cannot convert from String to T" (and likewise for Integer) in the getValue method. Clearly I'm just not understanding generics fully, but I thought this was the general idea behind generics - here I'm specifying (or trying to specify, at least) the real type of T via the parameter c. What am I doing wrong?
If you want to to create a single method with really safe casts - then I would suggest to setup a mapping between the expected type and its respective getter.
Given the MyObject class definition as:
public class MyObject {
public int getIntValue() {
return 42;
}
public String getStringValue() {
return "Answer";
}
}
So that the "accessor" class could look as follows (it can be generalized further if needed):
public class MyObjectAccessor {
private final Map<Class<?>, Function<MyObject, ?>> registry = new HashMap<>();
public Accessor() {
registerGetter(Integer.class, MyObject::getIntValue);
registerGetter(String.class, MyObject::getStringValue);
}
private <T> void registerGetter(Class<T> type, Function<MyObject, T> getter) {
registry.put(type, getter);
}
#SuppressWarnings("unchecked")
public <T> Optional<T> getValue(MyObject obj, Class<T> type) {
return (Optional<T>) ofNullable(registry.get(type)).map(getter -> getter.apply(obj));
}
}
This would allow you to make the behavior much more predictable with a control over the unexpected/missing mapping.
(Here it returns an Optional back, but you can also throw an exception or provide a default value or do something else)
Please note that the cast inside getValue is actually a safe checked cast (even though it was marked with #SuppressWarnings) as the "safety" proof here is a little bit beyond current javac's capability of static code analysys.
First of all, if getAsString and getAsInt are not doing any conversion (such as would be the case if all your values were stored as strings), you probably can reduce your method to this:
public <T> T getValue(MyObject obj) {
return (T) obj.value;
}
This will have an unchecked cast warning, but that's not worse than leaving the typing decision to your caller (so I'd just #SuppressWarnings("unchecked") it). If your caller uses the wrong target type, they will get a ClassCastException at runtime, which I assume goes well with your current contract. But you can keep c.cast(obj.getAsX()) if you want the exception to be raised in your own method.
With the above, your callers would just use:
String s = getValue(obj);
int i = getValue(obj);
If, however, you are actually converting data in getAs... methods, then you will need to cast in your generic getter after dispatching to the correct getAsX method, at least as ProGu suggested (i.e., return c.cast(obj.getAsX()) in each branch).
I'm trying to create DI container get method, but struggling with signature. Currently I have this definition:
public Object get(Class<?> key) {
// returns instance of `?`
}
The part of my code which I dont like much is usage of the get method:
IRouter router = (IRouter) container.get(IRouter.class);
where I have to cast return with (IRouter). Any ideas how to change method signature to make usage like this?
IRouter router = container.get(IRouter.class);
Thanks in advance for any ideas!
By using a scoped method parameterized type :
public <T> T get(Class<T> key) {
// ...
return (T) foo;
}
Here I suppose that foo is not typed as T.
If it is already typed as T you can of course return it without cast.
You could so invoke it :
IRouter router = container.get(IRouter.class);
I'm trying to genericize a factory method that returns
a generic Base class. It works, but I'm getting the
"BaseClass is a raw type..." warning.
I've read through the Java docs on Generic methods,
but I'm still not quite getting how to accomplish this.
Here's some code:
Class #1
//base abstract class
public abstract class BaseFormatter<T>
{
public abstract String formatValue(T value);
}
Class #2
//two implementations of concrete classes
public class FooFormatter extends BaseFormatter<Integer>
{
#Override
public String formatValue(Integer value)
{
//return a formatted String
}
}
Class #3
public class BarFormatter extends BaseFormatter<String>
{
#Override
public String formatValue(String value)
{
//return a formatted String
}
}
Factory Method in a separate class
public static BaseFormatter getFormatter(Integer unrelatedInteger)
{
if (FOO_FORMATTER.equals(unrelatedInteger))
return new FooFormatter();
else if (BAR_FORMATTER.equals(unrelatedInteger))
return new BarFormatter();
//else...
}
Call to the Factory Method from elsewhere in the code
BaseFormatter<Integer> formatter = getFormatter(someInteger);
formatter.formatValue(myIntegerToFormat);
The problem is the getFormatter() method warns that BaseFormatter is
a raw type, which it is. I've tried various things like BaseFormatter
et al. I, of course, want the return type to be generic, as in the declared
BaseFormatter in the calling method.
Note that the formatter type is not based on class type. e.g. not all Integer
values are formatted with a FooFormatter. There are two or three different
ways an Integer (or String, or List) can be formatted. That's what the
param unrelatedInteger is for.
Thanks in advance for any feedback.
If getFormatter is defined in BaseFormatter, then use:
public static BaseFormatter<T> getFormatter(Integer unrelatedInteger)
If getFormatter is defined in another class than BaseFormatter, then use:
public static BaseFormatter<?> getFormatter(Integer unrelatedInteger)
You're actuaaly saying that there's no connection between the typed parameter of BaseFormatter and the unrelatedInteger that is passed as argument to the getFormatter method.
I get some other warning:
Uncehcked Assignment: BaseFormatter to BaseFormatter<Integer>
This warning is worse than the one you indicated. It warns that this user code might try to insert a BaseFormatter<String> into BaseFormatter<Integer>, something that will be noticed only when fails in runtime... Consider a user accidentally uses you factory method like such:
BaseFormatter<Integer> myUnsafeFormatter =
FormatterFactory.getFormatter(unrelatedIntegerForBarFormatter);
The compiler cannot relate the unrelatedInteger with the parameterized type of the returned BaseFormatter.
Alternitavely, I'd let the user explicitly use the concrete formatter constructors. Any common code shared by all formatters could be put into FormatterUtils class (just don't let that utils class to grow to much...).
Some type systems in academic languages can express a so-called dependent sum. Java certainly cannot; so what, sensibly, could be the type of the object returned by the getFormatter method? The best we can do is BaseFormatter< ? extends Object >, or BaseFormatter< ? > for short, as Integer and String have only Object in common.
I think the original post begs the question, why must we use an integer to decide what formatter to return, and if the type of formatter would not be known by the caller, why would the caller need a stronger variable type than BaseFormatter< ? >?
I've been reading Effective Java and decided to try to put some of what I've learned into action. I'm trying to effectively create a Multimap<?, Condition<?> > where the wild card will be the same type for both the key and the value, but it will be different, distinct types.
Here is the item from the book I'm looking at: Item 29
I'm not trying to fully replicate it. I realize the big difference is the key does not represent the value directly as per the link. In mine, the key represents the generic type of the value.
So I will do mmap.put(Class<Integer>, ConditionMapping<Integer>)
when I do the get I don't have the generic type of the ConditionMapping, so I get the unchecked cast warning.
I have a get method that I want to have the signature <T> List<Condition <T> >(Class<T> type)
Due to type erasure, is my only option to make sure the condition.value is of type T and building a new list of objects?
I could just ignore the unchecked cast warning, but I'm just trying not to. Any suggestions? Tips? Tricks?
There is no way to express that the two wildcards should capture the same type. See this question for a similar situation and a number of possible solutions.
If you make your interface extend Multimap<Void, Condition<?>> it allows your user to call some of the methods that do not rely on type safety (e.g. containsKey) but not to add entries (bypassing your type-checked proxy methods) unless they use unchecked casts.
interface ConditionMapBase<T> extends Multimap<T, Condition<?>> {
}
interface ConditionMap extends ConditionMapBase<Void> {
<T>boolean putCondition(T key, Condition<T> value);
<T>Collection<Condition<T>> getConditions(T key);
}
class ConditionMapImpl
extends ForwardingMultimap<Void, Condition<?>>
implements ConditionMap {
ConditionMapImpl() {
delegate = HashMultimap.create();
}
#SuppressWarnings("unchecked")
#Override
protected Multimap<Void, Condition<?>> delegate() {
return (Multimap<Void, Condition<?>>) (Multimap<?, ?>) delegate;
}
private final Multimap<Object, Condition<?>> delegate;
#SuppressWarnings("unchecked")
#Override
public <T> Collection<Condition<T>> getConditions(T key) {
return (Collection<Condition<T>>) (Collection<?>) ((ConditionMapBase<T>) this).get(key);
}
#SuppressWarnings("unchecked")
#Override
public <T> boolean putCondition(T key, Condition<T> value) {
return ((ConditionMapBase<T>) this).put(key, value);
}
}
You could make a MyClass and then pass your own type to it, and ecapsulate the Multimap inside that. Template impossibilities in Java can often be solved by adding another layer, so to speak, and templating a class around what you really want, since you can get a "T" type that way, which you can then use for Lists or Maps, and guarantee that it is the same for multiple templates from then on.
This might be a step in the right direction.
<Multimap<Class<?>, Condition<?>>
I'm trying to create a generic type that keeps a map of the versions of itself that have been created for later use. Effectively, it's an singleton pattern where there's one instance per type. The code I have so far is:
public class FieldBinder<T> {
static final Map<Class<? extends Object>,FieldBinder<? extends Object>> instanceMap =
new HashMap<Class<? extends Object>,FieldBinder<? extends Object>>();
private FieldBinder() {}
synchronized public static <V extends Object> FieldBinder<V> getInstance(Class<V> klass) {
if(!instanceMap.containsKey(klass)) {
instanceMap.put(klass, new FieldBinder<V>());
}
return (FieldBinder<V>)instanceMap.get(klass);
}
}
However, I'm still unsure that I'm "doing it right". It feels like I should be able to specify that the collection is (Class -> FieldBinder). The fact that the IDE is warning about the return statement only reinforces this thought.
Is there a better way to handle this?
Note: This question seems very closely related, but just far enough away that I can't figure out how to apply the information in it to my own problem.
Your implementation is correct. There's no "better" way of doing it (if there is such a thing is "better" in code, which is another issue..)
Minor fixes:
<V extends Object> is equivalent to V which is less verbose
Class<? extends Object> is equivalent to Class<?> which is less verbose
You can use the #SuppressWarnings("unchecked") annotation to tell your compiler that the cast is safe
I don't think it can be done without having an unchecked cast somewhere. You would need something similar to Haskell's existential types, which Java does not have.
You could make the client perform the unchecked cast instead...
synchronized public static <V> FieldBinder<V>
getInstance(Class<V> klass, Class<FieldBinder<V>> binderKlass) {
if(!instanceMap.containsKey(klass)) {
instanceMap.put(klass, new FieldBinder<V>());
}
return binderKlass.cast(instanceMap.get(klass));
}
Now if the client passes a Class<FieldBinder<V>> to the getInstance() method you can avoid the unchecked cast within getInstance().
Unfortunately creating a Class<FieldBinder<V>> itself requires an unchecked cast.
Class<FieldBinder<Integer>> binderKlass =
(Class<FieldBinder<Integer>>) (Class<?>) FieldBinder.class;
BinderAssociator.getInstance(Integer.class, binderKlass);
RHSeeger, I got your original question. I found no solution for the problem. What you can try to play with is a MyMap class, which makes the binding as you request. However with this map two problems arise:
As it is declared as MyMap<?>, one cannot add something with a given type to it. That's dummy and I refer you to Java Generics FAQs (see case study 3) for more details.
As map has connection between key and value, one cannot add two independent objects of any type (two <?> refer to different types) because these two types may be not connected.
While playing I have seen some errors, which I could not explain myself. I think, everything goes into the fact (as I mentioned before) that we try to deal with 2-nd level parametrization.
class FieldBinder<T> {
static class MyMap<M> extends HashMap<Class<M>, FieldBinder<M>> {
}
static final MyMap<?> instanceMap1 = new MyMap<Object>();
static final Map<Class<?>, FieldBinder<?>> instanceMap2 = new HashMap<Class<?>, FieldBinder<?>>();
public static <V> void test() {
Class<V> c1 = null;
FieldBinder<V> f1 = null;
Class<?> c2 = null;
FieldBinder<?> f2 = null;
instanceMap1.put(c1, f1); // error (see 1)
instanceMap1.put(c2, f2); // error (see 2)
instanceMap2.put(c1, f1); // ok
instanceMap2.put(c2, f2); // ok
instanceMap2.put(c1, f2); // wish to be an error, but ok
instanceMap2.put(c2, f1); // wish to be an error, but ok
}
}
The example you refer tells, how to recover the type (class) of object, while you need to recover the type (class) of parametrization. That is not possible.