Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 438469

Summary: [null] How-to use null type annotations with generic methods from interfaces in some library you only have as binary JAR?
Product: [Eclipse Project] JDT Reporter: Michael Vorburger <mike>
Component: CoreAssignee: Stephan Herrmann <stephan.herrmann>
Status: VERIFIED DUPLICATE QA Contact:
Severity: normal    
Priority: P3 CC: manoj.palat, stephan.herrmann
Version: 4.4   
Target Milestone: 4.5 M1   
Hardware: PC   
OS: Linux   
Whiteboard:

Description Michael Vorburger CLA 2014-06-28 19:35:12 EDT
// Imagine this is in some library you only have as binary JAR (cannot modify src)
interface ITest {
	<T> T foo(T arg); // or arg Class<T> or TypeToken<T> + return TypeAdapter<T>, etc.
}

// This however is your code (src), in a project with null type annotations 
class Test implements ITest {
	@Override
	public <T> T foo(T arg) {
		return null;
	}
}

leads to "Null type mismatch (type annotations): 'null' is not compatible to the free type variable 'T'".  In this case you cannot use @Nullable in Test's foo(), because that would lead to "The method @Nullable T foo(T) from Test cannot implement the corresponding method from ITest due to incompatible nullness constraints"... assuming one cannot change ITest, how do you solve this? 

I have read http://help.eclipse.org/luna/index.jsp?topic=%2Forg.eclipse.jdt.doc.user%2Ftasks%2Ftask-using_null_type_annotations.htm and (roughly..) understand what's going on here technically. The point of the issue is to raise that, unless there is a trick that I'm missing, it's effectively not (yet, pending bug 331651 ?) possible to enable use of null type annotations in projects with code that overrides generic methods from interfaces in some library you only have as binary JAR?

If my understanding is correct, this problem is particular to generic methods, because in the following slightly different example, note that here the interface not the method is generic-ified, you're OK:

// This is in some library you only have as binary JAR
public interface ITest2<T> {
	/* NOT <T> */ T foo(T arg); // or arg Class<T> or TypeToken<T> + return TypeAdapter<T>, etc.
}

// This works - no worries:
public class Test2<@Nullable T> implements ITest2<T> {
	@Override
	public T foo(T arg) {
		return null;
	}
}
Comment 1 Stephan Herrmann CLA 2014-07-05 08:54:50 EDT
From a quick glance I see a chance that bug 438458 can help, hence marking as a bug dependency
Comment 2 Stephan Herrmann CLA 2014-07-22 04:29:16 EDT
After playing with this all I can say is: your analysis is correct, this is a problem specific to generic methods that return a value of the parameter type.

By declaring 

   <T> T foo(T arg);

this API promises: for whatever type you choose for T, foo will return a value of that type. T is not constrained in any way, so this includes the option to choose a @NonNull type for T.

Clients may expect things like this to work:

   void test(ITest i) {
      @NonNull String s = i.foo("OK");
   }

Any implementation that returns null is not compatible to that contract.

In the case of a generic interface, the implementor can modify the contract by constraining the type parameter. Such a means does not exist for generic methods.

Sorry to say: all we can do is to address bug 331651, so you can mark in ITest that null return is legal. Otherwise the contract must be fulfilled by avoiding null returns.


BTW: I'd like to encourage you to reverse your thinking about null: in Java null is always legal and we are trying to restrict this by whatever means. Going forward I believe you're better off by considering null as generally illegal - UNLESS you have specific license by way of an explicit @Nullable annotation. In that light not being allowed to return null is the rule, not a bug.


Still one tiny change that I'm planning to make: ensure that @SuppressWarnings("null") can be used to suppress this problem. You'd need to either:
- enable "[x] Suppress optional errors with '@SuppressWarnings'", or
- downgrade "Violation of null specification" to warning (not recommended)

In either case, use with caution! :)
Comment 3 Stephan Herrmann CLA 2014-07-22 12:03:44 EDT
As of http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=61133b8c5e6da454f7cea747a5c83744e4b067c9 the problem in this bug can now be suppressed using @SuppressWarnings("null").

That's all we can do here.
Comment 4 Stephan Herrmann CLA 2014-07-31 04:53:40 EDT
Changing bug dependency to duplication, because no additional change was made for this bug.

*** This bug has been marked as a duplicate of bug 438467 ***
Comment 5 Manoj N Palat CLA 2014-08-05 23:48:17 EDT
Verified duplicate in Eclipse Mars 4.5 M1 Build id: I20140804-2000