Mapear convenientemente entre enum e int / String

108

Cuando trabajo con variables / parámetros que solo pueden tomar un número finito de valores, trato de usar siempre Java enum, como en

public enum BonusType {
  MONTHLY, YEARLY, ONE_OFF
}

Mientras permanezca dentro de mi código, eso funciona bien. Sin embargo, a menudo necesito interactuar con otro código que usa valores simples int(o String) para el mismo propósito, o necesito leer / escribir desde / hacia una base de datos donde los datos se almacenan como un número o cadena.

En ese caso, me gustaría tener una forma conveniente de asociar cada valor de enumeración con un número entero, de modo que pueda convertir en ambos sentidos (en otras palabras, necesito una "enumeración reversible").

Pasar de enum a int es fácil:

public enum BonusType {
  public final int id;

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

Entonces puedo acceder al valor int como BonusType x = MONTHLY; int id = x.id;.

Sin embargo, no veo una buena manera de lo contrario, es decir, pasar de int a enum. Idealmente, algo como

BonusType bt = BonusType.getById(2); 

Las únicas soluciones que se me ocurren son:

  • Ponga un método de búsqueda en la enumeración, que se usa BonusType.values()para llenar un mapa "int -> enum", luego lo almacena en caché y lo usa para búsquedas. Funcionaría, pero tendría que copiar este método de forma idéntica en cada enumeración que uso :-(.
  • Coloque el método de búsqueda en una clase de utilidad estática. Entonces solo necesitaría un método de "búsqueda", pero tendría que jugar con la reflexión para que funcione para una enumeración arbitraria.

Ambos métodos parecen terriblemente incómodos para un problema tan simple (?).

¿Alguna otra idea / conocimiento?

sleske
fuente
1
¡Tengo <3 enumeraciones de Java, pero las odio exactamente por esta razón! Siempre parece que son perfectos, aparte de un defecto realmente feo ...
Chris Thompson
8
para enum-> int solo puede usarordinal()
davin
1
¿Sus valores de identificación son decidibles por usted (es decir, no podría simplemente usarlos .ordinal()), o son decididos por fuerzas externas?
Paŭlo Ebermann
2
@davin: Sí, y haga que su código se rompa en el momento en que alguien reorganice la declaración de enumeración o elimine un valor en el medio. Me temo que esa no es una solución sólida: - /.
sleske
1
@davin usando "ordinal ()" debe evitarse siempre que sea posible, está en la especificación del lenguaje
DPM

Respuestas:

37

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

La solución comienza similar a la suya con un valor int como parte de la definición de enumeración. Luego pasa a crear una utilidad de búsqueda basada en genéricos:

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

Esta solución es agradable y no requiere 'jugar con la reflexión' porque se basa en el hecho de que todos los tipos de enumeración heredan implícitamente la interfaz Enum.

Jeff
fuente
¿No usa esto el ordinal? Sleske usa una identificación solo porque el ordinal cambia cuando los valores de enumeración se reordenan.
extraneon
No, no usa ordinal. Se basa en un valor int explícitamente definido. Ese valor int se usa como la clave del mapa (devuelto por v.convert ()).
Jeff
2
Realmente me gusta esta solución; parece que esto es lo más general que puede obtener.
sleske
+1. Mi única nota es que usaría en Numberlugar de Byte, porque mi valor de respaldo podría ser mayor en tamaño.
Ivaylo Slavov
3
Real y verdaderamente lea la pregunta. Si está tratando con una base de datos heredada o un sistema externo que tiene números enteros definidos que no desea propagar a través de su propio código, este es exactamente uno de esos casos. El ordinal es una forma extremadamente frágil de conservar el valor de una enumeración, y más allá de eso, es inútil en el caso específico mencionado en la pregunta.
Jeff
327

enum → int

yourEnum.ordinal()

int → enum

EnumType.values()[someInt]

Cadena → enumeración

EnumType.valueOf(yourString)

enum → Cadena

yourEnum.name()

Una nota al margen:
como señala correctamente, ordinal()puede ser "inestable" de una versión a otra. Esta es la razón exacta por la que siempre almaceno constantes como cadenas en mis bases de datos. (¡En realidad, cuando uso MySql, los guardo como enumeraciones de MySql !)

aioobe
fuente
2
+1 Esta es la respuesta correcta obvia. Sin embargo, tenga en cuenta que hay un método de argumento único para valueOf que solo toma una cadena y existe siempre que esté utilizando el tipo de enumeración concreto (por ejemplo BonusType.valueOf("MONTHLY"))
Tim Bender
18
El uso ordinal()me parece una solución problemática, porque se romperá cuando se reorganice la lista de valores de enumeración o se elimine un valor. Además, esto solo es práctico si los valores int son 0 ... n (que a menudo he descubierto que no es el caso).
sábado
4
@sleske, si comienza a eliminar constantes, de todos modos tiene problemas con los datos persistentes existentes. (
Actualicé
3
El uso de la values()matriz solo funcionará si todos sus valores están indexados en 0 para su identificación y se declaran en orden. (He probado esto para verificar que si se declara FOO(0), BAR(2), BAZ(1);que values[1] == BAR, y values[2] == BAZpese a los identificadores se ha pasado.)
corsiKa
2
@glowcoder, bueno, por supuesto, el argumento entero es simplemente un campo en el objeto enum. No tiene nada que ver con la constante ordinal asociada con el objeto enum (bien podría haber sido a double).
aioobe
29

Encontré esto en la web, fue muy útil y simple de implementar. Esta solución NO fue hecha por mí.

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
fuente
s / EnumSet.allOf (Status.class) /Status.values ​​()
jelinson
8

Parece que las respuestas a esta pregunta están desactualizadas con el lanzamiento de Java 8.

  1. No use ordinal ya que ordinal es inestable si persiste fuera de la JVM, como una base de datos.
  2. Es relativamente fácil crear un mapa estático con los valores clave.

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
fuente
No debería el segundo parámetro de Collectors.toMap()estar Functions.identity()en lugar de null?
Adam Michalik
sí, adopté esto de una clase auxiliar que uso con guayaba que convierte nulo en identidad.
John Meyer
Ese es un buen uso de las nuevas funciones de Java 8. Sin embargo, todavía significa que el código tendría que repetirse en cada enumeración, y mi pregunta era sobre cómo evitar esta repetición (estructuralmente) repetida.
sábado
5

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

Para ahorrarme escribir un montón de código repetitivo o duplicar código para cada Enum, utilicé Apache Commons Lang's ValuedEnum lugar.

Definición :

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

Uso:

int -> ValuedEnum:

NRPEPacketType packetType = 
 (NRPEPacketType) EnumUtils.getEnum(NRPEPacketType.class, 1);
Alastair McCormack
fuente
Buena idea, no me di cuenta de que esto existía. ¡Gracias por compartir!
Keith P
3

Quizás podrías usar algo como

interface EnumWithId {
    public int getId();

}


enum Foo implements EnumWithId {

   ...
}

Eso reduciría la necesidad de reflexionar en su clase de servicios públicos.

extraneón
fuente
¿Puede dar un ejemplo de cómo utilizar este fragmento?
IgorGanapolsky
3

En este código, para una búsqueda permanente e intensa, tengo memoria o proceso para usar, y selecciono memoria, con array convertidor como índice. Espero que sea de ayuda

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]];
}
}
Sebastián Sgo Acevedo
fuente
2

Usa una interfaz para mostrarle quién manda.

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

Y el resultado:

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
fuente
1
Al igual que con la respuesta de Turd Ferguson, esa es la solución poco elegante que me gustaría evitar / mejorar ...
sleske
Por lo general, creo las asignaciones inversas en un bloque {} estático para no tener que recorrer los valores () cada vez que solicito un valor por id. También suelo llamar al método valueOf (int) para que se parezca al método valueOf (String) que ya existe para Strings (también parte de la pregunta del OP). Algo parecido al elemento 33 en Java efectivo: tinyurl.com/4ffvc38
Fredrik
@Sleske Actualizado con una solución más refinada. @Fredrik es interesante, aunque dudo que la iteración sea un problema importante.
corsiKa
@glowcoder Bueno, no tener que iterar más de una vez significa que no importa si lo hace mil veces por segundo, donde puede ser un problema muy importante o simplemente llamarlo dos veces.
Fredrik
@Fredrik Admito que hay momentos en los que puede ser necesario optimizar. También digo que hasta que no se identifique un problema de rendimiento, no lo optimices.
corsiKa
2

Tanto el .ordinal()comovalues()[i] son inestables ya que dependen del orden de enumeraciones. Por lo tanto, si cambia el orden de las enumeraciones o agrega / elimina algunas, su programa se romperá.

Aquí hay un método simple pero efectivo para mapear entre enum e 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");
    }
}

Aplicarlo para cuerdas no debería ser difícil.

hrzafer
fuente
Sí, me doy cuenta de que podría hacer eso, o mejor aún, usar un mapa para la búsqueda inversa, en lugar de recorrer todos los valores. Mencioné esto en mi pregunta y también mencioné que estoy buscando una mejor solución, para evitar tener un código repetitivo en cada enumeración.
sleske
2

Un ejemplo de uso muy limpio de Enum inverso

Paso 1 Definir un interfaceEnumConverter

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

Paso 2

Crear un nombre de clase 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);
    }
}

Paso 3

Vaya a su Enumclase y implement, por EnumConverter<ContentType>supuesto, anule los métodos de interfaz. También necesita inicializar un ReverseEnumMap estático.

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

Paso 4

Ahora cree un Communicationarchivo de clase y llamar a su nuevo método para convertir una Enuma Stringy Stringa Enum. Acabo de poner el método principal con fines explicativos.

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

Haga clic para obtener una explicación completa

ARIZONA_
fuente
1
Esto me gusta mucho, mucho: he estado buscando una solución sólida a este problema desde hace algún tiempo. El único cambio que hice fue hacer ContentType convert(String pKey)estática, lo que elimina la necesidad de la Communicationclase y fue más de mi agrado. +1
Chris Mantle
1

No estoy seguro de si es lo mismo en Java, pero los tipos de enumeración en C también se asignan automáticamente a números enteros, por lo que puede usar el tipo o el entero para acceder a él. ¿Ha intentado simplemente acceder a él con un número entero?

Detra83
fuente
2
Las enumeraciones en Java no se comportan de esa manera. Son un tipo explícito.
Chris Thompson
Cada objeto enum tendría un número interno (es decir, la posición en la que fue declarado), y el .ordinal()método puede acceder a él . (De otra manera, use BonusType.values()[i]). Pero en el ejemplo citado anteriormente, los índices aquí y los valores externos no coinciden.
Paŭlo Ebermann
1

Realmente una gran pregunta :-) Usé una solución similar a la del señor Ferguson hace algún tiempo. Nuestra enumeración descompilada se ve así:

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

Al ver esto, es evidente por qué ordinal()es inestable. Es el iin super(s, i);. También soy pesimista de que pueda pensar en una solución más elegante que las que ya enumeró. Después de que todas las enumeraciones son clases como cualquier clase final.

Lachezar Balev
fuente
1

En aras de la integridad, aquí hay un enfoque genérico para recuperar valores de enumeración por índice de cualquier tipo de enumeración. Mi intención era hacer que el método se viera y se sintiera como Enum.valueOf (Class, String) . Fyi, copié este método de aquí .

Los problemas relacionados con el índice (ya discutidos en profundidad aquí) todavía se aplican.

/**
 * 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];
}
whiskyysierra
fuente
Eso no es realmente lo que estoy buscando, ya que esto solo recupera valores de enumeración por su ordinal, no por una identificación entera asignada (vea mi pregunta). Además, si quiero eso, puedo usarlo MyEnumType.values(), sin necesidad de un método auxiliar estático.
sábado
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
fuente
0

Necesitaba algo diferente porque quería usar un enfoque genérico. Estoy leyendo la enumeración hacia y desde matrices de bytes. Aquí es donde se me ocurre:

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

Ejemplo de enumeraciones:

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
fuente
0

Solo porque la respuesta aceptada no es autónoma:

Código de soporte:

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

Ejemplo de uso:

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
fuente
0

dado:

enumeración pública BonusType {MONTHLY (0), YEARLY (1), ONE_OFF (2)}

BonusType bonus = YEARLY;

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

Salida: 1: ANUAL

David Urry
fuente
0

Si tienes un auto de clase

public class Car {
    private Color externalColor;
}

Y la propiedad Color es una clase

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

Y quieres convertir Color a Enum

public class CarDTO {
    private ColorEnum externalColor;
}

Simplemente agregue un método en la clase Color para convertir Color en ColorEnum

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

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

y dentro de ColorEnum implementa el método getById ()

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

Ahora puedes usar 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
fuente