Java Generics in arguments - java

I have the following interface:
public interface IRadioButtonGroup<T> {
List<IRadioButton<T>> getButtons();
}
Now I create a method
protected Object getDefaultRadioButtonValue(IRadioButtonGroup<?> field) {
List<IRadioButton<?>> buttons = field.getButtons();
Now java is complaining:
Type mismatch: cannot convert from List<IRadioButton<capture#1-of ?>> to List<IRadioButton<?>>
Any suggestions?

The unbounded wildcard parameter type of your method means that, it will accept an IRadioButtonGroup of an unknown type. The compiler doesn't know what type will come, but at compilation time, the compiler does generate and assign each wildcards with a placeholder, because although it doesn't know which type is coming, it is sure that there has to be a single type that will replace ?. And that placeholder is capture#1-of ? you see in the error message.
Basically, you are trying to assign a List<IRadioButton<Cap#1-of-?>> to a List<IRadioButton<?>>, and that is not valid, in a similar way how List<List<String>> cannot be assigned to List<List<?>>.
One well known way to solve these issues is to use capture helpers. Basically you create a generic method, and delegate the call to that method. That generic method will infer the type parameter and then you would be able to do type safe operation. See this Brian Goetz's article for more details.
So to solve the issue, provide another method as in below code:
protected Object getDefaultRadioButtonValue(IRadioButtonGroup<?> field) {
return getDefaultRadioButtonValueHelper(field);
}
private <T> Object getDefaultRadioButtonValueHelper(IRadioButtonGroup<T> field) {
List<IRadioButton<T>> buttons = field.getButtons();
// Write the logic of original method here
}

List<IRadioButton<?>> buttons = new List<IRadioButton<?>>();
foreach(IRadioButton button in field.getButtons())
{
buttons.Add(button);
}

You could do:
protected <T> Object getDefaultRadioButtonValue(IRadioButtonGroup<T> field) {
List<IRadioButton<T>> buttons = field.getButtons();
return buttons;
}
or
protected Object getDefaultRadioButtonValue(IRadioButtonGroup<?> field) {
return field.getButtons();
}

Change:
protected Object getDefaultRadioButtonValue(IRadioButtonGroup<?> field) { List<IRadioButton<?>> buttons = field.getButtons();
to:
protected Object getDefaultRadioButtonValue(IRadioButtonGroup<IRadioButton<?>> field) {
List> buttons = field.getButtons();

Related

Generic method <?> Type Arguments

In a library for charts I found the following class:
public class SeriesBuilder<T> {
private T[] data;
private SeriesBuilder() {
}
public static SeriesBuilder<?> get() {
return new SeriesBuilder();
}
public SeriesBuilder<T> withData(T... data) {
this.data = data;
return this;
}
public Series<T> build() {
Series<T> series = new Series<T>();
series.setData(data);
return series;
}
}
Using code:
SeriesBuilder.get()
.withData(<<<<<???>>>>)
.build()
I'm not able to find out how to use the class because of the <?> Type. I can't find an argument that fullfills the signature. How to use this?
I'm not able to find out how to use the class because of the <?> Type. I can't find an argument that fullfills the signature. How to use this?
You pretty much can't use it. There is no way to obtain a SeriesBuilder instance except via SeriesBuilder.get(), and the type parameter of an instance that you obtain that way is unknown -- in fact, what get actually instantiates is the raw type. You should be able to produce a series of nulls if you wish.
There cannot even be any subclasses of SeriesBuilder (that might be more usable), because its only constructor is private.
Without putting too fine a point on it, this SeriesBuilder is pretty much an abomination. There is an argument to be made for preferring factory methods (such as SeriesBuilder.get()) over constructors, but that implementation is terrible. In addition to the type parameter issues, it does not initialize the resulting object to a valid state. That has to be done separately via withData(), so what is the point of get() supposed to be?
I'm inclined to think that whoever wrote that was looking for something that would have been better expressed via this variation on withData():
public static <T> SeriesBuilder<T> withData(T ... data) {
SeriesBuilder<T> builder = new SeriesBuilder<>();
builder.data = data;
return builder;
}
You might use that as
SomeType item1 = /* value */;
SomeType item2 = /* value */;
SomeType item3 = /* value */;
Series<SomeType> series =
SeriesBuilder.withData(item1, item2, item3)
.build();

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.

What datatype to use for return of Interface using generics?

With this interface:
interface SomeInterface<E> {
List<E> getList();
}
And this implementation:
private void someMethod(SomeInterface someImplementation) {
Object item = someImplementation.getList().get(0); // here
}
What would be the appropriate datatype to use? Just Object, as shown?
private <T> void someMethod(SomeInterface<T> someImplementation) {
T item = someImplementation.getList().get(0); // here
}
Object is fine too, as long as you don't need to do something like someImplementation.getList().add(item) later. The key to this example is that it avoids the use of a raw type, so that the compiler can ensure that you've written type-safe code.
An alternative way to avoid the use of raw types is to use a wildcard ? in the signature. If you did it that way the appropriate type for item would be Object:
private void someMethod(SomeInterface<?> someImplementation) {
Object item = someImplementation.getList().get(0);
}
The downside of doing it this way is that you cannot use the generic type E in the body of the method.

Java Generics: Type cast issue (ClassCastException)

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;
}

Java Storing Conditions By Generic Type

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<?>>

Categories