Bequeme Zuordnung zwischen enum und int / String


108

Bei der Arbeit mit Variablen / Parametern, die nur eine begrenzte Anzahl von Werten annehmen können, versuche ich, immer Java zu verwenden enum, wie in

public enum BonusType {
  MONTHLY, YEARLY, ONE_OFF
}

Solange ich in meinem Code bleibe, funktioniert das einwandfrei. Ich muss jedoch häufig eine Schnittstelle zu anderem Code herstellen, der einfache int(oder String) Werte für denselben Zweck verwendet, oder ich muss aus / in eine Datenbank lesen / schreiben, in der die Daten als Zahl oder Zeichenfolge gespeichert sind.

In diesem Fall hätte ich gerne eine bequeme Möglichkeit, jeden Aufzählungswert mit einer Ganzzahl zu verknüpfen, sodass ich beide Möglichkeiten konvertieren kann (mit anderen Worten, ich benötige eine "umkehrbare Aufzählung").

Von enum nach int zu wechseln ist einfach:

public enum BonusType {
  public final int id;

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

Dann kann ich auf den int-Wert als zugreifen BonusType x = MONTHLY; int id = x.id;.

Ich sehe jedoch keinen guten Weg für das Gegenteil, dh von int nach enum. Im Idealfall so etwas wie

BonusType bt = BonusType.getById(2); 

Die einzigen Lösungen, die ich finden könnte, sind:

  • Fügen Sie eine Suchmethode in die Aufzählung ein, die verwendet BonusType.values() eine Karte "int -> enum" gefüllt wird, speichern Sie diese dann zwischen und verwenden Sie sie für Suchvorgänge. Würde funktionieren, aber ich müsste diese Methode identisch in jede von mir verwendete Aufzählung kopieren :-(.
  • Fügen Sie die Suchmethode in eine statische Dienstprogrammklasse ein. Dann würde ich nur eine "Nachschlage" -Methode benötigen, aber ich müsste mit der Reflexion herumspielen, damit sie für eine beliebige Aufzählung funktioniert.

Beide Methoden scheinen für ein so einfaches (?) Problem furchtbar umständlich.

Irgendwelche anderen Ideen / Einsichten?


1
Ich <3 Java-Enums, aber ich hasse sie genau aus diesem Grund! Es scheint immer so, als wären sie perfekt, abgesehen von einem wirklich hässlichen Fehler ...
Chris Thompson

8
für enum-> int können Sie einfach verwendenordinal()
davin

1
Sind Ihre ID-Werte von Ihnen entscheidbar (dh können Sie sie nicht einfach verwenden .ordinal()) oder werden sie von externen Kräften festgelegt?
Paŭlo Ebermann

2
@davin: Ja, und lassen Sie Ihren Code brechen, sobald jemand die Enum-Deklaration neu anordnet oder einen Wert in der Mitte löscht. Ich fürchte, das ist keine robuste Lösung: - /.
Sleske

1
@davin mit "ordinal ()" sollte nach Möglichkeit vermieden werden, es ist in der Spezifikation der Sprache
DPM

Antworten:


37

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

Die Lösung beginnt ähnlich wie Ihre mit einem int-Wert als Teil der Aufzählungsdefinition. Anschließend erstellt er ein generikbasiertes Suchdienstprogramm:

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

Diese Lösung ist nett und erfordert kein "Fummeln mit Reflexion", da sie auf der Tatsache basiert, dass alle Aufzählungstypen implizit die Aufzählungsschnittstelle erben.


Verwendet dies nicht die Ordnungszahl? Sleske verwendet eine ID, nur weil sich die Ordnungszahl ändert, wenn die Aufzählungswerte neu angeordnet werden.
extraneon

Nein, es wird keine Ordnungszahl verwendet. Es basiert auf einem explizit definierten int-Wert. Dieser int-Wert wird als Zuordnungsschlüssel verwendet (von v.convert () zurückgegeben).
Jeff

2
Ich mag diese Lösung wirklich; Es scheint, dass dies das allgemeinste ist, das Sie bekommen können.
Sleske

+1. Mein einziger Hinweis ist, dass ich Numberanstelle von verwenden würde Byte, da mein Hintergrundwert möglicherweise größer ist.
Ivaylo Slavov

3
Lesen Sie die Frage wirklich und wahrhaftig. Wenn Sie mit einer Legacy-Datenbank oder einem externen System arbeiten, das Ganzzahlen definiert hat, die Sie nicht über Ihren eigenen Code weitergeben möchten, ist dies genau einer dieser Fälle. Die Ordnungszahl ist ein äußerst fragiler Weg, um den Wert einer Aufzählung aufrechtzuerhalten, und darüber hinaus ist sie in dem in der Frage genannten speziellen Fall nutzlos.
Jeff

327

Aufzählung → int

yourEnum.ordinal()

int → enum

EnumType.values()[someInt]

String → Aufzählung

EnumType.valueOf(yourString)

Aufzählung → Zeichenfolge

yourEnum.name()

Eine Randnotiz:
Wie Sie richtig hervorheben, ordinal()kann das von Version zu Version "instabil" sein. Dies ist der genaue Grund, warum ich Konstanten immer als Zeichenfolgen in meinen Datenbanken speichere. (Wenn ich MySql verwende, speichere ich sie tatsächlich als MySql-Aufzählungen !)


2
+1 Dies ist die offensichtlich richtige Antwort. Beachten Sie jedoch, dass es für valueOf eine einzige Argumentmethode gibt, die nur einen String akzeptiert und existiert, solange Sie den konkreten Aufzählungstyp (z. B. BonusType.valueOf("MONTHLY")) verwenden
Tim Bender,

18
Die Verwendung ordinal()scheint mir eine problematische Lösung zu sein, da sie unterbrochen wird, wenn die Liste der Enum-Werte neu angeordnet oder ein Wert gelöscht wird. Dies ist auch nur dann praktisch, wenn die int-Werte 0 ... n sind (was ich oft als nicht der Fall befunden habe).
Sleske

4
@sleske, wenn Sie anfangen, Konstanten zu löschen, haben Sie sowieso Probleme mit vorhandenen persistierten Daten. (Aktualisierte meine Antwort in dieser Hinsicht.)
Aioobe

3
Die Verwendung des values()Arrays funktioniert nur, wenn alle Ihre Werte für ihre ID auf 0 indiziert und der Reihe nach deklariert sind. (Getestet habe ich dies , dass zu überprüfen , ob Sie erklären , FOO(0), BAR(2), BAZ(1);dass values[1] == BARund values[2] == BAZtrotz der vergangen ids in.)
CORSIKA

2
@glowcoder, natürlich ist das Integer-Argument nur ein Feld im Enum-Objekt. Es hat nichts mit der Ordnungskonstante zu tun, die dem Enum-Objekt zugeordnet ist (es hätte genauso gut a sein können double).
Aioobe

29

Ich fand dies im Web, es war sehr hilfreich und einfach zu implementieren. Diese Lösung wurde NICHT von mir gemacht

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

}}


s / EnumSet.allOf (Status.class) /Status.values ​​()
Jelinson

8

Die Antworten auf diese Frage scheinen mit der Veröffentlichung von Java 8 veraltet zu sein.

  1. Verwenden Sie keine Ordnungszahl, da die Ordnungszahl instabil ist, wenn sie außerhalb der JVM, z. B. einer Datenbank, beibehalten wird.
  2. Es ist relativ einfach, eine statische Karte mit den Schlüsselwerten zu erstellen.

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

Sollte nicht der zweite Parameter von Collectors.toMap()sein Functions.identity()statt null?
Adam Michalik

Ja, ich habe dies aus einer Hilfsklasse übernommen, die ich mit Guave verwende und die Null in Identität umwandelt.
John Meyer

Das ist eine nette Verwendung der neuen Funktionen von Java 8. Es bedeutet jedoch immer noch, dass der Code in jeder Aufzählung wiederholt werden muss - und meine Frage war, diese (strukturell) wiederholte Boilerplate zu vermeiden.
Sleske

5

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

Um mir das Schreiben einer Menge Boilerplate-Code oder das Duplizieren von Code für jede Aufzählung zu ersparen, habe ich ValuedEnumstattdessen Apache Commons Langs verwendet.

Definition :

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

Verwendung:

int -> ValuedEnum:

NRPEPacketType packetType = 
 (NRPEPacketType) EnumUtils.getEnum(NRPEPacketType.class, 1);

Gute Idee, ich wusste nicht, dass es das gibt. Danke für das Teilen!
Keith P

3

Sie könnten vielleicht so etwas gebrauchen

interface EnumWithId {
    public int getId();

}


enum Foo implements EnumWithId {

   ...
}

Dies würde den Reflexionsbedarf in Ihrer Utility-Klasse verringern.


Können Sie ein Beispiel für die Verwendung dieses Snippets geben?
IgorGanapolsky

3

In diesem Code haben Sie für eine permanente und intensive Suche Speicher oder Prozess zur Verwendung, und ich wähle Speicher mit Konverter-Array als Index aus. Ich hoffe es ist hilfreich

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

2

Verwenden Sie eine Schnittstelle, um zu zeigen, wer der Boss ist.

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

Und das Ergebnis:

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>

1
Genau wie bei Turd Fergusons Antwort, das ist die unelegante Lösung, die ich vermeiden / verbessern möchte ...
Sleske

Normalerweise erstelle ich die umgekehrten Zuordnungen in einem statischen {} Block, um nicht jedes Mal, wenn ich nach einem Wert nach id frage, eine Schleife über values ​​() durchführen zu müssen. Normalerweise rufe ich auch die Methode valueOf (int) auf, damit sie der bereits für Strings vorhandenen valueOf (String) -Methode ähnelt (ebenfalls Teil der OP-Frage). Etwas wie Punkt 33 in Effective Java: tinyurl.com/4ffvc38
Fredrik

@Sleske Aktualisiert mit einer verfeinerten Lösung. @Fredrik interessant, obwohl ich bezweifle, dass die Iteration ein bedeutendes Problem sein wird.
CorsiKa

@glowcoder Wenn Sie nicht mehr als einmal iterieren müssen, spielt es keine Rolle, ob Sie es tausendmal pro Sekunde tun, wenn es ein sehr wichtiges Problem sein kann, oder es einfach zweimal aufrufen.
Fredrik

@Fredrik Ich gebe zu, es gibt Zeiten, in denen es notwendig sein kann, zu optimieren. Ich sage auch, dass Sie nicht darauf optimieren sollten, bis es sich um ein identifiziertes Leistungsproblem handelt.
CorsiKa

2

Sowohl die .ordinal()als auch values()[i]sind instabil, da sie von der Reihenfolge der Aufzählungen abhängen. Wenn Sie also die Reihenfolge der Aufzählungen ändern oder einige hinzufügen / löschen, wird Ihr Programm beschädigt.

Hier ist eine einfache, aber effektive Methode, um zwischen enum und int abzubilden.

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

Das Anwenden auf Saiten sollte nicht schwierig sein.


Ja, mir ist klar, dass ich das tun könnte - oder noch besser, eine Karte für die umgekehrte Suche verwenden, anstatt alle Werte zu durchlaufen. Ich erwähnte dies in meiner Frage, und ich erwähnte auch, dass ich nach einer besseren Lösung suche, um zu vermeiden, dass in jeder Aufzählung Boilerplate-Code enthalten ist.
Sleske

2

Ein sehr sauberes Anwendungsbeispiel für Reverse Enum

Schritt 1 Definieren Sie einen interfaceEnumConverter

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

Schritt 2

Erstellen Sie einen Klassennamen 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);
    }
}

Schritt 3

Gehen Sie zu Ihrer EnumKlasse und implementsie EnumConverter<ContentType>überschreiben und überschreiben natürlich die Schnittstellenmethoden. Sie müssen auch eine statische ReverseEnumMap initialisieren.

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

Schritt 4

Erstellen Sie nun eine CommunicationKlassendatei und rufen Sie die neue Methode zum Konvertieren von Enumnach Stringund Stringnach auf Enum. Ich habe gerade die Hauptmethode zur Erklärung angegeben.

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

Klicken Sie hier für eine vollständige Erklärung


1
Das gefällt mir wirklich sehr gut - ich habe seit einiger Zeit nach einer soliden Lösung für dieses Problem gesucht. Die einzige Änderung, die ich vorgenommen habe, war, ContentType convert(String pKey)statisch zu machen , wodurch die Notwendigkeit für die CommunicationKlasse entfällt und mehr nach meinem Geschmack war. +1
Chris Mantle

1

Ich bin nicht sicher, ob es in Java dasselbe ist, aber Aufzählungstypen in C werden automatisch auch Ganzzahlen zugeordnet, sodass Sie entweder den Typ oder die Ganzzahl verwenden können, um darauf zuzugreifen. Haben Sie schon versucht, einfach mit einer Ganzzahl darauf zuzugreifen?


2
Aufzählungen in Java verhalten sich nicht so. Sie sind ein expliziter Typ.
Chris Thompson

Jedes Enum-Objekt hätte eine interne Nummer (nämlich die Position, an der es deklariert wurde), auf die die .ordinal()Methode zugreifen kann. (Umgekehrt verwenden BonusType.values()[i].) In dem oben genannten Beispiel stimmen die Indizes hier und die äußeren Werte jedoch nicht überein.
Paŭlo Ebermann

1

Wirklich tolle Frage :-) Ich habe vor einiger Zeit eine ähnliche Lösung wie Mr.Ferguson verwendet. Unsere dekompilierte Aufzählung sieht folgendermaßen aus:

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

Dies zu sehen ist offensichtlich, warum ordinal()es instabil ist. Es ist das iin super(s, i);. Ich bin auch pessimistisch, dass Sie sich eine elegantere Lösung vorstellen können als die, die Sie bereits aufgezählt haben. Immerhin sind Aufzählungen Klassen wie alle Abschlussklassen.


1

Der Vollständigkeit halber ist hier ein allgemeiner Ansatz zum Abrufen von Aufzählungswerten nach Index von jedem Aufzählungstyp. Meine Absicht war es, die Methode wie Enum.valueOf (Class, String) aussehen zu lassen . Zu Ihrer Information, ich habe diese Methode von hier kopiert .

Indexbezogene Probleme (die hier bereits ausführlich erörtert wurden) gelten weiterhin.

/**
 * 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];
}

Das ist nicht wirklich das, wonach ich suche, da dies nur Enum-Werte anhand ihrer Ordnungszahl abruft, nicht anhand einer zugewiesenen Ganzzahl-ID (siehe meine Frage). Wenn ich das will, kann ich es auch einfach verwenden MyEnumType.values()- keine statische Hilfsmethode erforderlich.
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);
            }
        }

0

Ich brauchte etwas anderes, weil ich einen generischen Ansatz verwenden wollte. Ich lese die Aufzählung von und zu Byte-Arrays. Hier komme ich auf:

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

Beispiel für Aufzählungen:

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

0

Nur weil die akzeptierte Antwort nicht in sich geschlossen ist:

Support-Code:

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

Anwendungsbeispiel:

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

}

0

gegeben:

public enum BonusType {MONATLICH (0), JAHR (1), ONE_OFF (2)}

BonusType Bonus = JAHR;

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

Ausgabe: 1: JAHR


0

Wenn Sie eine Klasse haben Car

public class Car {
    private Color externalColor;
}

Und die Eigenschaft Farbe ist eine Klasse

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

Und Sie möchten Farbe in eine Aufzählung konvertieren

public class CarDTO {
    private ColorEnum externalColor;
}

Einfach ein Verfahren in hinzufügen Farbklasse zu konvertieren Farbe in ColorEnum

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

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

und implementiert in ColorEnum die Methode getById ()

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

Jetzt können Sie eine classMap verwenden

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);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.