-
Notifications
You must be signed in to change notification settings - Fork 10.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make method TypeToken.toGenericType() public #1645
Comments
Original comment posted by lowasser@google.com on 2014-01-24 at 10:09 PM (No comment entered for this change.) Labels: |
Original comment posted by archie.cobbs on 2014-01-24 at 10:15 PM Snooping through the code, it looks like such a method as suggested at the end of comment #1 already exists:
Any reason this method can't be made public? |
Original comment posted by archie.cobbs on 2014-01-27 at 04:46 PM Just to clarify things a bit here, as this issue has evolved and the issue title is no longer accurate. The original request for a String parser is no longer needed... I can do that part myself, but need TypeToken.toGenericType() to made public in order for it to be feasible. So instead what is being requested here is simply that TypeToken.toGenericType() be made public. This method provides useful functionality that is not available anywhere else; and you can consider the original string parsing question as a motivating example (i.e., how could you implement string parsing without it?). |
Original comment posted by archie.cobbs on 2014-02-22 at 09:29 PM Please change the title of this feature request to: Make method TypeToken.toGenericType() public Thanks. |
Original comment posted by cpovirk@google.com on 2014-02-25 at 04:54 PM (No comment entered for this change.) |
Original comment posted by benyu@google.com on 2014-06-25 at 08:57 PM Exposing toGenericType() sounds reasonable. Although can you show us how it's going to be used in this use case? I wonder if it can be done with existing utilities such as where(), getSupertype(), getSubtype() etc. |
Original comment posted by archie.cobbs on 2014-06-26 at 12:11 AM As mentioned above, the original motivating example is a TypeToken parser (converts String -> TypeToken). I tried to implement one using all available public API's but it seemed impossible. The root problem is that e.g. TypeToken.of(List.class) returns "java.util.List", not "java.util.List<E>". Because of this, there's no way to take an arbitrary Class object representing a parameterized type, create a corresponding TypeToken, and then set the type parameters for the TypeToken. However, if TypeToken.toGenericType() is available then that makes it easy. You can see the current implementation of the parser here: Currently it uses reflection to access Types.newParameterizedType() directly (note, it invokes Types.newParameterizedType() instead of TypeToken.toGenericType() because the parser doesn't handle arrays). I could be completely missing something... if so, I'd be interested to see how you'd rewrite TypeTokenParser.java using only existing public API's. Thanks. |
Original comment posted by benyu@google.com on 2014-06-27 at 01:26 AM I know the dependency is kinda weird. But ignore that for a moment, if you had Guice's Types.newParamterizedType(), would you still have needed toGenericType()? Were you trying to use toGenericType() to implement newParameterizedType()? Although it doesn't seem easy to do though? For example, when parsing "List<String>", after calling List.class.toGenericType(), you have TypeToken<List<E>>, but there isn't any easy way to turn that into List<String> unless you use reflection to get the type variable <E> and do substitution using TypeResolver. |
Original comment posted by benyu@google.com on 2014-06-27 at 01:48 AM Oh. I guess you sort of implied it's what you are going to do: use clazz.getTypeParameters() to get the type vars and use TypeResolver to substitute. So never mind my previous question then. It still seems like newParameterizedType() is what's really needed. It was asked before that newParameterizedType() be exposed. That Guice already has it was one of the reasons we haven't done that, yet. |
Original comment posted by archie.cobbs on 2014-06-27 at 02:21 AM Exposing newParameterizedType() would work. I don't currently use Guice, so that option would be inconvenient. Seems like guava should have it's own version for completeness' sake, though that's a matter of opinion I suppose. Thanks. |
Original comment posted by benyu@google.com on 2014-06-27 at 02:40 AM Okay. Whether it's possible to use Guice was what I was curious to know. I think you have a perfectly reasonable use case here. I'm torn between the two options:
Or, maybe even more directly:
Hmm... Status: |
Regarding "Just offer a TypeToken parser", that's too limited a solution. The functionality provided by For example, I came across another use case whereby I needed a method that would "wildcardify" any raw type. For example, for some class The easiest (only?) way to do this was to call |
Technically, a type token parser can still work, right?
|
Yep, that's right... didn't think of that.. though that's a little messier, especially when the number of generic type parameters can vary. FWIW here's what I'm currently doing... private static final WildcardType QUESTION_MARK = new WildcardType() {
@Override
public Type[] getUpperBounds() {
return new Type[] { Object.class };
}
@Override
public Type[] getLowerBounds() {
return new Type[0];
}
@Override
public String toString() {
return "?";
}
};
...
/**
* Parameterize the raw type with wildcards.
*/
public static <T> TypeToken<? extends T> getWildcardedType(Class<T> type) {
if (type == null)
throw new IllegalArgumentException("null type");
final TypeVariable<Class<T>>[] typeVariables = type.getTypeParameters();
if (typeVariables.length == 0)
return TypeToken.of(type);
final WildcardType[] questionMarks = new WildcardType[typeVariables.length];
Arrays.fill(questionMarks, QUESTION_MARK);
return Util.newParameterizedType(type, questionMarks);
} However I still would rather see the more general functionality exposed. There are sure to be other use cases that could benefit besides the ones I've come across. |
It's better if you don't have to manually implement WildcardType or any of these Type impls. Your WildcardType impl wouldn't be equal to the JDK built-in wildcards when you get them through reflection like And then, getUpperBounds() isn't necessarily Object.class. Even if it's "?" literally. If The use case you mentioned above seems to call for a different utility: Of course, if there is
If we offer TypeToken.parse(), we should make sure we get the upper/lower bounds right. |
Yes I agree my current solution is a hack... right now there's no other (easy) way to do it. This is of course more evidence that there are functionality holes remaining to be filled. Thanks. |
Agreed. Based on earlier use cases in this thread and the one you just brought up, I'm more convinced that a In contrast, either
Compared to providing 5 extra API methods (newParameterizedType, newWildcardType, supertypeOf, subtypeOf, newTypeVariable) that are somewhat hard to use, a simple parse() method is also simpler from API perspective. I'll run this idea internally by others and see if I can convince enough people. If anything, I suspect a question could come up as "what is the user really trying to do through creating the wildcard type?". If you could provide some more information behind this use case, that might help. Thanks! |
My current use case requiring As described above, for reasons I don't fully understand So as a workaround, I'm adding the "wildcarded" type to the list manually. In any case, the whole wildcard thing is a digression. The larger issues is that it seems like there should be a programmatic way to take a raw As a side note, a parsing method would be nice to have for it's own reasons. E.g. it would make it easy to serialize a |
By getTypes() not including wildcard types, do you mean this?
? I believe About exposing the public methods that already sit there, the concerns have been:
Good point about the serialization/deserialization of TypeToken. Thanks! |
I mean the output of: import com.google.common.reflect.TypeToken;
public class xx {
public static void main(String[] args) throws Exception {
System.out.println(TypeToken.of(java.util.List.class).getTypes());
}
} is
which does not include Thinking about this more I realize now that Here's a little more background: the code I'm working with is attempting to track types using |
Here's a tiny TypeParser, and Types It lacks type bounds checking, but delegates to Guava for the Type implementations. |
Just wanted to add that a I also happen to think that the API should also provide a public |
Just wanted to add that public If the Alternatives to throwing in Guice into the projects are using Apache |
PING. 2.5+ years and still waiting for To summarize: there are legitimate situations where we need to convert a raw class (represented by a This is exactly what It's there. It's useful. Let's do this!! |
Wow, this bug is so old I almost forgot about it... coming up on 8 years. They grow up so fast... Would be funny if it weren't so sad... |
Oops, I missed this bug's tenth birthday back in January. HAPPY TENTH BIRTHDAY!! So close, and yet so far... diff --git a/guava/src/com/google/common/reflect/Types.java b/guava/src/com/google/common/reflect/Types.java
index 0b54e6a..3c06d13 100644
--- a/guava/src/com/google/common/reflect/Types.java
+++ b/guava/src/com/google/common/reflect/Types.java
@@ -91,7 +91,7 @@ final class Types {
}
/** Returns a type where {@code rawType} is parameterized by {@code arguments}. */
- static ParameterizedType newParameterizedType(Class<?> rawType, Type... arguments) {
+ public static ParameterizedType newParameterizedType(Class<?> rawType, Type... arguments) {
return new ParameterizedTypeImpl(
ClassOwnership.JVM_BEHAVIOR.getOwnerType(rawType), rawType, arguments);
} |
Original issue created by archie.cobbs on 2014-01-24 at 09:56 PM
I don't know if this is even possible, but it seems like it should be...
I'd like the ability to take the output of TypeToken.toString() and parse it back into the equivalent TypeToken.
For example, one should be able to say:
foo = TypeToken.parse("java.util.List<java.lang.String>");
and have foo equal to new TypeToken<List<String>>() {}.
NOTE 1: it seems reasonable to have the restriction that no type variables are allowed (would it even make sense to allow them? If you did you'd have to have some way of deciding whether "T" was a type variable or a class name).
NOTE 2: a ClassLoader should probably be a parameter to the parse method
I tried to implement this myself but it seems impossible without using package/private methods or generating bytecode (if it's possible to implement this idea using the standard public TypeToken API, please advise on how it would be done).
For example, this doesn't work:
prints:
instead of:
Also can't use TypeToken.of(List.class).getTypes(), which returns:
instead of:
The special case for the first item in the list seems odd (is the raw "List" type really a sub-type of Iterable<E>?)
What seems to be stopping this is the ability to convert a raw class into its parameterized Type or TypeToken. E.g., wish there was a method like this:
That is, this feature request could be answered by adding a new method that does the equivalent, e.g.:
So that e.g. TypeToken.of(List.class).getGenericType() -> List<E>
I'm guessing all of this is impossible for some reason I don't understand or it would already be there....
Thanks.
The text was updated successfully, but these errors were encountered: