Jan Skrasek
04/15/2021, 2:47 PMClass<*>
to Class<Enum<*>>
and use if in Java function requiring public static <T extends Enum<T>> EnumJsonAdapter<T> create(Class<T> enumType) {
Should I do it somehow differently, or is it a bug?diesieben07
04/15/2021, 2:48 PMClass<Enum<Nothing>>
Jan Skrasek
04/15/2021, 2:51 PMval enumClass = rawType as Class<Enum<Nothing>>
EnumJsonAdapter.create(enumClass)
Victor Petukhov
04/15/2021, 2:52 PMEnum<*>
isn’t subtype of Enum<Enum<*>>
(you try to pass Class<Enum<*>>
into Java method with bound on T
Enum<T>
). You should introduce a type variable with the same bound:
fun <T: Enum<T>> foo(enumClass: Class<T>) {
EnumJsonAdapter.create(enumClass)
}
Victor Petukhov
04/15/2021, 2:53 PMJan Skrasek
04/15/2021, 2:57 PMJan Skrasek
04/15/2021, 3:01 PMVictor Petukhov
04/15/2021, 3:02 PMEnum<T>
type, where T
is bounded by Enum<T>
(as in the example I wrote about above).Jan Skrasek
04/15/2021, 3:06 PMClass<*>
and need to cast it to Class<Enum<*>>
. I do not have an option making the code generic. I'm ok with runtime error when the class is not a class of enum.Victor Petukhov
04/15/2021, 3:09 PMEnum<*>
) – make it use site covariant: try casting to Class<out Enum<*>>
.Jan Skrasek
04/15/2021, 3:21 PMclass Helper {
@SuppressWarnings("rawtypes")
public static <T extends Enum<T>> EnumJsonAdapter<T> createEnumJsonAdapter(Class<?> rawType) {
// noinspection unchecked
return EnumJsonAdapter.create((Class<? extends Enum>) rawType);
}
}
but that doesn't work either, since I am unable to tell what is the resulting generic type in Kotlin:Jan Skrasek
04/15/2021, 3:22 PMjw
04/15/2021, 3:32 PMdiesieben07
04/15/2021, 3:32 PMEnum<Nothing>
is valid, in 1.5 it is not.Victor Petukhov
04/15/2021, 3:34 PMSimply said it seems there is no way to type non generic Enum.It’s possible. Here the point is, what constraints are imposed on the declaration site of what you call (in your case, the call site does not comply with the constraints imposed on the declaration site). BTW out projection should work. Probably the problem is in something else. Look at three examples showing using enums including non-generic (out-projected):
fun <E: Enum<E>> foo(x: Class<E>) {}
fun <T: Enum<T>> main(x: Class<Enum<*>>, y: Class<out Enum<*>>, z: Class<T>) {
foo(x) // error because we pass Enum<*> as E but E has upper bound Enum<E> – Enum<*> doesn't have super type Enum<Enum<*>>
foo(y) // OK
foo(z) // OK
}
Zac Sweers
04/15/2021, 3:36 PMinternal object DefaultToUnknownEnumJsonAdapterFactory : JsonAdapter.Factory {
override fun create(type: Type, annotations: Set<Annotation>, moshi: Moshi): JsonAdapter<*>? {
if (annotations.isNotEmpty()) return null
val rawType = Types.getRawType(type)
if (!rawType.isEnum) return null
if (!rawType.isAnnotationPresent(JsonClass::class.java)) return null
@Suppress("UNCHECKED_CAST")
return createAdapter(rawType as Class<out Enum<*>>)
}
// Separate function in order to get generics to play nice
private fun <T : Enum<T>> createAdapter(clazz: Class<T>): JsonAdapter<T> {
val unknown = clazz.enumConstants[0]
check(unknown.name == "UNKNOWN") {
"@JsonClass-annotated enums must reserve their first member as 'UNKNOWN'"
}
return EnumJsonAdapter.create(clazz)
.withUnknownFallback(unknown)
.nullSafe()
}
}
Zac Sweers
04/15/2021, 3:36 PM