Зручно карта між enum та int / String


108

Працюючи зі змінними / параметрами, які можуть приймати лише обмежену кількість значень, я намагаюся завжди використовувати Java enum, як в

public enum BonusType {
  MONTHLY, YEARLY, ONE_OFF
}

Поки я залишаюся всередині свого коду, це працює чудово. Однак мені часто потрібно взаємодіяти з іншим кодом, який використовує звичайні int(або String) значення з тією ж метою, або мені потрібно читати / записувати з / в базу даних, де дані зберігаються у вигляді числа або рядка.

У такому випадку я хотів би мати зручний спосіб пов'язувати кожне значення перерахунку з цілим числом, таким чином, щоб я міг перетворити обидва способи (іншими словами, мені потрібна "оборотна enum").

Перехід від enum до int легко:

public enum BonusType {
  public final int id;

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

Тоді я можу отримати доступ до значення int як BonusType x = MONTHLY; int id = x.id;.

Однак я не бачу жодного приємного способу для реверсу, тобто переходу від int до enum. В ідеалі щось подібне

BonusType bt = BonusType.getById(2); 

Єдині рішення, які я міг придумати, це:

  • Помістіть метод enum в enum, який використовує BonusType.values()для заповнення карти "int -> enum", а потім кешує це і використовує його для пошуку. Було б спрацювати, але я повинен був би скопіювати цей метод однаково у кожен перелік, який я використовую :-(
  • Помістіть метод пошуку в статичний клас корисності. Тоді мені знадобився б лише один метод "пошуку", але мені доведеться поспішати з роздумом, щоб змусити його працювати для довільного перерахунку.

Обидва методи здаються страшенно незручними для такої простої (?) Проблеми.

Будь-які інші ідеї / уявлення?


1
Я <3 java перераховує, але ненавиджу їх саме з цієї причини! Завжди здається, що вони ідеально вбік від однієї по-справжньому потворної вади ...
Кріс Томпсон,

8
for enum-> int ви можете просто скористатисяordinal()
davin

1
Чи ваші id-значення визначаються вами (значить, ви не могли просто використовувати .ordinal()), або їх вирішили сторонні сили?
Paŭlo Ebermann

2
@davin: Так, і ваш код порушить момент, коли хтось переставить декларацію перерахунку або видалить значення посередині. Боюся, це не надійне рішення: - /.
sleske

1
@davin використання "ordinal ()" слід уникати, коли це можливо, це в специфікації мови
DPM

Відповіді:


37

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

Рішення починається аналогічно вашому зі значенням int як частини визначення enum. Потім він продовжує створювати утиліту пошуку на основі дженерики:

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

Це рішення є приємним і не вимагає «зіткнення з рефлексією», оскільки воно засноване на тому, що всі типи enum неявно успадковують інтерфейс Enum.


Це не використовує порядкового? Sleske використовує ідентифікатор лише тому, що порядкові зміни змінюються, коли значення перерахунків переставляються.
екстранеон

Ні, він не використовує порядкових. Він спирається на явно визначене значення int. Це значення int використовується як ключ карти (повертається v.convert ()).
Джефф

2
Мені дуже подобається таке рішення; здається, це найзагальніше, що можна отримати.
sleske

+1. Єдине моє зауваження - це те, що я б використовував Numberзамість цього Byte, тому що моє значення резервного копіювання може бути більшим за розміром.
Івайло Славов

3
Дійсно і справді прочитайте питання. Якщо ви маєте справу зі спадковою базою даних або зовнішньою системою, яка визначає цілі числа, які ви не хочете поширювати через власний код, то це саме один із таких випадків. Порядок є надзвичайно крихким способом зберегти значення перерахунку, і поза цим він марний у конкретному випадку, про який йдеться у питанні.
Джефф

327

enum → int

yourEnum.ordinal()

int → enum

EnumType.values()[someInt]

Рядок → перерахунок

EnumType.valueOf(yourString)

enum → Рядок

yourEnum.name()

Побічна примітка:
Як ви правильно зазначаєте, вона ordinal()може бути "нестабільною" від версії до версії. Це точно причина, чому я завжди зберігаю константи як рядки у своїх базах даних. (Насправді, під час використання MySql, я зберігаю їх як MySql перераховує !)


2
+1 Це очевидно правильна відповідь. Зауважте, що існує метод єдиного аргументу для valueOf, який займає лише рядок і існує до тих пір, поки ви використовуєте тип конкретного перерахунку (наприклад BonusType.valueOf("MONTHLY"))
Тім Бендер,

18
Використання ordinal()вважає мене проблематичним рішенням, оскільки воно порушиться, коли перелік значень перерахувань буде переставлений або вилучено значення. Крім того, це практично лише в тому випадку, якщо значення int дорівнюють 0 ... n (що я часто виявляв, що це не так).
sleske

4
@sleske, якщо ви почнете видаляти константи, ви все одно зіткнулися з наявними збереженими даними. (Оновлено мою відповідь з цього приводу.)
aioobe

3
Використання values()масиву буде працювати лише в тому випадку, якщо всі ваші значення 0 індексуються для їх ідентифікатора та оголошені в порядку. (Я перевірив це, щоб переконатися, що якщо ви заявляєте про FOO(0), BAR(2), BAZ(1);це, values[1] == BARі values[2] == BAZнезважаючи на передані ідентифікатори.)
corsiKa

2
@glowcoder, звичайно, цілий аргумент - це просто поле в enum-об'єкті. Це не має нічого спільного з порядковою постійною, пов'язаною з об'єктом enum (це могло так само бути double).
aioobe

29

Я знайшов це в Інтернеті, це було дуже корисно і просто втілити в життя. Це рішення НЕ було прийнято мною

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

Здається, відповіді на це питання застаріли з виходом Java 8.

  1. Не використовуйте порядковий номер, оскільки порядковий номер нестабільний, якщо він зберігається поза JVM, наприклад, база даних.
  2. Створити статичну карту з ключовими значеннями порівняно просто.

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

Чи не повинен другий параметр Collectors.toMap()бути Functions.identity()замість null?
Адам Міхалик

так, я прийняв це з класу помічників, який я використовую з guava, який перетворює нуль в ідентичність.
Джон Мейєр

Це акуратне використання нових функцій Java 8. Однак це все ще означає, що код доведеться повторювати в кожному переліку - і моє запитання стосувалось уникнення цього (структурно) повторного котла.
sleske

5

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

Щоб заощадити мені писати набір кодового шаблону або дублюючий код для кожного Enum, я використав ValuedEnumзамість Apache Commons Lang .

Визначення :

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

Використання:

int -> ValuedEnum:

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

Хороша ідея, я не усвідомлював, що це існує. Дякую, що поділились!
Кіт П

3

Можливо, ви можете використати щось подібне

interface EnumWithId {
    public int getId();

}


enum Foo implements EnumWithId {

   ...
}

Це зменшило б потребу в рефлексії у вашому класі корисності.


Чи можете ви навести приклад того, як використовувати цей фрагмент?
ІгорГанапольський

3

У цьому коді для постійного та інтенсивного пошуку є пам'ять або процес для використання, і я вибираю пам'ять з масивом перетворювача як індекс. Я сподіваюся, що це корисно

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

Використовуйте інтерфейс, щоб показати, хто це начальник.

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

І результат:

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
Так само, як і у відповіді Турда Фергюсона, це не елегантне рішення, яке я хотів би уникнути / покращити ...
sleske

Зазвичай я створюю зворотні відображення в статичному блоці {}, щоб не потрібно перебирати значення () щоразу, коли я запитую значення за id. Я також зазвичай називаю метод valueOf (int), щоб він виглядав дещо схожим на метод valueOf (String), який вже існує для Strings (також частина запитання ОП). Дещо схожий на предмет 33 в Ефективній Java: tinyurl.com/4ffvc38
Фредрік

@Sleske Оновлено більш вдосконаленим рішенням. @Fredrik цікавий, хоча я сумніваюся, що ітерація буде важливою проблемою.
corsiKa

@glowcoder Добре, що не потрібно повторювати більше одного разу, це не має значення, чи будете ви робити це тисячу разів за секунду, де це може бути дуже важливою проблемою або просто зателефонувати двічі.
Фредрік

@Fredrik Я визнаю, є періоди, коли може знадобитися оптимізувати. Я також говорю, що поки не буде визначено проблему ефективності, не оптимізуйте її.
corsiKa

2

І те, .ordinal()і values()[i]нестійке, оскільки залежать від порядку перерахунків. Таким чином, якщо ви зміните порядок перерахунків або додаєте / видалите, частина вашої програми порушиться.

Ось простий, але ефективний метод для відображення між enum та 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");
    }
}

Застосовувати його для рядків не повинно бути складно.


Так, я розумію, що міг би це зробити - а ще краще - використовувати карту для зворотного пошуку, а не повторювати всі значення. Я згадував про це у своєму запитанні, а також зазначив, що шукаю кращого рішення, щоб уникнути наявності кодового коду у кожному переліку.
sleske

2

Дуже чистий приклад використання зворотного Enum

Крок 1 Визначте interfaceEnumConverter

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

Крок 2

Створіть назву класу 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);
    }
}

Крок 3

Перейти до вас Enumклас і implementце з EnumConverter<ContentType>і методів корекції інтерфейсу курсу. Вам також потрібно ініціалізувати статичну 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);
    }
}

Крок 4

Тепер створіть Communicationфайл класу і зателефонуйте, що це новий метод для перетворення Enumв Stringі Stringв Enum. Я щойно поставив основний метод для пояснення.

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

Клацніть для повного пояснення


1
Це мені дуже, дуже подобається - я вже деякий час шукаю міцного рішення цієї проблеми. Єдина зміна, яку я вніс, полягала в тому, щоб зробити ContentType convert(String pKey)статичну, що знімає потребу в Communicationкласі і мені більше подобалось. +1
Кріс Мантл

1

Я не впевнений, чи однаково це в Java, але типи перерахувань у C автоматично відображаються на цілі числа, щоб ви могли використовувати або тип, або ціле число для доступу до нього. Ви спробували просто отримати доступ до нього з цілим числом?


2
Енуми на Java не так поводяться. Вони явний тип.
Кріс Томпсон

Кожен об’єкт перерахунку мав би внутрішній номер (а саме положення, в якому він був оголошений), і до нього можна отримати доступ .ordinal()методом. (Інший спосіб, використовуйте BonusType.values()[i].) Але у наведеному вище прикладі індекси та зовнішні значення не збігаються.
Paŭlo Ebermann

1

Дійсно чудове запитання :-) Я використовував рішення, подібне до пана Фергюсона колись тому. Наш декомпільований перелік виглядає так:

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

Побачивши це, очевидно, чому ordinal()це нестабільно. Саме iв super(s, i);. Я також песимістичний, що ви можете придумати більш елегантне рішення, ніж ви вже перелічили. Адже перерахунки - це класи, як і будь-які заключні класи.


1

Для повноти тут є загальний підхід до отримання значень перерахунків за індексом з будь-якого типу перерахунків. Мій намір полягав у тому, щоб зробити метод схожим на Enum.valueOf (Class, String) . Fyi, я скопіював цей метод звідси .

Проблеми, пов’язані з індексом (тут уже детально обговорювались), все ще застосовуються

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

Це насправді не те, що я шукаю, оскільки це витягує лише значення перерахунків за порядковим, а не за призначеним цілим ідентифікатором (див. Моє запитання). Крім того, якщо я цього хочу, я можу просто використовувати MyEnumType.values()- немає необхідності в статичному методі помічника.
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

Мені потрібно було щось інше, тому що я хотів використовувати загальний підхід. Я читаю перерахунки до і з байтових масивів. Ось де я придумав:

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

Приклад перерахунків:

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

Просто тому, що прийнята відповідь не міститься в собі:

Код підтримки:

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

Приклад використання:

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

дано:

Тип публічного перерахунку BonusType {MONTHLY (0), YEARLY (1), ONE_OFF (2)}

BonusType bonus = РОКІВ;

System.out.println (bonus.Ordinal () + ":" + бонус)

Вихід: 1: РОКІВ


0

Якщо у вас автомобіль класу

public class Car {
    private Color externalColor;
}

А властивість Color - це клас

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

І ви хочете перетворити Color в Enum

public class CarDTO {
    private ColorEnum externalColor;
}

Просто додайте метод у класі кольорів для перетворення Color у ColorEnum

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

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

і всередині ColorEnum реалізує метод getById ()

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

Тепер ви можете використовувати 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);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.