简体   繁体   中英

Simplest way to cast a Class<T> to a Class<E extends Enum<E>> without losing type information

I have a method createFoo() that creates instances of Foo<T> using the Class<T> instance for that T . Now I want to extend that method to forward calls that are made using an enum type to the method createEnumFoo() . Calling the second method from the first one seems to be non-trivial. Below is an example of how I managed to do it using two unchecked casts and an extra method, all of which I would like to get rid of.

The method castEnumType() is required because I couldn't find a way to cast a Class<?> to a Class<E extends Enum<E>> without having the E bound somewhere. This involves an unchecked cast because I have not found a way to do it using Class.asSubclass() . After creating the instance of Foo , I need to cast it from Foo<E> to Foo<T> event though E and T will always be the same types.

I can't weaken the signature of createEnumFoo() because it is calling Enum.valueOf(enumType, ...) and requires the result of this to be of type E .

final class Example {
    <E extends Enum<E>> Foo<E> createEnumFoo(Class<E> enumType) {
        // This makes use of e.g. Enum.valueOf(enumType, ...).
        return null;
    }

    <E extends Enum<E>> Class<E> castEnumType(Class<?> enumType) {
        return (Class<E>) enumType;
    }

    <T> Foo<T> createFoo(Class<T> type) {
        if (Enum.class.isAssignableFrom(type))
            return (Foo<T>) createEnumFoo(castEnumType(type));
        else
            // Here we would do something else or maybe throw an exception.
            return null;
    }

    interface Foo<T> {
    }
}

Is there a simpler way to do this?


Some context

To clarify the problem I'm facing, I'll explain how this problem actually arose in a project I'm working on:

In the code where I came across this problem, Foo<T> is actually Converter<T> , which is an interface which allows an instance of T to be serialized and de-serialized from and to a JSON value:

public interface Converter<T> {
    JsonObject encode(T value);

    T decode(JsonObject data);
} 

And createFoo() is actually a method converterForType() which takes a Class<T> instance and dynamically dispatches to a bunch of static methods and fields that create/contain converters for common Java types and types specific to the project. Normally when a converter is needed, the appropriate method/field is accessed directly but there are some places where the type is only known at runtime, which is where converterForType() is used.

Now I wanted to extend that method to automatically handle enum types by converting those to JSON strings containing the name of the enum constant. This is why I need to call the method enumConverter() from converterForType() . This is the implementation of enumConverter() :

public static <E extends Enum<E>> Converter<E> enumConverter(final Class<E> enumClass) {
    return new Converter<E>() {
        public JsonObject encode(E value) {
            return Json.convert(value.name());
        }

        public E decode(JsonObject data) {
            return Enum.valueOf(enumClass, data.asString());
        }
    };
}

What about this, use raw types for createEnumFoo method
Edit: fixed compile error reported by @Feuermurmel in comments

@SuppressWarnings({ "unchecked", "rawtypes" })
final class Example
{
    <E extends Enum<E>> Foo<E> createEnumFoo(Class enumType)
    {
        // This makes use of e.g. Enum.valueOf(enumType, ...).
        Enum x = Enum.valueOf(enumType, "x");
        return (Foo<E>) x;
    }

    <T extends Enum> Foo<T> createFoo(Class<T> type)
    {
        if (Enum.class.isAssignableFrom(type))
            return (Foo<T>) createEnumFoo(type);
        else
            // Here we would do something else or maybe throw an exception.
            return null;
    }

    interface Foo<T>
    {
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM