Reputation: 1594
I am currently trying to translate a small application from java to kotlin without having to rewrite everything, however i am facing problems with a generic enum, since kotlin doesn't support generics in enums.
I have the following enum in java:
public enum Property {
LAST_VIEW(0, 1, Integer.class),
MAXIMIZED(2, false, Boolean.class),
private final int id;
private final String defaultValue;
private final Class<?> datatype;
<T> Property(final int id, final T defaultValue, final Class<T> datatype) {
this.id = id;
this.defaultValue = defaultValue == null ? null : defaultValue.toString();
this.datatype = datatype;
}
}
I am using this for a generic properties api in order to verify that my default values have the correct type and also do some runtime checks in order to give proper feedback as soon as i am making a mistake.
Is there anyways to make such a class in kotlin or should i consider refactoring my properties api instead?
Upvotes: 1
Views: 1430
Reputation: 148189
While Kotlin does not allow constructors to have their own type parameters, this feature in Java only affects type checking of the constructor arguments at call sites (the enum entries don't retain the type safety). So it's possible to achieve similar behavior in Kotlin by declaring a helper generic class and accepting its instance in a secondary constructor:
class TypedDefaultValue<T>(
val defaultValue: T,
val datatype: Class<T>
)
enum class Property(
val id: Int,
val defaultValue: Any,
val datatype: Class<out Any>
) {
LAST_VIEW(0, TypedDefaultValue(1, Int::class.java)), // calls the constructor below
MAXIMIZED(2, TypedDefaultValue(false, Boolean::class.java));
constructor(id: Int, typedDefaultValue: TypedDefaultValue<out Any>) :
this(id, typedDefaultValue.defaultValue, typedDefaultValue.datatype)
}
Use Any?
and out Any?
in the enum code to accept nullable values as well.
Upvotes: 1
Reputation: 31720
Perhaps you could consider sealed classes for this, rather than an enum?
sealed class Property<T>(val id: Int, val defaultValue: T, dataType: Class<T>)
object LastView : Property<Int>(0, 1, Int::class.java)
object Maximised : Property<Boolean>(2, false, Boolean::class.java)
In this case because LastView
and Maximized
don't have any user-defined or mutable state, I've defined them as objects
. And because Property<T>
is sealed, no other instances can be created.
Upvotes: 3