views:

121

answers:

3

Hello,

Sometimes, when using Java reflection or some special storing operation into Object, you end up with unchecked warnings. I got used to it and when I can't do anything about it, I document why one call is unchecked and why it should be considered as safe.

But, for the first time, I've got an error about a unchecked call. This function :

public <K,V extends SomeClass & SomeOtherClass<K>> void doSomethingWithSomeMap (Map<K,V> map, V data);

I thought that calling it this way :

Map someMap = ...;
SomeClass someData = ...;
doSomethingWithSomeMap(someMap, someData);

would give me an unchecked call warning. Jikes does a warning, but javac gives me an error :

Error: <K,V>doSomethingWithSomeMap(java.util.Map<K,V>,V) in SomeClass cannot be applied to (java.util.Map,SomeClass)

Any way to force it to compile with a warning?

Thanks.

A: 

Try to specify it explicitely:

//Type2 is subclass of (or implements) SomeClass
Map<Type1, Type2> someMap = ...;
SomeClass someData = ...;
<Type1, Type2>doSomethingWithSomeMap(someMap, someData);
Roman
François Cassistat
I would recommend you to simplify this method. In two weeks (or two months in the best case) you'll forget what all that type parameters mean and how to use it. All other developers don't understand it already.
Roman
Actually, in its context, it is simpler, it only validate that you are using the right type of content with the right type of map. The way I am using it right now from a reflection-based algorithm is an exception case. Thank you for suggestion.
François Cassistat
A: 

You specify the second bound for V to extend SomeOtherClass. But I assume SomeClass does not implement SomeOtherClass (if it did, you wouldn't need multiple bounds). So someData does not conform to this bound, and hence compiler error. The variable someData needs to belong to a class which both extends SomeClass and implements SomeOtherClass.

Yardena
Yes, this is exactly the problem. Since I use reflection in an algorithm, I can assume that what I am doing is safe and add all necessary assertions, but I am unable to convince the compiler that it is safe. What is bugging me is that, it does not seems possible to do some unsafe cast operations go on with an unsafe call warning with javac even if it does not change anything at runtime...
François Cassistat
Yardena
+1  A: 

In what voodoo have you got yourself into :) ? From the question and comments I assumed that you are sure that you have objects that extend abstract class SomeClass and also implement interface SomeOtherClass. If this is the case I suggest an intermediate abstract class in the hierarchy that share these properties.

public abstract class Foo<K> extends SomeClass implements SomeOtherClass<K> {
  ...
}

That way you could simplify the static method signature to:

public <K,V extends Foo<K>> void doSomethingWithSomeMap (Map<K,V> map, V data);

If you do not want to change your current object hierarchy you can fool the compiler using another level of indirection with the adapter pattern.

"All problems in computer science can be solved by another level of indirection." -- David Wheeler

public abstract class SomeClass {    
  public abstract void method1();
}

public interface SomeOtherClass<K> {
  void method2(K value);
}

public class MyClass extends SomeClass implements SomeOtherClass<Integer> {
  @Override
  public void method1() {
    System.out.println("MyClass.method1");
  }

  @Override
  public void method2(Integer value) {
    System.out.println("MyClass.method2(" + value + ")");
  }
}

public class Indirection<K> extends SomeClass implements SomeOtherClass<K> {
  private final Object objectValue;

  public Indirection(final Object value) {
    this.objectValue = value;
  }

  @Override
  public void method1() {
    ((SomeClass) objectValue).method1();
  }

  @Override
  public void method2(K value) {
    @SuppressWarnings("unchecked")
    SomeOtherClass<K> delegate = ((SomeOtherClass<K>) objectValue);

    delegate.method2(value);
  }
}

public static void main(String[] args) {
  Map someMap = new HashMap<Integer, MyClass>();
  SomeClass someData = new MyClass();
  Indirection a = new Indirection(someData);
  doSomethingWithSomeMap(someMap, a, 12);
}

public static <K,V extends SomeClass & SomeOtherClass<K>>
void doSomethingWithSomeMap (Map<K,V> map, V data, K value) {
  data.method1();
  data.method2(value);
}

This would print:

MyClass.method1
MyClass.method2(12)

smink
Hmm, this is the best solution so far. But, it won't work in all case when there is polymorphism on class SomeClass where superclasses does not implements SomeOtherClass which is my case.You gave me an idea for another solution, all SomeClass could implements SomeOtherClass with the default implementation throwing a NotImplementedException, but I don't like the solution since it cannot check at runtime if you are using the function right.I'll think I stick with my first idea to do a safe and a unsafe version of doSomethingWithSomeMap. Thanks.
François Cassistat