Using generics with collection of enum classes implementing same interface - java

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));
}
}

Related

How get list of all classes that inherit from the interface with the specified generic (interface<concrete class>)

I have command interface
public interface ICommand {...}
and handler interface that is associated with specific command
public interface ICommandHandler<T extends ICommand> {
IResponse handle(T command);
}
For example, I have concrete command
public class GetCatalogById implements ICommand{
private final long catalogId;
public GetCatalogById(long catalogId) {
this.catalogId = catalogId;
}
public long getCatalogId() {
return catalogId;
}
}
How programmatically get list (List) of all classes in project that
implements ICommandHandler<GetCatalogById>
?
Your problem can be divided into 2 subproblems:
Getting a list of all classes that implement ICommandHandler
Filtering ones which have a required type parameter
As #ArvindKumarAvinash said, you can find many solutions to the first subproblem here.
And here is my solution for a second one:
public static <T extends ICommand> List<Class<? extends ICommandHandler<T>>> getCommandHandlers(
Class<T> commandClass, String packageName
) {
return new Reflections(packageName).getSubTypesOf(ICommandHandler.class).stream()
.filter(subtype -> !subtype.isInterface())
.filter(subtype -> Objects.equals(getParameter(subtype, ICommandHandler.class, 0), commandClass))
.map(subtype -> (Class<? extends ICommandHandler<T>>) subtype)
.collect(Collectors.toList());
}
#Nullable
public static <T> Type getParameter(
Class<T> clazz,
Class<? super T> parametrizedParent,
int index
) {
Type result = null;
for (ParameterizedType parent : getParameterizedParents(clazz, parametrizedParent)) {
result = parent.getActualTypeArguments()[index];
if (!(result instanceof TypeVariable)) return result;
index = getTypeVariableIndex((TypeVariable<?>) result);
}
return result;
}
private static <T> List<ParameterizedType> getParameterizedParents(Class<? extends T> clazz, Class<T> parent) {
List<ParameterizedType> genericParents = new ArrayList<>();
Class<? extends T> current = clazz;
while (true) {
Type supertype = getSuperType(current, parent);
if (supertype instanceof ParameterizedType)
genericParents.add((ParameterizedType) supertype);
else genericParents.clear();
Type rawSupertype = toRawType(supertype);
if (rawSupertype == parent) {
Collections.reverse(genericParents);
return genericParents;
}
current = (Class<? extends T>) rawSupertype;
}
}
private static <T> Type getSuperType(Class<? extends T> child, Class<T> parent) {
if (child == parent) return child;
Type superclass = child.getGenericSuperclass();
if (isSubTypeOfClass(superclass, parent)) return superclass;
for (Type type : child.getGenericInterfaces())
if (isSubTypeOfClass(type, parent)) return type;
throw new IllegalArgumentException(child.getName() + " is not assignable from " + parent.getName());
}
private static int getTypeVariableIndex(final TypeVariable<?> typeVariable) {
return Arrays.asList(typeVariable.getGenericDeclaration().getTypeParameters()).indexOf(typeVariable);
}
private static boolean isSubTypeOfClass(Type type, Class<?> clazz) {
Type rawType = toRawType(type);
return rawType instanceof Class && clazz.isAssignableFrom((Class<?>) rawType);
}
private static Type toRawType(Type type) {
return type instanceof ParameterizedType ? ((ParameterizedType) type).getRawType() : type;
}

static generic method and subinterface?

I have an interface looks like this.
public interface FieldEnum<T> {
static <E extends Enum<E> & FieldEnum<T>, T> E valueOfRaw(
final Class<E> type, final T raw) {
for (final E enumConstant : type.getEnumConstants()) {
if (Objects.equals(enumConstant.getRaw(), raw)) {
return enumConstant;
}
}
throw new IllegalArgumentException("unknown raw: " + raw);
}
T getRaw();
}
When I extend it like this,
public interface StringFieldEnum extends FieldEnum<String> {
}
Is it redundant to define following method in it?
static <E extends Enum<E> & StringFieldEnum> E valueOfRaw(
final Class<E> type, final String raw) {
return FieldEnum.valueOfRaw(type, raw);
}

Properly cast generics

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.

Generic class as argument

I have a generic class Card . Rank is interface
class Card<T extends Enum<T> & Rank>
I am trying to create two static comparators of Card.
public final static Comparator<Card<?>> comparatorByAttribute1 = new Comparator<Card<?>>() {
#Override
public int compare(Card<?> o1, Card<?> o2)
{
...
}
};
How can I define that the type of o1 should be the same with o2 ?
Why not just use the actual type in the type declaration?
public final static Comparator<Card<ActualType>> comparatorByAttribute1 =
new Comparator<Card<ActualType>>() {
#Override
public int compare(Card<ActualType> o1, Card<ActualType> o2) {
return 0;
}
};
With...
public enum ActualType implements Rank {...}
Alternatively, if you want to keep the generic type <T>, you will need to resort to using a generic static method, because there is no way of having generic attributes in Java:
public final static <T extends Enum<T> & Rank> Comparator<Card<T>>
comparatorByAttribute1() {
return new Comparator<Card<T>>() {
#Override
public int compare(Card<T> o1, Card<T> o2) {
return 0;
}
};
}
Or, you resort to unsafe casting:
#SuppressWarnings({ "rawtypes", "unchecked" })
public final static <T extends Enum<T> & Rank> Comparator<Card<T>>
comparatorByAttribute1() {
// Your attribute
return (Comparator) comparatorByAttribute1;
}

JAVA and generic types issue

I'm facing an issue with generic types:
public static class Field<T> {
private Class<? extends T> clazz;
public Field(Class<? extends T> clazz) {
this.clazz = clazz;
}
}
public static void main(String[] args) {
// 1. (warning) Iterable is a raw type. References to generic type Iterable<T> should be parameterized.
new Field<Iterable>(List.class);
// 2. (error) The constructor Main.Field<Iterable<?>>(Class<List>) is undefined.
new Field<Iterable<?>>(List.class);
// 3. (error) *Simply unpossible*
new Field<Iterable<?>>(List<?>.class);
// 4. (warning) Type safety: Unchecked cast from Class<List> to Class<? extends Iterable<?>>.
new Field<Iterable<?>>((Class<? extends Iterable<?>>) List.class);
}
What's the best solution between the 1. and the 4. (or any other one by the way)?
public class Field <T> {
private Class <? extends T> clazz;
public <TT extends T> Field (Class <TT> clazz) {
this.clazz = clazz;
}
public static void main (String [] args) {
new Field <Iterable <?>> (List.class);
}
}

Categories

Resources