2012-06-18 50 views
19

Tengo;¿Cómo convertir un enum a otro enum en java?

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

y necesita convertirlo en lo siguiente;

public enum Simple { 
    DONE, RUNNING, ERROR; 
} 

Así primeros PASSED ->DONE y INPROCESS ->RUNNING, pero todos los errores deben ser: ERROR. Obviamente, es posible escribir casos para todos los valores, pero puede haber una mejor solución.

Respuesta

19

Una forma es definir un método asSimple() en su Detailed enumeración:

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

continuación, puede simplemente llamar al método cuando se quiere hacer el mapeo:

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

Tiene la ventaja de poner el conocimiento del mapeo con la enumeración Detailed (donde quizás pertenece). Tiene la desventaja de tener conocimiento de Simple mezclado con el código para Detailed. Esto puede o no ser malo, dependiendo de la arquitectura de su sistema.

+2

Creo que poner la lógica de mapeo dentro de una enumeración a otra enumeración es romper la encapsulación, introducir el acoplamiento y reducir la cohesión. La preocupación de una enumeración debe ser simplemente representar un conjunto de estados (o conceptos). La preocupación de mapear de una enumeración a otra debe encapsularse por separado. – Chomeh

+3

@Chomeh - Noté en mi respuesta que 'Detailed' terminaría requiriendo conocimiento de' Simple'. (Básicamente, estaba expresando la misma preocupación que usted hizo en su comentario, pero con la crítica bastante vaga de llamarlo una "desventaja". Usted fue mucho más preciso.) Sin embargo, creo que vale la pena considerar este enfoque. Los nombres enum de OP sugieren que 'Detailed' es conceptualmente un refinamiento de' Simple'. Si ese es el caso, entonces no es nada malo que 'Detailed' esté acoplado a 'Simple' (tanto como no siempre es malo que una subclase esté acoplada a su clase principal). –

15

Personalmente, simplemente crearía un Map<Detailed, Simple> y lo haría explícitamente, o incluso utilizaría una declaración switch, potencialmente.

Otra alternativa sería pasar el mapeo en el constructor - que sólo podía hacerlo de una forma redonda, por supuesto:

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

(Me parece más sencillo que el enfoque de utilizar el polimorfismo de Ted, que a nosotros re no realmente tratando de ofrecer diferentes comportamiento -. sólo un simple mapeo diferente)

Mientras podría potencialmente hacer algo astuto con el valor ordinal, que sería mucho menos evidente, y tomar más código - I Don No creo que hubiera ser cualquier beneficio.

+0

Mi voto es para el mapa – Nu2Overflow

1

respuesta de Ted es muy Javaly, pero la expresión

passed == PASSED ? DONE : ERROR 

haría el trabajo, también.

+0

¿Qué pasó con la parte de INPROCESS -> RUNNING del mapa? –

+0

@Ted: por supuesto, tienes razón, gracias por la corrección. No propondré '' ¿PASADO? HECHO: INPROCESS? EJECUTANDO: ERROR'' ya que, obviamente, es menos legible. (Por otra parte, ya lo he visto antes, y con un buen formato, [no parece demasiado extraño] (http://rors.org/2008/01/20/nested-ternary-operator) ...) – tiwo

0

Para mí eso suena más como un problema conceptual que como un problema de programación. ¿Por qué no elimina el tipo de enumeración "Simple" y utiliza el otro en todos los lugares del programa?

Para aclarar esto con otro ejemplo: ¿Realmente intenta definir un tipo de enumeración para los días de trabajo en una semana (de lunes a viernes) y otra enumeración para todos los días de una semana (de lunes a domingo)?

+0

Dado que Los tipos 'enum' no pueden heredarse de otros tipos' enum' en Java, usted está bastante atrapado en hacer este tipo de mapeo de vez en cuando. –

6

Uso EnumMap

que desacoplar mi interfaz XML externo de mi modelo de dominio interno mediante la implementación de un servicio de transformación. Esto incluye el mapeo de las enumeraciones del código generado jaxb a las enumeraciones del modelo de dominio.

El uso de EnumMap estático encapsula la preocupación de la transformación dentro de la clase responsable de la transformación.Es cohesivo.

@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); 
    } 
    ... 
} 
0

Aquí es la simple enumeración asignador con la prueba:

- APLICACIÓN

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

} 

- PRUEBA

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

}