Dogodnie mapuj między enum i int / String

108

Podczas pracy ze zmiennymi / parametrami, które mogą przyjmować tylko skończoną liczbę wartości, staram się zawsze używać języka Java enum, tak jak w

public enum BonusType {
  MONTHLY, YEARLY, ONE_OFF
}

Tak długo, jak pozostaję w swoim kodzie, działa dobrze. Jednak często muszę łączyć się z innym kodem, który używa zwykłych int(lub String) wartości do tego samego celu, lub muszę czytać / zapisywać z / do bazy danych, w której dane są przechowywane jako liczba lub ciąg.

W takim przypadku chciałbym mieć wygodny sposób powiązania każdej wartości wyliczenia z liczbą całkowitą, tak aby można było konwertować w obie strony (innymi słowy, potrzebuję „odwracalnego wyliczenia”).

Przejście od enum do int jest łatwe:

public enum BonusType {
  public final int id;

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

Wtedy mogę uzyskać dostęp do wartości int jako BonusType x = MONTHLY; int id = x.id;.

Jednak nie widzę fajnego sposobu na odwrócenie, tj. Przejście z int do enum. Idealnie coś takiego

BonusType bt = BonusType.getById(2); 

Jedyne rozwiązania, jakie mogłem wymyślić, to:

  • Umieść metodę wyszukiwania w wyliczeniu, która BonusType.values()wypełnia mapę „int -> enum”, a następnie buforuje ją i używa do wyszukiwania. Zadziałałoby, ale musiałbym skopiować tę metodę identycznie do każdego wyliczenia, którego używam :-(.
  • Umieść metodę wyszukiwania w statycznej klasie narzędziowej. Wtedy potrzebowałbym tylko jednej metody „wyszukiwania”, ale musiałbym majstrować przy odbiciu, aby działał dla dowolnego wyliczenia.

Obie metody wydają się strasznie niewygodne w przypadku tak prostego (?) Problemu.

Jakieś inne pomysły / spostrzeżenia?

sleske
źródło
1
Mam <3 wyliczenia java, ale nienawidzę ich właśnie z tego powodu! Zawsze wydaje się, że są idealne, poza jedną naprawdę brzydką wadą ...
Chris Thompson,
8
dla enum-> int możesz po prostu użyćordinal()
davin
1
Czy twoje wartości identyfikacyjne są przez ciebie rozstrzygane (to znaczy, nie mógłbyś po prostu użyć .ordinal()), czy też są one ustalane przez siły zewnętrzne?
Paŭlo Ebermann
2
@davin: Tak, i niech twój kod zepsuje się w momencie, gdy ktoś przestawia deklarację wyliczenia lub usuwa wartość w środku. Obawiam się, że to nie jest solidne rozwiązanie: - /.
sleske
1
@davin należy unikać używania „ordinal ()”, gdy tylko jest to możliwe, jest to zgodne ze specyfikacją języka
DPM

Odpowiedzi:

37

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

Rozwiązanie zaczyna się podobnie do twojego z wartością int jako częścią definicji wyliczenia. Następnie tworzy narzędzie wyszukiwania oparte na generycznych:

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

To rozwiązanie jest przyjemne i nie wymaga „majstrowania przy odbiciu”, ponieważ jest oparte na fakcie, że wszystkie typy wyliczeniowe domyślnie dziedziczą interfejs Enum.

Jeff
źródło
Czy to nie używa liczby porządkowej? Sleske używa identyfikatora tylko dlatego, że liczba porządkowa zmienia się, gdy wartości wyliczenia są zmieniane.
extraneon
Nie, nie używa liczby porządkowej. Opiera się na wyraźnie określonej wartości int. Ta wartość int jest używana jako klucz mapy (zwracany przez v.convert ()).
Jeff,
2
Bardzo podoba mi się to rozwiązanie; wydaje się, że jest to najbardziej ogólny, jaki możesz uzyskać.
sleske
+1. Moją jedyną uwagą jest to, że użyłbym Numberzamiast Byte, ponieważ moja wartość zapasowa może być większa.
Ivaylo Slavov
3
Naprawdę i naprawdę przeczytaj pytanie. Jeśli masz do czynienia ze starszą bazą danych lub systemem zewnętrznym, który ma zdefiniowane liczby całkowite, których nie chcesz propagować za pomocą własnego kodu, to jest to dokładnie jeden z tych przypadków. Liczba porządkowa jest niezwykle delikatnym sposobem na zachowanie wartości wyliczenia, a poza tym jest bezużyteczna w konkretnym przypadku wspomnianym w pytaniu.
Jeff,
327

enum → int

yourEnum.ordinal()

int → enum

EnumType.values()[someInt]

String → enum

EnumType.valueOf(yourString)

enum → String

yourEnum.name()

Na marginesie:
jak słusznie zauważyłeś, plik ordinal()może być „niestabilny” z wersji na wersję. To jest dokładny powód, dla którego zawsze przechowuję stałe jako ciągi w moich bazach danych. (Właściwie podczas korzystania z MySql przechowuję je jako wyliczenia MySql !)

aioobe
źródło
2
+1 To jest oczywiście poprawna odpowiedź. Należy jednak pamiętać, że istnieje metoda z jednym argumentem dla valueOf, która przyjmuje tylko ciąg i istnieje tak długo, jak używasz konkretnego typu wyliczenia (np. BonusType.valueOf("MONTHLY"))
Tim Bender,
18
Użycie ordinal()wydaje mi się problematyczne, ponieważ może się zepsuć, gdy lista wartości wyliczeniowych zostanie zmieniona lub wartość zostanie usunięta. Jest to również praktyczne tylko wtedy, gdy wartości int są równe 0 ... n (co, jak często, nie ma miejsca).
sleske
4
@sleske, jeśli zaczniesz usuwać stałe, i tak masz problem z istniejącymi utrwalonymi danymi. (Zaktualizowałem moją odpowiedź w tym zakresie.)
aioobe
3
Korzystanie z values()tablicy będzie działać tylko wtedy, gdy wszystkie wartości są indeksowane za 0 id i deklarowane są w porządku. (Testowałem to, aby sprawdzić, jeśli deklarują FOO(0), BAR(2), BAZ(1);, że values[1] == BARi values[2] == BAZpomimo identyfikatorów wydanych w.)
corsiKa
2
@glowcoder, oczywiście, argument liczby całkowitej jest tylko polem w obiekcie wyliczenia. Nie ma to nic wspólnego ze stałą porządkową związaną z obiektem wyliczenia (równie dobrze mogła to być a double).
aioobe
29

Znalazłem to w sieci, było bardzo pomocne i łatwe do wdrożenia. To rozwiązanie NIE zostało wykonane przeze mnie

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
źródło
s / EnumSet.allOf (Status.class) /Status.values ​​()
jelinson
8

Wydaje się, że odpowiedzi na to pytanie są nieaktualne w wydaniu Java 8.

  1. Nie używaj liczby porządkowej, ponieważ numer porządkowy jest niestabilny, jeśli jest utrwalany poza maszyną JVM, taką jak baza danych.
  2. Utworzenie mapy statycznej z kluczowymi wartościami jest stosunkowo łatwe.

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
źródło
Czy drugi parametr nie powinien Collectors.toMap()być Functions.identity()zamiast null?
Adam Michalik
tak, przejąłem to z klasy pomocniczej, której używam z guawą, która przekształca wartość null w tożsamość.
John Meyer
To zgrabne wykorzystanie nowych funkcji Java 8. Jednak nadal oznacza to, że kod musiałby być powtarzany w każdym wyliczeniu - a moje pytanie dotyczyło uniknięcia tego (strukturalnie) powtarzającego się schematu.
sleske
5

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

Aby zaoszczędzić mi pisania wielu standardowych kodów lub powielania kodu dla każdego Enum, użyłem ValuedEnumzamiast tego Apache Commons Lang .

Definicja :

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

Stosowanie:

int -> ValuedEnum:

NRPEPacketType packetType = 
 (NRPEPacketType) EnumUtils.getEnum(NRPEPacketType.class, 1);
Alastair McCormack
źródło
Dobry pomysł, nie zdawałem sobie sprawy, że to istnieje. Dzięki za udostępnienie!
Keith P,
3

Możesz użyć czegoś takiego

interface EnumWithId {
    public int getId();

}


enum Foo implements EnumWithId {

   ...
}

Zmniejszyłoby to potrzebę refleksji w twojej klasie użytkowej.

extraneon
źródło
Czy możesz podać przykład, jak używać tego fragmentu kodu?
IgorGanapolsky
3

W tym kodzie, do stałego i intensywnego wyszukiwania, mam pamięć lub proces do użycia i wybieram pamięć z tablicą konwertera jako indeksem. Mam nadzieję, że to pomocne

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
źródło
2

Użyj interfejsu, aby pokazać, kto tu rządzi.

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

A wynik:

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
źródło
1
Podobnie jak w przypadku odpowiedzi Turda Fergusona, jest to nieeleganckie rozwiązanie, którego chciałbym uniknąć / ulepszyć ...
sleske
Zwykle tworzę odwrotne mapowania w statycznym bloku {}, aby nie musieć zapętlać wartości () za każdym razem, gdy pytam o wartość według identyfikatora. Zwykle wywołuję również metodę valueOf (int), aby wyglądała trochę jak metoda valueOf (String), która jest już dostępna dla Strings (również część pytania OP). Trochę jak pozycja 33 w Efektywnej Javie: tinyurl.com/4ffvc38
Fredrik
@Sleske Zaktualizowano o bardziej wyrafinowane rozwiązanie. @Fredrik interesujący, chociaż wątpię, czy iteracja będzie istotna.
corsiKa
@glowcoder Cóż, brak konieczności wykonywania iteracji więcej niż raz oznacza, że ​​nie ma znaczenia, czy robisz to tysiąc razy na sekundę, gdzie może to być bardzo istotny problem, czy po prostu wywołujesz to dwa razy.
Fredrik
@Fredrik Przyznaję, że są chwile, w których może być konieczna optymalizacja. Mówię też, że dopóki nie zostanie zidentyfikowany problem z wydajnością, nie optymalizuj go.
corsiKa
2

Zarówno, jak .ordinal()ivalues()[i] są niestabilne, ponieważ są zależne od kolejności wyliczeń. Dlatego jeśli zmienisz kolejność wyliczeń lub dodasz / usuniesz część programu, program się zepsuje.

Oto prosta, ale skuteczna metoda mapowania między enum i 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");
    }
}

Nałożenie go na struny nie powinno być trudne.

hrzafer
źródło
Tak, zdaję sobie sprawę, że mógłbym to zrobić - lub nawet lepiej, użyć mapy do wyszukiwania wstecznego, zamiast iterować po wszystkich wartościach. Wspomniałem o tym w swoim pytaniu, a także wspomniałem, że szukam lepszego rozwiązania, aby uniknąć posiadania kodu standardowego w każdym wyliczeniu.
sleske
2

Bardzo czysty przykład użycia odwrotnego Enum

Krok 1 Zdefiniuj interfaceEnumConverter

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

Krok 2

Utwórz nazwę klasy 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);
    }
}

Krok 3

Idź do Ciebie Enumklasie, a implementto ze EnumConverter<ContentType>i przesłanianie metod interfejsu kursu. Musisz także zainicjować statyczną mapę ReverseEnumMap.

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

Krok 4

Teraz utwórz Communicationplik klasy i wywołaj nową metodę, aby przekonwertować Enumna Stringi Stringna Enum. Właśnie przedstawiłem główną metodę w celu wyjaśnienia.

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

Kliknij, aby uzyskać pełne wyjaśnienie

AZ_
źródło
1
To mi się bardzo podoba - od jakiegoś czasu szukałem solidnego rozwiązania tego problemu. Jedyną zmianą, jaką wprowadziłem, była ContentType convert(String pKey)statystyka, co eliminuje potrzebę Communicationzajęć i bardziej mi się podobało. +1
Chris Mantle
1

Nie jestem pewien, czy jest to to samo w Javie, ale typy wyliczeniowe w C są również automatycznie mapowane na liczby całkowite, więc możesz użyć typu lub liczby całkowitej, aby uzyskać do niego dostęp. Czy próbowałeś już po prostu uzyskać do niego dostęp za pomocą liczby całkowitej?

Detra83
źródło
2
Wyliczenia w Javie nie zachowują się w ten sposób. Są wyraźnym typem.
Chris Thompson,
Każdy obiekt enum miałby numer wewnętrzny (a mianowicie pozycję, w której został zadeklarowany) i można uzyskać do niego dostęp za pomocą .ordinal()metody. (W drugą stronę, użyj BonusType.values()[i].) Ale w powyższym przykładzie indeksy tutaj i wartości zewnętrzne nie pokrywają się.
Paŭlo Ebermann
1

Naprawdę świetne pytanie :-) Jakiś czas temu korzystałem z rozwiązania podobnego do pana Ferguson. Nasze zdekompilowane wyliczenie wygląda następująco:

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

Widząc to, widać, dlaczego ordinal()jest niestabilny. To jest iw super(s, i);. Jestem również pesymistą, że można wymyślić bardziej eleganckie rozwiązanie niż te, które już wymieniłeś. Przecież wyliczenia są klasami jak wszystkie klasy końcowe.

Lachezar Balev
źródło
1

Ze względu na kompletność, oto ogólne podejście do pobierania wartości wyliczenia według indeksu z dowolnego typu wyliczenia. Moim zamiarem było, aby metoda wyglądała i działała jak Enum.valueOf (Class, String) . Fyi, skopiowałem stąd tę metodę .

Nadal obowiązują kwestie związane z indeksem (już szczegółowo omówione tutaj).

/**
 * 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
źródło
To naprawdę nie jest to, czego szukam, ponieważ to pobiera wartości wyliczenia tylko według ich liczby porządkowej, a nie przez przypisany identyfikator całkowity (patrz moje pytanie). Ponadto, jeśli tego chcę, mogę po prostu użyć MyEnumType.values()- nie ma potrzeby stosowania statycznej metody pomocniczej.
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
źródło
0

Potrzebowałem czegoś innego, ponieważ chciałem zastosować podejście ogólne. Czytam wyliczenie do iz tablic bajtowych. Oto, co wymyśliłem:

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.
}
}

Przykład wyliczeń:

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
źródło
0

Tylko dlatego, że zaakceptowana odpowiedź nie jest samodzielna:

Kod pomocniczy:

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

Przykład użycia:

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
źródło
0

dany:

publiczne wyliczenie BonusType {MONTHLY (0), YEARLY (1), ONE_OFF (2)}

BonusType = YEARLY;

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

Wyjście: 1: ROCZNIE

David Urry
źródło
0

Jeśli masz samochód klasy

public class Car {
    private Color externalColor;
}

Właściwość Color jest klasą

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

I chcesz przekonwertować Color na Enum

public class CarDTO {
    private ColorEnum externalColor;
}

Po prostu dodaj metodę w klasie Color, aby przekonwertować Color na ColorEnum

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

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

a wewnątrz ColorEnum implementuje metodę getById ()

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

Teraz możesz użyć mapy klas

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
źródło