Using generics with a set of enum classes that implement the same interface

I am trying to do a reverse search on several enum classes that implement the same Field interface by repeating using the Class es list using Guava 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 the same code (to create an index and perform a search) in all enumeration classes, so I use the auxiliary static Fields class containing the 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 Class<? extends Enum<?>> clazz for each loop (not matching the field) , but I don't know how to handle this case (obviously, I can't add & Field to clazz ).

+6
source share
3 answers

Inspired by Tom Hotin 's Answer I created a wrapper Class es, but only those with the 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 using the FieldEnumWrapper static factory:

 FieldEnumWrapper.of(NotEnumAndFieldClass.class) 

generates a compilation error.

In addition, valueOfSearchName now a FieldEnumWrapper method, which is more important than the helper class.

+1
source

Consider Class<? extends List<?> Class<? extends List<?> . Class<? extends List<?> Class<? extends List<?> has two wildcards, while <E extends List<E>> Class<E> has only a common parameter. The first recognizes Class<ArrayList<String>> . Therefore, without doing anything special for the enumerations, the types are incompatible.

How to fix? An additional 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() ); ... 

(The usual exemption from: not the way they tried to compile.)

+4
source

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 < Nn; i++) System.out.println(i + " " + helper.map.get(i)); } } 
0
source

Source: https://habr.com/ru/post/904605/


All Articles