Mappez facilement entre enum et int / String

108

Lorsque je travaille avec des variables / paramètres qui ne peuvent prendre qu'un nombre fini de valeurs, j'essaie de toujours utiliser Java enum, comme dans

public enum BonusType {
  MONTHLY, YEARLY, ONE_OFF
}

Tant que je reste dans mon code, cela fonctionne très bien. Cependant, j'ai souvent besoin de m'interfacer avec un autre code qui utilise des valeurs simples int(ou String) dans le même but, ou j'ai besoin de lire / écrire depuis / vers une base de données où les données sont stockées sous forme de nombre ou de chaîne.

Dans ce cas, j'aimerais avoir un moyen pratique d'associer chaque valeur d'énumération à un entier, de sorte que je puisse convertir dans les deux sens (en d'autres termes, j'ai besoin d'une "énumération réversible").

Passer de enum à int est facile:

public enum BonusType {
  public final int id;

  BonusType(int id) {
    this.id = id;
  }
  MONTHLY(1), YEARLY(2), ONE_OFF(3);
}

Ensuite, je peux accéder à la valeur int comme BonusType x = MONTHLY; int id = x.id;.

Cependant, je ne vois pas de bon moyen pour l'inverse, c'est-à-dire passer de int à enum. Idéalement, quelque chose comme

BonusType bt = BonusType.getById(2); 

Les seules solutions que je pourrais proposer sont:

  • Mettez une méthode de recherche dans l'énumération, qui utilise BonusType.values() pour remplir une carte "int -> enum", puis la met en cache et l'utilise pour les recherches. Cela fonctionnerait, mais je devrais copier cette méthode de manière identique dans chaque énumération que j'utilise :-(.
  • Placez la méthode de recherche dans une classe utilitaire statique. Ensuite, je n'aurais besoin que d'une méthode de «recherche», mais je devrais bricoler avec la réflexion pour que cela fonctionne pour une énumération arbitraire.

Les deux méthodes semblent terriblement maladroites pour un problème aussi simple (?).

Avez-vous d'autres idées / idées?

sleske
la source
1
I <3 java enums mais les déteste pour cette raison exactement! Il semble toujours qu'ils soient parfaits à part un défaut vraiment laid ...
Chris Thompson
8
pour enum-> int, vous pouvez simplement utiliserordinal()
davin
1
Vos valeurs d'identité .ordinal()peuvent-elles être décidées par vous (c'est-à-dire, ne pouvez-vous pas simplement les utiliser ), ou sont-elles décidées par des forces extérieures?
Paŭlo Ebermann
2
@davin: Oui, et demandez à votre code d'interrompre le moment où quelqu'un réorganise la déclaration d'énumération ou supprime une valeur au milieu. J'ai peur que ce ne soit pas une solution robuste: - /.
sleske
1
@davin en utilisant "ordinal ()" doit être évité autant que possible, c'est dans la spécification du langage
DPM

Réponses:

37

http://www.javaspecialists.co.za/archive/Issue113.html

La solution commence comme la vôtre avec une valeur int dans le cadre de la définition enum. Il continue ensuite à créer un utilitaire de recherche basé sur les génériques:

public class ReverseEnumMap<V extends Enum<V> & EnumConverter> {
    private Map<Byte, V> map = new HashMap<Byte, V>();
    public ReverseEnumMap(Class<V> valueType) {
        for (V v : valueType.getEnumConstants()) {
            map.put(v.convert(), v);
        }
    }

    public V get(byte num) {
        return map.get(num);
    }
}

Cette solution est agréable et ne nécessite pas de `` bidouiller la réflexion '' car elle est basée sur le fait que tous les types enum héritent implicitement de l'interface Enum.

Jeff
la source
Cela n'utilise-t-il pas l'ordinal? Sleske utilise un identifiant simplement parce que l'ordinal change lorsque les valeurs d'énumération sont réorganisées.
extraneon le
Non, il n'utilise pas d'ordinal. Il repose sur une valeur int explicitement définie. Cette valeur int est utilisée comme clé de mappage (retournée par v.convert ()).
Jeff
2
J'aime vraiment cette solution; il semble que ce soit le plus général que vous puissiez obtenir.
sleske
+1. Ma seule remarque est que j'utiliserais à la Numberplace de Byte, car ma valeur de support peut être plus grande.
Ivaylo Slavov le
3
Lisez vraiment et vraiment la question. Si vous avez affaire à une base de données héritée ou à un système externe qui a défini des entiers que vous ne souhaitez pas propager via votre propre code, c'est exactement l'un de ces cas. L'ordinal est un moyen extrêmement fragile de conserver la valeur d'une énumération, et au-delà, il est inutile dans le cas spécifique mentionné dans la question.
Jeff
327

énumération → int

yourEnum.ordinal()

int → énumération

EnumType.values()[someInt]

Chaîne → enum

EnumType.valueOf(yourString)

enum → Chaîne

yourEnum.name()

Remarque:
comme vous le faites remarquer correctement, le ordinal()peut être "instable" d'une version à l'autre. C'est la raison exacte pour laquelle je stocke toujours les constantes sous forme de chaînes dans mes bases de données. (En fait, lorsque j'utilise MySql, je les stocke sous forme d' énumérations MySql !)

aioobe
la source
2
+1 C'est la bonne réponse évidente. Notez cependant qu'il existe une méthode d'argument unique pour valueOf qui ne prend qu'une chaîne et existe tant que vous utilisez le type enum concret (par exemple BonusType.valueOf("MONTHLY"))
Tim Bender
18
L'utilisation ordinal()me semble être une solution problématique, car elle sera interrompue lorsque la liste des valeurs d'énumération est réorganisée ou qu'une valeur est supprimée. De plus, cela n'est pratique que si les valeurs int sont 0 ... n (ce que j'ai souvent trouvé ne pas être le cas).
sleske
4
@sleske, si vous commencez à supprimer des constantes, vous avez de toute façon des problèmes avec les données persistantes existantes. (Mis à jour ma réponse à cet égard.)
aioobe
3
L'utilisation du values()tableau ne fonctionnera que si toutes vos valeurs sont indexées à 0 pour leur id et sont déclarées dans l'ordre. (J'ai testé ceci pour vérifier que si vous déclarez FOO(0), BAR(2), BAZ(1);cela values[1] == BARet values[2] == BAZmalgré les identifiants passés.)
corsiKa
2
@glowcoder, eh bien, bien sûr, l'argument entier est simplement un champ dans l'objet enum. Cela n'a rien à voir avec la constante ordinale associée à l'objet enum (cela aurait tout aussi bien pu être a double).
aioobe
29

J'ai trouvé cela sur le Web, c'était très utile et simple à mettre en œuvre. Cette solution n'a PAS été faite par moi

http://www.ajaxonomy.com/2007/java/making-the-most-of-java-50-enum-tricks

public enum Status {
 WAITING(0),
 READY(1),
 SKIPPED(-1),
 COMPLETED(5);

 private static final Map<Integer,Status> lookup 
      = new HashMap<Integer,Status>();

 static {
      for(Status s : EnumSet.allOf(Status.class))
           lookup.put(s.getCode(), s);
 }

 private int code;

 private Status(int code) {
      this.code = code;
 }

 public int getCode() { return code; }

 public static Status get(int code) { 
      return lookup.get(code); 
 }

}

melqkiades
la source
s / EnumSet.allOf (Status.class) /Status.values ​​()
jelinson
8

Il semble que les réponses à cette question soient obsolètes avec la sortie de Java 8.

  1. N'utilisez pas ordinal car ordinal est instable s'il est conservé en dehors de la JVM, comme une base de données.
  2. Il est relativement facile de créer une carte statique avec les valeurs clés.

public enum AccessLevel {
  PRIVATE("private", 0),
  PUBLIC("public", 1),
  DEFAULT("default", 2);

  AccessLevel(final String name, final int value) {
    this.name = name;
    this.value = value;
  }

  private final String name;
  private final int value;

  public String getName() {
    return name;
  }

  public int getValue() {
    return value;
  }

  static final Map<String, AccessLevel> names = Arrays.stream(AccessLevel.values())
      .collect(Collectors.toMap(AccessLevel::getName, Function.identity()));
  static final Map<Integer, AccessLevel> values = Arrays.stream(AccessLevel.values())
      .collect(Collectors.toMap(AccessLevel::getValue, Function.identity()));

  public static AccessLevel fromName(final String name) {
    return names.get(name);
  }

  public static AccessLevel fromValue(final int value) {
    return values.get(value);
  }
}
John Meyer
la source
Le deuxième paramètre de ne devrait-il pas Collectors.toMap()être Functions.identity()au lieu de null?
Adam Michalik
oui, j'ai adopté cela à partir d'une classe d'aide que j'utilise avec la goyave qui convertit null en identité.
John Meyer
C'est une belle utilisation des nouvelles fonctionnalités de Java 8. Cependant, cela signifie toujours que le code devrait être répété dans chaque énumération - et ma question était d'éviter ce passe-partout (structurellement) répété.
sleske
5

org.apache.commons.lang.enums.ValuedEnum;

Pour m'éviter d'écrire des tonnes de code standard ou de dupliquer du code pour chaque Enum, j'ai utilisé Apache Commons Lang à la ValuedEnumplace.

Définition :

public class NRPEPacketType extends ValuedEnum {    
    public static final NRPEPacketType TYPE_QUERY = new NRPEPacketType( "TYPE_QUERY", 1);
    public static final NRPEPacketType TYPE_RESPONSE = new NRPEPacketType( "TYPE_RESPONSE", 2);

    protected NRPEPacketType(String name, int value) {
        super(name, value);
    }
}

Usage:

int -> ValuedEnum:

NRPEPacketType packetType = 
 (NRPEPacketType) EnumUtils.getEnum(NRPEPacketType.class, 1);
Alastair McCormack
la source
Bonne idée, je ne savais pas que cela existait. Merci d'avoir partagé!
Keith P
3

Vous pourriez peut-être utiliser quelque chose comme

interface EnumWithId {
    public int getId();

}


enum Foo implements EnumWithId {

   ...
}

Cela réduirait le besoin de réflexion dans votre classe d'utilité.

extraneon
la source
Pouvez-vous donner un exemple d'utilisation de cet extrait de code?
IgorGanapolsky
3

Dans ce code, pour une recherche permanente et intense, ayez de la mémoire ou un processus à utiliser, et je sélectionne la mémoire, avec un tableau de conversion comme index. J'espère que c'est utile

public enum Test{ 
VALUE_ONE(101, "Im value one"),
VALUE_TWO(215, "Im value two");
private final int number;
private final byte[] desc;

private final static int[] converter = new int[216];
static{
    Test[] st = values();
    for(int i=0;i<st.length;i++){
        cv[st[i].number]=i;
    }
}

Test(int value, byte[] description) {
    this.number = value;
    this.desc = description;
}   
public int value() {
    return this.number;
}
public byte[] description(){
    return this.desc;
}

public static String description(int value) {
    return values()[converter[rps]].desc;
}

public static Test fromValue(int value){
return values()[converter[rps]];
}
}
Sebastian Sgo Acevedo
la source
2

Utilisez une interface pour lui montrer qui est le patron.

public interface SleskeEnum {
    int id();

    SleskeEnum[] getValues();

}

public enum BonusType implements SleskeEnum {


  MONTHLY(1), YEARLY(2), ONE_OFF(3);

  public final int id;

  BonusType(int id) {
    this.id = id;
  }

  public SleskeEnum[] getValues() {
    return values();
  }

  public int id() { return id; }


}

public class Utils {

  public static SleskeEnum getById(SleskeEnum type, int id) {
      for(SleskeEnum t : type.getValues())
          if(t.id() == id) return t;
      throw new IllegalArgumentException("BonusType does not accept id " + id);
  }

  public static void main(String[] args) {

      BonusType shouldBeMonthly = (BonusType)getById(BonusType.MONTHLY,1);
      System.out.println(shouldBeMonthly == BonusType.MONTHLY);

      BonusType shouldBeMonthly2 = (BonusType)getById(BonusType.MONTHLY,1);
      System.out.println(shouldBeMonthly2 == BonusType.YEARLY);

      BonusType shouldBeYearly = (BonusType)getById(BonusType.MONTHLY,2);
      System.out.println(shouldBeYearly  == BonusType.YEARLY);

      BonusType shouldBeOneOff = (BonusType)getById(BonusType.MONTHLY,3);
      System.out.println(shouldBeOneOff == BonusType.ONE_OFF);

      BonusType shouldException = (BonusType)getById(BonusType.MONTHLY,4);
  }
}

Et le résultat:

C:\Documents and Settings\user\My Documents>java Utils
true
false
true
true
Exception in thread "main" java.lang.IllegalArgumentException: BonusType does not accept id 4
        at Utils.getById(Utils.java:6)
        at Utils.main(Utils.java:23)

C:\Documents and Settings\user\My Documents>
corsiKa
la source
1
Tout comme avec la réponse de Turd Ferguson, c'est la solution peu élégante que je voudrais éviter / améliorer ...
sleske
Je crée généralement les mappages inverses dans un bloc static {} pour ne pas avoir à boucler sur values ​​() chaque fois que je demande une valeur par id. J'appelle aussi généralement la méthode valueOf (int) pour la faire apparaître un peu comme la méthode valueOf (String) déjà présente pour Strings (également partie de la question de l'OP). Un peu comme l'élément 33 dans Effective Java: tinyurl.com/4ffvc38
Fredrik
@Sleske Mis à jour avec une solution plus raffinée. @Fredrik intéressant, même si je doute que l'itération soit un problème important.
corsiKa
@glowcoder Eh bien, ne pas avoir à itérer plus d'une fois signifie que peu importe si vous le faites mille fois par seconde, ce qui peut être un problème très important ou simplement l'appeler deux fois.
Fredrik
@Fredrik J'admets qu'il y a des moments où il peut être nécessaire d'optimiser. Je dis également que tant que ce n'est pas un problème de performance identifié, ne l'optimisez pas.
corsiKa
2

Les deux .ordinal()et values()[i]sont instables car ils dépendent de l'ordre des énumérations. Ainsi, si vous changez l'ordre des énumérations ou en ajoutez / supprimez certaines, votre programme serait interrompu.

Voici une méthode simple mais efficace pour mapper entre enum et int.

public enum Action {
    ROTATE_RIGHT(0), ROTATE_LEFT(1), RIGHT(2), LEFT(3), UP(4), DOWN(5);

    public final int id;
    Action(int id) {
        this.id = id;
    }

    public static Action get(int id){
        for (Action a: Action.values()) {
            if (a.id == id)
                return a;
        }
        throw new IllegalArgumentException("Invalid id");
    }
}

L'application pour les chaînes ne devrait pas être difficile.

hrzafer
la source
Oui, je me rends compte que je pourrais le faire - ou même mieux, utiliser une carte pour la recherche inversée, plutôt que de parcourir toutes les valeurs. Je l'ai mentionné dans ma question, et j'ai également mentionné que je cherchais une meilleure solution, pour éviter d'avoir un code standard dans chaque énumération.
sleske
2

Un exemple d'utilisation très propre de l'énumération inverse

Étape 1 Définissez un interfaceEnumConverter

public interface EnumConverter <E extends Enum<E> & EnumConverter<E>> {
    public String convert();
    E convert(String pKey);
}

Étape 2

Créer un nom de classe ReverseEnumMap

import java.util.HashMap;
import java.util.Map;

public class ReverseEnumMap<V extends Enum<V> & EnumConverter<V>> {
    private Map<String, V> map = new HashMap<String, V>();

    public ReverseEnumMap(Class<V> valueType) {
        for (V v : valueType.getEnumConstants()) {
            map.put(v.convert(), v);
        }
    }

    public V get(String pKey) {
        return map.get(pKey);
    }
}

Étape 3

Allez à votre Enumclasse et implementavec EnumConverter<ContentType>et bien sûr remplacer les méthodes d'interface. Vous devez également initialiser un ReverseEnumMap statique.

public enum ContentType implements EnumConverter<ContentType> {
    VIDEO("Video"), GAME("Game"), TEST("Test"), IMAGE("Image");

    private static ReverseEnumMap<ContentType> map = new ReverseEnumMap<ContentType>(ContentType.class);

    private final String mName;

    ContentType(String pName) {
        this.mName = pName;
    }

    String value() {
        return this.mName;
    }

    @Override
    public String convert() {
        return this.mName;
    }

    @Override
    public ContentType convert(String pKey) {
        return map.get(pKey);
    }
}

Étape 4

Créez maintenant un Communicationfichier de classe et appelez sa nouvelle méthode pour convertir un Enumen Stringet Stringen Enum. Je viens de mettre la méthode principale à des fins d'explication.

public class Communication<E extends Enum<E> & EnumConverter<E>> {
    private final E enumSample;

    public Communication(E enumSample) {
        this.enumSample = enumSample;
    }

    public String resolveEnumToStringValue(E e) {
        return e.convert();
    }

    public E resolveStringEnumConstant(String pName) {
        return enumSample.convert(pName);
    }

//Should not put main method here... just for explanation purpose. 
    public static void main(String... are) {
        Communication<ContentType> comm = new Communication<ContentType>(ContentType.GAME);
        comm.resolveEnumToStringValue(ContentType.GAME); //return Game
        comm.resolveStringEnumConstant("Game"); //return GAME (Enum)
    }
}

Cliquez pour une explication complète

AZ_
la source
1
Cela me plaît vraiment, vraiment - je cherche depuis un certain temps une solution solide à ce problème. Le seul changement que j'ai fait était de rendre ContentType convert(String pKey)statique, ce qui supprime le besoin de la Communicationclasse et était plus à mon goût. +1
Chris Mantle
1

Je ne suis pas sûr que ce soit la même chose en Java, mais les types enum en C sont automatiquement mappés en nombres entiers afin que vous puissiez utiliser le type ou l'entier pour y accéder. Avez-vous déjà essayé d'y accéder simplement avec un entier?

Detra83
la source
2
Les énumérations en Java ne se comportent pas de cette façon. C'est un type explicite.
Chris Thompson
Chaque objet enum aurait un numéro interne (à savoir la position dans laquelle il a été déclaré), et il est accessible par la .ordinal()méthode. (Dans l'autre sens, utilisez BonusType.values()[i].) Mais dans l'exemple cité ci-dessus, les index ici et les valeurs extérieures ne coïncident pas.
Paŭlo Ebermann
1

Vraiment bonne question :-) J'ai utilisé une solution similaire à celle de Mr.Ferguson il y a quelque temps. Notre énumération décompilée ressemble à ceci:

final class BonusType extends Enum
{

    private BonusType(String s, int i, int id)
    {
        super(s, i);
        this.id = id;
    }

    public static BonusType[] values()
    {
        BonusType abonustype[];
        int i;
        BonusType abonustype1[];
        System.arraycopy(abonustype = ENUM$VALUES, 0, abonustype1 = new BonusType[i = abonustype.length], 0, i);
        return abonustype1;
    }

    public static BonusType valueOf(String s)
    {
        return (BonusType)Enum.valueOf(BonusType, s);
    }

    public static final BonusType MONTHLY;
    public static final BonusType YEARLY;
    public static final BonusType ONE_OFF;
    public final int id;
    private static final BonusType ENUM$VALUES[];

    static 
    {
        MONTHLY = new BonusType("MONTHLY", 0, 1);
        YEARLY = new BonusType("YEARLY", 1, 2);
        ONE_OFF = new BonusType("ONE_OFF", 2, 3);
        ENUM$VALUES = (new BonusType[] {
            MONTHLY, YEARLY, ONE_OFF
        });
    }
}

Voir cela est évident pourquoi ordinal()est instable. C'est le idedans super(s, i);. Je suis également pessimiste que vous puissiez penser à une solution plus élégante que celles que vous avez déjà énumérées. Après tout, les énumérations sont des classes comme toutes les classes finales.

Lachezar Balev
la source
1

Par souci d'exhaustivité, voici une approche générique pour récupérer les valeurs d'énumération par index à partir de n'importe quel type d'énumération. Mon intention était de faire en sorte que la méthode ressemble à Enum.valueOf (Class, String) . Fyi, j'ai copié cette méthode à partir d' ici .

Les problèmes liés à l'index (déjà abordés en détail ici) s'appliquent toujours.

/**
 * Returns the {@link Enum} instance for a given ordinal.
 * This method is the index based alternative
 * to {@link Enum#valueOf(Class, String)}, which
 * requires the name of an instance.
 * 
 * @param <E> the enum type
 * @param type the enum class object
 * @param ordinal the index of the enum instance
 * @throws IndexOutOfBoundsException if ordinal < 0 || ordinal >= enums.length
 * @return the enum instance with the given ordinal
 */
public static <E extends Enum<E>> E valueOf(Class<E> type, int ordinal) {
    Preconditions.checkNotNull(type, "Type");
    final E[] enums = type.getEnumConstants();
    Preconditions.checkElementIndex(ordinal, enums.length, "ordinal");
    return enums[ordinal];
}
whiskeysierra
la source
Ce n'est pas vraiment ce que je recherche, car cela ne récupère les valeurs d'énumération que par leur ordinal, pas par un identifiant entier attribué (voir ma question). De plus, si je le souhaite, je peux simplement utiliser MyEnumType.values()- pas besoin d'une méthode d'assistance statique.
sleske
0
Int -->String :

public enum Country {

    US("US",0),
    UK("UK",2),
    DE("DE",1);


    private static Map<Integer, String> domainToCountryMapping; 
    private String country;
    private int domain;

    private Country(String country,int domain){
        this.country=country.toUpperCase();
        this.domain=domain;
    }

    public String getCountry(){
        return country;
    }


    public static String getCountry(String domain) {
        if (domainToCountryMapping == null) {
            initMapping();
        }

        if(domainToCountryMapping.get(domain)!=null){
            return domainToCountryMapping.get(domain);
        }else{
            return "US";
        }

    }

     private static void initMapping() {
         domainToCountryMapping = new HashMap<Integer, String>();
            for (Country s : values()) {
                domainToCountryMapping.put(s.domain, s.country);
            }
        }
Ran Adler
la source
0

J'avais besoin de quelque chose de différent parce que je voulais utiliser une approche générique. Je lis l'énumération vers et à partir de tableaux d'octets. C'est là que je viens avec:

public interface EnumConverter {
    public Number convert();
}



public class ByteArrayConverter {
@SuppressWarnings("unchecked")
public static Enum<?> convertToEnum(byte[] values, Class<?> fieldType, NumberSystem numberSystem) throws InvalidDataException {
    if (values == null || values.length == 0) {
        final String message = "The values parameter must contain the value";
        throw new IllegalArgumentException(message);
    }

    if (!dtoFieldType.isEnum()) {
        final String message = "dtoFieldType must be an Enum.";
        throw new IllegalArgumentException(message);
    }

    if (!EnumConverter.class.isAssignableFrom(fieldType)) {
        final String message = "fieldType must implement the EnumConverter interface.";
        throw new IllegalArgumentException(message);
    }

    Enum<?> result = null;
    Integer enumValue = (Integer) convertToType(values, Integer.class, numberSystem); // Our enum's use Integer or Byte for the value field.

    for (Object enumConstant : fieldType.getEnumConstants()) {
        Number ev = ((EnumConverter) enumConstant).convert();

        if (enumValue.equals(ev)) {
            result = (Enum<?>) enumConstant;
            break;
        }
    }

    if (result == null) {
        throw new EnumConstantNotPresentException((Class<? extends Enum>) fieldType, enumValue.toString());
    }

    return result;
}

public static byte[] convertEnumToBytes(Enum<?> value, int requiredLength, NumberSystem numberSystem) throws InvalidDataException {
    if (!(value instanceof EnumConverter)) {
        final String message = "dtoFieldType must implement the EnumConverter interface.";
        throw new IllegalArgumentException(message);
    }

    Number enumValue = ((EnumConverter) value).convert();
    byte[] result = convertToBytes(enumValue, requiredLength, numberSystem);
    return result;
}

public static Object convertToType(byte[] values, Class<?> type, NumberSystem numberSystem) throws InvalidDataException {
    // some logic to convert the byte array supplied by the values param to an Object.
}

public static byte[] convertToBytes(Object value, int requiredLength, NumberSystem numberSystem) throws InvalidDataException {
    // some logic to convert the Object supplied by the'value' param to a byte array.
}
}

Exemple d'énumérations:

public enum EnumIntegerMock implements EnumConverter {
    VALUE0(0), VALUE1(1), VALUE2(2);

    private final int value;

    private EnumIntegerMock(int value) {
        this.value = value;
    }

public Integer convert() {
    return value;
}

}

public enum EnumByteMock implements EnumConverter {
    VALUE0(0), VALUE1(1), VALUE2(2);

    private final byte value;

    private EnumByteMock(int value) {
        this.value = (byte) value;
    }

    public Byte convert() {
        return value;
    }
}
Patrick Koorevaar
la source
0

Juste parce que la réponse acceptée n'est pas autonome:

Code de support:

public interface EnumWithCode<E extends Enum<E> & EnumWithCode<E>> {

    public Integer getCode();

    E fromCode(Integer code);
}


public class EnumWithCodeMap<V extends Enum<V> & EnumWithCode<V>> {

    private final HashMap<Integer, V> _map = new HashMap<Integer, V>();

    public EnumWithCodeMap(Class<V> valueType) {
        for( V v : valueType.getEnumConstants() )
            _map.put(v.getCode(), v);
    }

    public V get(Integer num) {
        return _map.get(num);
    }
}

Exemple d'utilisation:

public enum State implements EnumWithCode<State> {
    NOT_STARTED(0), STARTED(1), ENDED(2);

    private static final EnumWithCodeMap<State> map = new EnumWithCodeMap<State>(
            State.class);

    private final int code;

    private State(int code) {
        this.code = code;
    }

    @Override
    public Integer getCode() {
        return code;
    }

    @Override
    public State fromCode(Integer code) {
        return map.get(code);
    }

}
Leonbloy
la source
0

donné:

public enum BonusType {MONTHLY (0), YEARLY (1), ONE_OFF (2)}

Bonus de type bonus = ANNUEL;

System.out.println (bonus.Ordinal () + ":" + bonus)

Sortie: 1: ANNUELLE

David Urry
la source
0

Si vous avez une voiture de classe

public class Car {
    private Color externalColor;
}

Et la propriété Color est une classe

@Data
public class Color {
    private Integer id;
    private String name;
}

Et vous voulez convertir Color en Enum

public class CarDTO {
    private ColorEnum externalColor;
}

Ajoutez simplement une méthode dans la classe Color pour convertir Color en ColorEnum

@Data
public class Color {
    private Integer id;
    private String name;

    public ColorEnum getEnum(){
        ColorEnum.getById(id);
    }
}

et à l'intérieur de ColorEnum implémente la méthode getById ()

public enum ColorEnum {
...
    public static ColorEnum getById(int id) {
        for(ColorEnum e : values()) {
            if(e.id==id) 
                return e;
        }
    }
}

Vous pouvez maintenant utiliser un classMap

private MapperFactory factory = new DefaultMapperFactory.Builder().build();
...
factory.classMap(Car.class, CarDTO.class)
    .fieldAToB("externalColor.enum","externalColor")
    .byDefault()
    .register();
...
CarDTO dto = mapper.map(car, CarDTO.class);
Danilo
la source