17

What does it mean to resolve a type in Java?

Here are some usage examples with my attempts at making sense of them:

From Field#getGenericType():

If the type of the underlying field is a type variable or a parameterized type, it is created. Otherwise, it is resolved.

  • Type variables or parameterized types need to be created for this form of reflection to work because they can't be loaded, because they don't really "exist" at runtime?
  • So if something exists at runtime, it can be "resolved"? By the classloader?

From TypeToken#resolveType():

Resolves the given type against the type context represented by this type. For example:

new TypeToken<List<String>>() {}.resolveType(
    List.class.getMethod("get", int.class).getGenericReturnType())
=> String.class
  • This I don't really get at all. Not sure what this code is doing.
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
Dmitry Minkovsky
  • 36,185
  • 26
  • 116
  • 160

1 Answers1

8

Regarding your first question, consider a field declaration like

public List<String> parameterizedField;

The JVM does not maintain an object representing the type List<String> (as it would a Class object). It therefore needs to create a new Type (ParameterizedType in this case) object representing that type and return it (it might also cache it for future use). It will do the same for

public E genericField;

creating a TypeVariable object in this case.

For

public String regularTypeField;

however, the type is known, the JVM maintains a Class object for String and therefore only needs to return that.


In the second case, the type token hack

new TypeToken<List<String>>() {}

internally creates a Type that represents List<String> which would otherwise not be possible to retrieve directly because of type erasure.

The resolveType call checks the Type you give it and resolves it based on the TypeToken's type argument.

In your example, the getGenericReturnType() invoked will return a Type representing the type variable declared in the List class. Since you've parameterized List with String, resolveType() will return String. It binds the type argument you provided in the type token to its corresponding type variable used in methods or fields.

Had you used

new TypeToken<List<String>>() {}.
    resolveType(Iterator.class.getMethod("next").getGenericReturnType())

it would have returned E because that type variable is unrelated to the one you bound in the type token.


The uses of resolved in both cases is different.

Dmitry Minkovsky
  • 36,185
  • 26
  • 116
  • 160
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • Thank you Sotirios. Still: "The `resolveType` call checks the `Type` you give it and resolves it based on the `TypeToken`'s type argument." What does this mean? I understand the constituent components you are referring to, but I don't understand this "resolving" – Dmitry Minkovsky Jul 28 '15 at 20:33
  • For example, I am aware of some concepts like resolving relative paths in a filesystem or URL. Say https://nodejs.org/api/url.html#url_url_resolve_from_to – Dmitry Minkovsky Jul 28 '15 at 20:35
  • 2
    @dimadima To _resolve_ simply means to **determine**. Take [`Path#resolve(Path)`](http://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html#resolve-java.nio.file.Path-) for example. Take a path `p1 = /home/ex` and another `p2 = some/other`, resolving `p2` based on `p1`, or `p1.resolve(p2)` would give `/home/ex/some/other`. It's simply giving context to one value in order to determine another value. – Sotirios Delimanolis Jul 28 '15 at 20:54
  • @dimadima For the `Type`, the context is the `TypeToken` and the type argument you provided. With `resolveType` you provide uses where the corresponding type argument would be bound. – Sotirios Delimanolis Jul 28 '15 at 20:54
  • Say you're are using an `Iterator` and wanted to know what return type its method `next()` would have (which you obviously can't know directly), you'd resolve `next` against the `TypeToken` representing `Iterator`. In that context, `next` would have a return type of `Integer`. – Sotirios Delimanolis Jul 28 '15 at 20:58
  • I see. So you're saying if I have an `Iterator> it = getIterator()` at runtime. I do `TypeToken.of(it.getClass()).resolveType(Iterator.class.getMethod("next").getGenericReturnType())` and it reveals the `?`; or, if they are orthogonal, returns `E`? I read through a bit of https://github.com/google/guava/blob/v16.0/guava/src/com/google/common/reflect/TypeToken.java and some of the tests the other day, but didn't get to this resolution thing. – Dmitry Minkovsky Jul 28 '15 at 21:10
  • The thing I don't get about reflection is that it's not statically checked, it seems like you can't do much with it. Yet, I know from reading docs etc that it's used all over the place all the time. Do you know any good resources/codebases for me too look at that show exemplary or canonical uses of reflection? This Guava package has given me some introduction but isn't focused on teaching the ins and outs. – Dmitry Minkovsky Jul 28 '15 at 21:13
  • @dimadima Not in that case. `it.getClass()` will not have the type information. It'll simply return the `Class` object for `Iterator`. The [type token hack](http://gafter.blogspot.com/2006/12/super-type-tokens.html) works based on the anonymous class declaration which contains the type argument information at runtime. – Sotirios Delimanolis Jul 28 '15 at 21:20
  • Oooof reflection is a huge topic, I've read code here and there (and the corresponding javadoc). I don't have anything specific. Spring (even Guice) makes use of reflection extensively, maybe that. Anything that uses annotations (Spring AOP). – Sotirios Delimanolis Jul 28 '15 at 21:23
  • [I've explained the type token hack in other posts, if you're interested.](http://stackoverflow.com/questions/27234928/guava-typetoken-isnt-able-to-resolve-generic-parameter) – Sotirios Delimanolis Jul 28 '15 at 21:24
  • Yeah I realized that was incorrect after I posted it. I meant like `class IntIterator extends Iterator`, and then `it.getClass()` of such an iterator with the type argument not erased. – Dmitry Minkovsky Jul 28 '15 at 21:26
  • @dimadima In that case, yes, the information would exist, the same way as if you had done `new TypeToken> (){}`. – Sotirios Delimanolis Jul 28 '15 at 21:27
  • Thank you! I have a whole list of these things I've read recently. Will read that one too. – Dmitry Minkovsky Jul 28 '15 at 21:27
  • Found some classics like this the other day http://www.artima.com/weblogs/viewpost.jsp?thread=208860. Anyway, Stack Overflow is not happy about this "extended discussion". Thank you again. – Dmitry Minkovsky Jul 28 '15 at 21:28
  • @dimadima I will emphasize that knowing the [`Type`](http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Type.html) class hierarchy helps a lot. – Sotirios Delimanolis Jul 28 '15 at 21:30
  • I was just looking at this https://github.com/google/guava/blob/v16.0/guava/src/com/google/common/reflect/TypeVisitor.java, which seems to sum it up nicely? – Dmitry Minkovsky Jul 28 '15 at 21:34
  • @dimadima If you find the relevant implementations too :). Also look at Jackson and similar serialization frameworks. Those also use reflection extensively, **resolving** nested object trees based on generic types where available. – Sotirios Delimanolis Jul 28 '15 at 21:35
  • @dimadima - if you need "extended discussion", you are welcome to do it on https://groups.google.com/forum/#!forum/java-lang-fans :) – ZhongYu Jul 28 '15 at 22:51