Properly cast generics - java

How can I cast Class<? extends Enum<?>> to Class<T>, where <T extends Enum<T>>? Specifically I need to pass an instance of Class<? extends Enum<?>> to the Enum.valueOf() method. http://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html#valueOf(java.lang.Class,%20java.lang.String)
Here are the classes I have:
enum Foo1 implements Bar {
VALUE1("A"), VALUE2("B");
String me;
Foo1(String me) {
this.me = me;
}
String getMe() {return me;}
}
enum Foo2 implements Bar {
V1("A"), V2("B");
String me;
Foo2(String me) {
this.me = me;
}
String getMe() {return me;}
}
interface Bar {
String getMe();
}
enum Z {
Z1(Foo1.class), Z2(Foo2.class);
private final Class<? extends Enum<? extends Bar>> myEnum;
Z(Class<? extends Enum<? extends Bar>> myEnum) {
this.myEnum = myEnum;
}
Class<? extends Enum<? extends Bar>> getMyEnum() {
return myEnum;
}
}
class X {
public getMe(Z z, String fooValue) {
Class<? extends Enum<? extends Bar>> fooEnum = z.getMyEnum();
// does not compile
return ((Bar)Enum.valueOf(fooEnum, fooValue)).getMe();
}
}

The easy way to do this is to cast to the raw type Class:
return ((Bar)Enum.valueOf((Class)fooEnum, fooValue)).getMe();
If you don't like casts you could wrap your enum classes in another class when you put them in Z to preserve more of their type relationship.
enum Z {
Z1(new Holder<>(Foo1.class)), Z2(new Holder<>(Foo2.class));
private final Holder<?> myEnum;
Z(Holder<?> myEnum) {
this.myEnum = myEnum;
}
Holder<?> getMyEnumHolder() {
return myEnum;
}
static class Holder<T extends Enum<T> & Bar> {
private final Class<T> myEnum;
private Holder(Class<T> myEnum) {
this.myEnum = myEnum;
}
Class<T> getMyEnum() {
return myEnum;
}
}
}
class X {
public static String getMe(Z z, String fooValue) {
return Enum.valueOf(z.getMyEnumHolder().getMyEnum(), fooValue).getMe();
}
}

Basically it is impossible to express the type relationship that you need to, given Java's current generic grammar constructs. So you can do something unchecked, or, if all you need is to do something like
String str = someX.getMe(Z1, "VALUE1");
then you can ditch enum and declare Z as a regular class that takes a parameter. This way you retain a complete type argument and can use it later.
public final class Z<E extends Enum<E> & Bar> {
public static final Z<Foo1> Z1 = new Z<>(Foo1.class);
public static final Z<Foo2> Z2 = new Z<>(Foo2.class);
private final Class<E> myEnumClass;
private Z(Class<E> myEnumClass) {
this.myEnumClass = myEnumClass;
}
public Class<E> getMyEnumClass() {
return myEnumClass;
}
/*
* recreate enum functionality if needed
*/
}
public <E extends Enum<E> & Bar> String getMe(Z<E> z, String fooValue) {
Class<E> fooEnumClass = z.getMyEnumClass();
return Enum.valueOf(fooEnumClass, fooValue).getMe();
}
Enum is not very flexible. There are things that it just can't do and it may not be appropriate.

Here's one way to do it
class X {
#SuppressWarnings("unchecked")
public <T extends Enum<T> & Bar> String getMe(Z z, String fooValue) {
Class<T> fooEnum = (Class<T>) z.getMyEnum();
return Enum.valueOf(fooEnum, fooValue).getMe();
}
}
Externally, the type parameter is useless. Internally, it lets us declare a type that is both a subtype of Enum and of Bar. The cast to Bar is also no longer necessary.

Related

How to return the Class of a generic type

I have this compilation problem:
Here is the class in question:
package huru.entity;
import io.vertx.core.json.JsonObject;
import java.util.Date;
public class BaseEntity <T extends BaseModel> extends JsonObject {
private T model;
public BaseEntity(T m){
this.model = m;
}
public void setUpdateInfo(String user){
this.model.updatedBy = user;
this.model.updatedAt = new Date();
}
public JsonObject toJsonObject(){
return JsonObject.mapFrom(this.model);
}
public T getEntityType (){
return this.model.getClass(); // doesn't compile
}
}
I also tried using
public T getEntityType (){
return T; // doesn't compile
}
but that clearly doesn't work either. Anybody know how I can return the class instance of that generic type?
I also tried this:
public Class<T> getEntityType (){
return this.model.getClass();
}
and I get:
and then I tried this:
public Class<? extends T> getEntityType (){
return this.model.getClass();
}
and I have:
You appear to be confused. You're returning the class that represents T, not a T.
Let's replace T with String and show why what you're doing makes no sense:
private String model;
public String getEntityType() {
return model.getClass();
// Of course this does not work; model.getClass() is not a string!
}
public String getEntityType() {
return String;
// This doesn't even compile.
}
To try to explain, this:
public T getEntityType() {
....
}
requires you to return an actual instance of whatever T is. Not whatever type T is representing. Just like 'String' means you should return an actual instance of String, not the concept of String, the type.
Perhaps you meant to do this:
public T getEntityType() {
return model;
}
or more likely, given that you named this method 'getEntityType', what you mean is this:
public Class<? extends T> getEntityType() {
return model.getClass();
}
Yes, ? extends T, because model is a T, or any subtype of T.
What about the following code. I think it works.
public Class<? extends BaseModel> getEntityType (){
return model.getClass();
}
class Foo<T> {
final Class<T> typeParameterClass;
public Foo(Class<T> typeParameterClass) {
this.typeParameterClass = typeParameterClass;
}
public void bar() {
// you can access the typeParameterClass here and do whatever you like
}
}
Part of the problem is that getClass is defined in Object to give you a Class< ? > with a wildcard as the generic parameter. If you want to return Class< ? extends T > you will need to cast to that:
return (Class< ? extends T >) (model.getClass());

Enum to return an instance of an interface using generics in Java?

I would like to have an enum to return an instance of an interface, using generics. I can't quite figure it out yet. I'm not exactly sure how to phrase my question. Below is the code that I am trying to get working. It won't compile because the enum wants the constructor to handle ImplementingClass explicity.
My interface
public interface MyInterface {
}
My implementing class
public class ImplementingClass implements MyInterface {
}
The enum I'm trying to get working
public enum MyEnum {
CASE1(“CODE1”, ImplementingClass.class);
private String code;
private Class<MyInterface> aClass;
private MyEnum(String code, Class<MyInterface> aClass) {
this.code = code;
this.aClass = aClass;
}
public String getCode() {
return this.code;
}
public MyInterface getInstance() {
return this.aClass.newInstance();
}
}
The problem is that a Class<MyInterface> can only be MyInterface.class, and not any implementing class such as ImplementingClass.class.
You can use a wildcard to create an upper bound on the declaration of aClass to take a Class object representing any class that implements MyInterface:
private Class<? extends MyInterface> aClass;
private MyEnum(String code, Class<? extends MyInterface> aClass) {
this.code = code;
this.aClass = aClass;
}
Some use of wildcards and casting do the magic:
public enum MyEnum {
CASE1("CODE1", (Class<? extends MyInterface>)ImplementingClass.class);
private String code;
private Class<? extends MyInterface> aClass;
private MyEnum(String code, Class<? extends MyInterface> aClass) {
this.code = code;
this.aClass = aClass;
}
//...
}

How do I return a class' enums from its own class in Java?

I want to enforce enum implementation in Java but I found out that I couldn't do it.
So I decided to define an abstract function that returns the enums of subclasses. But don't know how to do it.
Here is the code:
EnumInterface
public interface EnumInterface
{
public String getString();
}
ParentClass
public abstract class ParentClass {
public abstract Enum<?> getEnums();
}
ChildClass
public class ChildClass extends ParentClass{
public enum EnumImplementation implements EnumInterface
{
FOO("foo"),
BAR("bar");
String string;
EnumImplementation(String field)
{
this.string = string;
}
#Override
public String getString() {
return string;
}
}
#Override
public Enum<?> getEnums() {
return ?;
}
}
The code above doesn't work, I'm just trying to describe my problem.
I also want to enforce the enum return type to EnumInterface if possible.
If you know how to enforce specific enum implementation that would be better as I don't even have to define the function in ParentClass.
So, how do I return the enum so that I can just do this instanceOfParentClass.getEnums().FOO?
What about this:
public <T extends Enum<T> & EnumInterface> T[] getEnums() {
return (T[])EnumImplementation.values();
}
Note the cast, which might result in a ClassCastException.
To prevent this you could pass the enum class or just return an array of EnumInterface:
public <T extends Enum<T> & EnumInterface> T[] getEnums(Class<T> enumType)
public <T extends Enum<T> & EnumInterface> EnumInterface[] getEnums()
Note that this doesn't enable you to call the method like getEnums().FOO, but you could pass the class and the name, e.g.
public <T extends Enum<T> & EnumInterface> T[] getEnum(Class<T> enumType, String enumName) {
return Enum.valueOf( enumType, enumName);
}
However, just as Tim B said, there might be a better option for what you're trying to achieve.
Try this.
EnumInterface
public interface EnumInterface {
public String getString();
}
ParentClass
public abstract class ParentClass<ENUM_TYPE extends Enum<ENUM_TYPE> & EnumInterface> {
public abstract ENUM_TYPE getEnums();
}
ChildClass
public class ChildClass extends ParentClass<ChildClass.EnumImplementation> {
public static enum EnumImplementation implements EnumInterface {
FOO("foo"),
BAR("bar");
String string;
EnumImplementation(String field) {
this.string = field;
}
#Override
public String getString() {
return string;
}
}
public EnumImplementation getEnums() {
return EnumImplementation.values()[0];
}
public static void test() {
Object result = new ChildClass().getEnums().FOO;
}
}
Note that getEnums() returns an enum value. It's not possible to return the enum container itself, but you can call other enum values from any value (f.e. EnumImplementation.FOO.BAR.FOO)
In order to map property names to database field you can use the enum valueOf method.
You need to do the mapping in your class as you cannot pass a reference to the static enumeration:
http://www.tryjava8.com/app/snippets/52b86150e4b0f5090255bc45
import java.util.*;
public class Main{
static enum TestE {
FOO,
BAR
}
static class TestC {
TestE getEnum(String name) {
return TestE.valueOf(name);
}
}
public static void main(String[] args){
System.out.println(TestE.FOO);
System.out.println(new TestC().getEnum("BAR"));
}
}

method return type from a class variable

Given the following class:
...
Class<? extends Enum<?>> enumType;
public MyClass(Class<? extends Enum<?>> enumType) {
super();
this.enumType=enumType;
...
How do i define a method that returns an Enum of the "enumType" class?
I need something like:
public enumType getValue(){
...
}
,but this doesn't work ..
Use a type parameter instead of a wildcard. For example:
class MyClass<T extends Enum<T>> {
private Class<T> enumType;
public MyClass(Class<T> enumType) {
this.enumType = enumType;
}
public T getValue() {
// ...
}
}
edit In response to your comment, here's a method that lists all constants of an arbitrary enum:
public <E extends Enum<E>> void showEnumValues(Class<E> e) {
for (E value : e.getEnumConstants())
System.out.println(value);
}
}
You have to actually specify a variable inside your generic, not just use wildcards everywhere. Then it's just like this:
public class MyClass<E extends EnumType<E>> {
Class<E> enumType;
E value;
public MyClass(Class<E> enumType) {
this.enumType = enumType;
}
public E getValue() {
return value;
}
}

Using generics with collection of enum classes implementing same interface

I am trying to do reverse lookup on few enum classes implementing same Field interface by iterating through list of Classes using Guava's Maps.uniqueIndex:
Field valueOfSearchName = null;
for (final Class<? extends Enum<?>> clazz : ImmutableList.of(
EntityField.class,
AddressField.class,
PersonFunctionType.class)) {
valueOfSearchName = Fields.valueOfSearchName(clazz, term.field()); // error
if (valueOfSearchName != null) {
// do something...
break;
}
}
I don't want to repeat same code (for making index and doing lookup) in all enum classes, so I use helper static class Fields containing Fields.valueOfSearchName method:
public static <E extends Enum<E> & Field> Field valueOfSearchName(
final Class<E> clazz, final String searchName) {
// TODO: cache the index
final ImmutableMap<String, E> index = Maps.uniqueIndex(
EnumSet.allOf(clazz), GET_SEARCH_NAME_FUNCTION);
return index.get(searchName);
}
Unfortunately, Eclipse shows an error:
Bound mismatch:
The generic method valueOfSearchName(Class<E>, String) of type Fields is not
applicable for the arguments (Class<capture#1-of ? extends Enum<?>>, String).
The inferred type capture#1-of ? extends Enum<?> is not a valid substitute
for the bounded parameter <E extends Enum<E> & Field>
The problem is Class<? extends Enum<?>> clazz in for-each loop (not matching Field), but I don't know how to deal with this case (obviously I cannot add & Field to clazz).
Consider Class<? extends List<?>. Class<? extends List<?> has two wildcards whereas <E extends List<E>> Class<E> only has generic parameter. The former will admit Class<ArrayList<String>>. So without doing something extra special for enums, the types are not compatible.
How to fix? An extra layer of indirection!
public final class MetaEnum<E extends Enum<E>> {
private final E clazz;
public static <E extends Enum<E>> MetaEnum<E> of(E clazz) {
return clazz;
}
private MetaEnum(E clazz) {
this.clazz = clazz;
}
public E clazz() {
return clazz;
}
// ...
}
for (final MetaEnum<?> meta : ImmutableList.of(
MetaEnum.of(EntityField .class),
MetaEnum.of(AddressField .class),
MetaEnum.of(PersonFunctionType.class)
)) {
Field valueOfSearchName = Fields.valueOfSearchName(
meta.clazz(), term.field()
);
...
(Usual Stack Overflow dislaimer: Not so much as attempted to compile.)
Inspired by Tom Hawtin's answer I created wrapper class holding Classes, but only those with signature <E extends Enum<E> & Field>:
public final static class FieldEnumWrapper<E extends Enum<E> & Field> {
private final Class<E> clazz;
private final ImmutableMap<String, E> index;
public static <E extends Enum<E> & Field>
FieldEnumWrapper<E> of(final Class<E> clazz) {
return new FieldEnumWrapper<E>(clazz);
}
private FieldEnumWrapper(final Class<E> clazz) {
this.clazz = clazz;
this.index = Maps.uniqueIndex(
EnumSet.allOf(clazz), new Function<E, String>() {
#Override
public String apply(final E input) {
return input.searchName();
}
});
}
public Class<E> clazz() {
return clazz;
}
public Field valueOfSearchName(final String searchName) {
return index.get(searchName);
}
}
Now:
for (final FieldEnumWrapper<?> fieldEnum : ImmutableList.of(
FieldEnumWrapper.of(EntityField.class),
FieldEnumWrapper.of(AddressField.class),
FieldEnumWrapper.of(PersonFunctionType.class))) {
valueOfSearchName = fieldEnum.valueOfSearchName("POD_I_OS_PARTNER");
// ...
is type-safe and inappropriate usage of FieldEnumWrapper's static factory:
FieldEnumWrapper.of(NotEnumAndFieldClass.class)
generates compile error.
Moreover, valueOfSearchName is now method of FieldEnumWrapper what make more sense that helper class.
maybe something like this:
import java.util.*;
class N {
static int n;
}
interface HasField {
int getField();
}
enum Color implements HasField {
r, g, b;
public int getField() {
return field;
}
private int field = N.n++;
}
enum Day implements HasField {
m, t, w, th, f, sa, su;
public int getField() {
return field;
}
private int field = N.n++;
}
class Helper {
Helper(Set<HasField> set) {
for (HasField hasField : set)
if (hasField instanceof Enum) {
Enum<?> e = (Enum<?>) hasField;
for (Object o : e.getDeclaringClass().getEnumConstants()) {
map.put(((HasField) o).getField(), (Enum<?>) o);
}
} else
throw new RuntimeException(hasField + " is not an enum!");
}
final Map<Integer, Enum<?>> map = new TreeMap<Integer, Enum<?>>();
}
public class Main {
public static void main(String[] args) {
Set<HasField> set = new LinkedHashSet<HasField>();
set.add(Color.r);
set.add(Day.m);
Helper helper = new Helper(set);
for (int i = 0; i < N.n; i++)
System.out.println(i + " " + helper.map.get(i));
}
}

Categories

Resources