typetools icon indicating copy to clipboard operation
typetools copied to clipboard

TypeResolver.resolveRawArgument returns java.lang.Object instead of actual type ?

Open pderop opened this issue 10 years ago • 6 comments

Hi;

I'm having (for example) the following interface:

public static class Printer<T> {
    public void print(T t) {
        ...
    }
}

Now, let's define a method reference on the "print" method, and using an instance of the Printer class:

Printer<String> printer = new Printer<>();
Consumer<String> print = printer::println;
Class<?> type = TypeResolver.resolveRawArgument(Consumer.class, print.getClass());
System.out.println(type); // prints "java.lang.Object" instead of "Printer" ?

so, above, I would expect to get a Printer type instead of Object ?

Notice that the following similar example is working fine:

Consumer<String> print = System.out::println;
type = TypeResolver.resolveRawArgument(Consumer.class, print.getClass());
System.out.println(type); // "java.lang.String"

Am I missing something ?

thanks in advance; /Pierre

pderop avatar Dec 03 '15 11:12 pderop

I forgot to say that I'm using the following java version:

java -version

java version "1.8.0_66" Java(TM) SE Runtime Environment (build 1.8.0_66-b17) Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)

pderop avatar Dec 03 '15 12:12 pderop

errata, (oops sorry):

for the following example:

Printer<String> printer = new Printer<>();
Consumer<String> print = printer::println;
Class<?> type = TypeResolver.resolveRawArgument(Consumer.class, print.getClass());
System.out.println(type);

I would expect the type to be "java.lang.String" instead of "Java.lang.Object".

thanks /Pierre

pderop avatar Dec 03 '15 12:12 pderop

This seems to be similar to my #16?

I would explain this here that the object printer is taken as first parameter into the new created lambda expression printer::println as local variable. Then the TypeResolver finds the class both Printer and String share, which is Object. Could this theory be true?

mickare avatar Jan 07 '16 15:01 mickare

The short answer is that this use case does not appear to be supported by the technique we're using to resolve lambda type information. The reason is, with:

Printer<String> printer = new Printer<>();
Consumer<String> print = printer::println;

The argument for println is defined as String on the Printer<String> variable declaration. At runtime though, variable declarations are erased, so this just becomes Printer and the String is lost. It is similar to:

Consumer<String> print = System.out::println;

The difference is here the value of T is explicitly defined on the System.out.println method definition as a String rather than as T.

jhalterman avatar Mar 30 '16 05:03 jhalterman

Hi,

I am facing this issue.

Consumer<Integer> c = System.out::println ; // not working it returns Object instead of Integer

work around is

Consumer<Integer> c = (Integer x) -> System.out.println(x);

yaitskov avatar May 24 '17 10:05 yaitskov

Hi @yaitskov,

What's interesting about your scenario is that this works:

Consumer<String> print = System.out::println;

But this doesn't:

Consumer<Integer> print = System.out::println;

For whatever reason the ConstantPool, which is where we read lambda/method ref type information, encodes the latter scenario as println(Object o). It might be hard for us to recognize that in this scenario Object should actually be String since we're converting from another type. Perhaps we can detect that, but will need some further investigation.

jhalterman avatar May 25 '17 23:05 jhalterman