简体   繁体   中英

Type inference discrepancy between Eclipse Java compiler and OpenJDK compiler (Java 8)

I'm doing some meta programming where I'm parsing JAXB beans, particularly XmlAdapter annotations. I arrived at a situation where the compiler of Eclipse Oxygen (4.7.2) is fully content with some methods that use type inference, but the OpenJDK compiler (javac 1.8.0_131) chokes on them.

I've extracted the principal structure into this MWE:

import java.time.LocalDate;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class Main<BoundType>
{
   public void parse( Class<? extends XmlAdapter<?, BoundType>> adapterClass ) throws Exception
   {
      process( adapterClass );
   }

   private <ValueType> void process( Class<? extends XmlAdapter<ValueType, BoundType>> adapterClass ) throws Exception
   {
      // Do something with adapterClass ...
   }

   private static final class SomeAdapter extends XmlAdapter<String, LocalDate>
   {
      @Override
      public LocalDate unmarshal( String v ) throws Exception
      {
         return v == null ? null : LocalDate.parse( v );
      }

      @Override
      public String marshal( LocalDate v ) throws Exception
      {
         return v == null ? null : v.toString();
      }
   }

   public static void main( String[] args ) throws Exception
   {
      Main<LocalDate> main = new Main<>();

      main.parse( SomeAdapter.class );
   }
}

The OpenJDK compiler produces this error:

/[...]/WildcardProblem/src/Main.java:21: error: method process in class Main<BoundType> cannot be applied to given types;
      process( adapterClass );
      ^
  required: Class<? extends XmlAdapter<ValueType,BoundType>>
  found: Class<CAP#1>
  reason: cannot infer type-variable(s) ValueType
    (argument mismatch; Class<CAP#1> cannot be converted to Class<? extends XmlAdapter<ValueType,BoundType>>)
  where ValueType,BoundType are type-variables:
    ValueType extends Object declared in method <ValueType>process(Class<? extends XmlAdapter<ValueType,BoundType>>)
    BoundType extends Object declared in class Main
  where CAP#1 is a fresh type-variable:
    CAP#1 extends XmlAdapter<?,BoundType> from capture of ? extends XmlAdapter<?,BoundType>

I can work around the compiler error by modifying method process like this:

   private <ValueType> void process( Class<? extends XmlAdapter<?, BoundType>> adapterClass ) throws Exception
   {
      @SuppressWarnings( "unchecked" )
      Class<? extends XmlAdapter<ValueType, BoundType>> capturedAdapterClass = (Class<? extends XmlAdapter<ValueType, BoundType>>) adapterClass;

      // Do something with adapterClass ...
   }

But of course, the unchecked cast is ugly. I believe that it should be safe though because the type parameter ValueType is introduced arbitrarily here only to capture the wildcard. I just need it further down in my processing where I instantiate an XmlAdapter and call unmarshal on it. At runtime, no exceptions occur.

So my questions are, first of all, is the original code supposed to compile, and second, would this be an Eclipse compiler or an OpenJDK compiler bug?

Not a bug. You are playing with nested generics here.

Class<? extends XmlAdapter<?, BoundType>> Class<? extends XmlAdapter<?, BoundType>> is not the same as Class<? extends XmlAdapter<ValueType, BoundType>> Class<? extends XmlAdapter<ValueType, BoundType>> .

You must change the method signature to:

public <ValueType> void parse( Class<? extends XmlAdapter<ValueType, BoundType>> adapterClass )

or cast as you did before.


Simpler example:

public void parse2(List<? extends Optional<?>> optionals) {
    process2(optionals); // compilation error
}

public <T> void process2(List<? extends Optional<T>> optionals) {

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM