web-dev-qa-db-fra.com

Comment convertir une enum en une autre en java?

J'ai;

public enum Detailed {
    PASSED, INPROCESS, ERROR1, ERROR2, ERROR3;
}

et besoin de le convertir au suivant;

public enum Simple {
    DONE, RUNNING, ERROR;
}

Donc d'abord PASSED-> DONE et INPROCESS-> RUNNING, mais toutes les erreurs devraient être: ERROR. De toute évidence, il est possible d'écrire des observations pour toutes les valeurs, mais il pourrait y avoir une meilleure solution?

24
user710818

Une solution consiste à définir une méthode asSimple() dans votre Detailed enum:

public enum Detailed {
    PASSED {
        @Override
        Simple asSimple() {
            return PASSED;
        }
    },
    INPROCESS {
        @Override
        Simple asSimple() {
            return RUNNING;
        }
    },
    ERROR1,
    ERROR2,
    ERROR3;
    public Simple asSimple() {
        return Simple.ERROR; // default mapping
    }
}

Vous pouvez ensuite simplement appeler la méthode lorsque vous souhaitez effectuer le mappage:

Detailed code = . . .
Simple simpleCode = code.asSimple();

Il a l'avantage de mettre la connaissance de la cartographie avec l'enumération Detailed (où elle appartient peut-être). Il a pour inconvénient d’avoir la connaissance de Simple mélangée au code de Detailed. Cela peut ou peut ne pas être une mauvaise chose, selon l'architecture de votre système.

23
Ted Hopp

Personnellement, je créerais simplement un Map<Detailed, Simple> et le ferais explicitement - ou même utiliser potentiellement une instruction switch.

Une autre alternative serait de passer le mappage au constructeur - vous ne pouvez le faire que dans un sens, bien sûr:

public enum Detailed {
    PASSED(Simple.DONE),
    INPROCESS(Simple.RUNNING),
    ERROR1(Simple.ERROR),
    ERROR2(Simple.ERROR),
    ERROR3(Simple.ERROR);

    private final Simple simple;

    private Detailed(Simple simple) {
        this.simple = simple;
    }

    public Simple toSimple() {
        return simple;
    }
}

(Je trouve cela plus simple que l'approche de Ted consistant à utiliser le polymorphisme, car nous n'essayons pas vraiment de fournir un comportement différent behavior - juste un mappage simple différent.)

Tandis que vous pourriez potentiellement faire quelque chose de rusé avec la valeur ordinale, ce serait beaucoup moins évident, et prendre plus de code - je ne pense pas qu'il y aurait aucun avantage.

22
Jon Skeet

Utilisez EnumMap

Je dissocie mon interface XML externe de mon modèle de domaine interne en implémentant un service de transformation. Cela inclut la correspondance des énumérations du code généré par jaxb avec les énumérations de modèle de domaine.

L'utilisation d'un objet EnumMap statique résume le problème de la transformation dans la classe responsable de la transformation. Sa cohésion. 

@Service
public class XmlTransformer {

    private static final Map<demo.xml.Sense, Constraint.Sense> xmlSenseToSense;
    static {
        xmlSenseToSense = new EnumMap<demo.xml.Sense, Constraint.Sense> (
            demo.xml.Sense.class);
        xmlSenseToSense.put(demo.xml.planningInterval.Sense.EQUALS, 
            Constraint.Sense.EQUALS);
        xmlSenseToSense.put(demo.xml.planningInterval.Sense.GREATER_THAN_OR_EQUALS, 
            Constraint.Sense.GREATER_THAN_OR_EQUALS);
        xmlSenseToSense.put(demo.xml.planningInterval.Sense.LESS_THAN_OR_EQUALS, 
            Constraint.Sense.LESS_THAN_OR_EQUALS);
    }
    ...
}
8
Chomeh

La réponse de Ted est très Javaly, mais l'expression

passed == PASSED ? DONE : ERROR

ferait le travail aussi.

1
tiwo

Pour moi, cela ressemble plus à un problème conceptuel qu’à un problème de programmation. Pourquoi ne vous contentez-vous pas de supprimer le type "Simple" et d'utiliser l'autre à la place du programme?

Pour clarifier cela avec un autre exemple: Voulez-vous vraiment définir un type d’énum pour les jours de travail de la semaine (du lundi au vendredi) et un autre enum pour tous les jours de la semaine (du lundi au dimanche)?

0
Bananeweizen

Enums.getIfPresent() de Guava sur Enum.name()

Notre cas était une spécialisation particulière de celui-ci. Nous avons deux Enum: un que nous utilisons dans l’application et un autre que nous utilisons dans la bibliothèque principale. La bibliothèque principale est utilisée par une poignée d'applications, par différentes équipes. Chaque application affiche un sous-ensemble de toutes les fonctionnalités. Toute la fonctionnalité est configurée avec les énumérations afin d’allumer et d’éteindre, d’accélérer ou de réduire les vitesses, de sélectionner des stratégies, etc.

Nous nous sommes donc retrouvés avec:

  1. une énumération pour la bibliothèque, contenant toutes les configurations possibles, visibles depuis les applications, ainsi que certaines spécificités
  2. une énumération pour chaque application, contenant les littéraux correspondant à ce que l’application peut voir/toucher dans la bibliothèque, et certaines spécifiques à l’application

Ensuite, lorsque nous transmettons des données à la bibliothèque, nous adaptons toutes les données et également ces configurations. Nous possédons tous les enums, nous pouvons donc choisir d'appeler la même configuration avec le même littéral dans des enums différents.

Enum LibraryConfig {
    FUNCTION_ONE,
    FUNCTION_TWO,
    FUNCTION_THREE,
    FUNCTION_FOUR;
}

Enum Aplication1Config {
    FUNCTION_ONE,
    FUNCTION_TWO,
    FUNCTION_THREE,
    APPL1_FUNCTION_ONE,
    APPL1_FUNCTION_TWO;
}

Enum Aplication2Config {
    FUNCTION_ONE,
    FUNCTION_TWO,
    FUNCTION_FOUR;
    APPL2_FUNCTION_ONE;
}

Lorsque nous devons convertir un type en un autre (app -> lib ou lib -> app), nous utilisons la méthode getIfPresent() de com.google.common.base.Enums de cette façon:

Aplication1Config config1App1 = FUNCTION_TWO;
LibraryConfig configLib = Enums.getIfPresent(LibraryConfig.class, config1App1.name()).orNull();

Nous vérifions configLib pour null valeur pour voir si la conversion a réussi. Cette dernière étape est utilisée pour APPX_FUNCTION_YYY, qui sont spécifiques à l'application, et pour la conversion dans le sens lib -> app, afin de ne pas transmettre les valeurs de configuration spécifiques à la bibliothèque (FUNCTION_FOUR dans l'exemple).

gestion de la dépendance de maven:

Juste au cas où quelqu'un en aurait besoin:

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>20.0</version>
    </dependency>

Version maison:

Vous pouvez effectuer votre propre conversion à l'aide des méthodes Enum, mais vous devez vous occuper de l'exception pour détecter le moment où la conversion a échoué:

try {
    Aplication1Config config1App1 = FUNCTION_TWO;
    LibraryConfig configLib = LibraryConfig.valueOf(config1App1.name());
} catch (IllegalArgumentException iae) {
    // if the conversion did not succeed
}
0
manuelvigarcia

Voici le mappeur enum simple avec test:

-- LA MISE EN OEUVRE

- ENUMS

public enum FirstEnum {

A(0), B(1);

private final int value;

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

public int getValue() {
    return value;
}
}

public enum  SecondEnum {

C(0), D(1);

private final int valueId;

private SecondEnum(int valueId) {
    this.valueId = valueId;
}

public int getValueId() {
    return valueId;
}

}

--MAPPER

import Java.lang.reflect.InvocationTargetException;
import Java.util.HashMap;
import Java.util.Map;

import org.Apache.commons.beanutils.PropertyUtils;
import org.Apache.commons.lang3.Validate;

import com.google.common.collect.Sets;

public class EnumPropertyMapping {

private final Map<?, ?> firstMap;
private final Map<?, ?> secondMap;

private final Class<?> firstType;
private final Class<?> secondType;

private EnumPropertyMapping(
        Map<?, ?> firstMap, Map<?, ?> secondMap, Class<?> firstType, Class<?> secondType) {

    this.firstMap = firstMap;
    this.secondMap = secondMap;
    this.firstType = firstType;
    this.secondType = secondType;
}

public static Builder builder() {
    return new Builder();
}

@SuppressWarnings("unchecked")
public <R> R getCorrespondingEnum(Object mappedEnum) {
    Validate.notNull(mappedEnum, "Enum must not be NULL");
    Validate.isInstanceOf(Enum.class, mappedEnum, "Parameter must be an Enum");

    if (firstType.equals(mappedEnum.getClass())) {
        return (R) firstMap.get(mappedEnum);
    }

    if (secondType.equals(mappedEnum.getClass())) {
        return (R) secondMap.get(mappedEnum);
    }

    throw new IllegalArgumentException("Didn't found mapping for enum value: " + mappedEnum);
}

public static class Builder {

    private final Map<Object, Object> firstEnumMap = new HashMap<>();
    private final Map<Object, Object> secondEnumMap = new HashMap<>();
    private Class<?> firstEnumType;
    private Class<?> secondEnumType;

    public <T extends Enum<T>> Builder addFirst(Class<T> enumType, String propertyName) {
        firstEnumType = enumType;
        initMap(firstEnumMap, enumType.getEnumConstants(), propertyName);
        return this;
    }

    public <T extends Enum<T>> Builder addSecond(Class<T> enumType, String propertyName) {
        secondEnumType = enumType;
        initMap(secondEnumMap, enumType.getEnumConstants(), propertyName);
        return this;
    }

    private void initMap(Map<Object, Object> enumMap, Object[] enumConstants, String propertyName) {
        try {
            for (Object constant : enumConstants) {
                enumMap.put(PropertyUtils.getProperty(constant, propertyName), constant);
            }
        } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException ex) {
            throw new IllegalStateException(ex);
        }
    }

    public EnumPropertyMapping mapEnums() {
        Validate.isTrue(firstEnumMap.size() == secondEnumMap.size());
        Validate.isTrue(Sets.difference(firstEnumMap.keySet(), secondEnumMap.keySet()).isEmpty());

        Map<Object, Object> mapA = new HashMap<>();
        Map<Object, Object> mapB = new HashMap<>();

        for (Map.Entry<Object, Object> obj : firstEnumMap.entrySet()) {
            Object secondMapVal = secondEnumMap.get(obj.getKey());
            mapA.put(obj.getValue(), secondMapVal);
            mapB.put(secondMapVal, obj.getValue());
        }
        return new EnumPropertyMapping(mapA, mapB, firstEnumType, secondEnumType);
    }
}

}

- TEST

import org.junit.Test;

import com.bondarenko.common.utils.lang.enums.FirstEnum;
import com.bondarenko.common.utils.lang.enums.SecondEnum;

import static junit.framework.TestCase.assertEquals;

public class EnumPropertyMappingTest {

@Test
public void testGetMappedEnum() {
    EnumPropertyMapping mapping = EnumPropertyMapping.builder()
                                                                                                     .addSecond(SecondEnum.class, "valueId")
                                                                                                     .addFirst(FirstEnum.class, "value")
                                                                                                     .mapEnums();

    assertEquals(SecondEnum.D, mapping.getCorrespondingEnum(FirstEnum.B));
    assertEquals(FirstEnum.A, mapping.getCorrespondingEnum(SecondEnum.C));
}

}
0
Yurii Bondarenko