简体   繁体   English

Java中枚举的每个值的键-值映射

[英]Key-value map of each value of an enum in Java

Task 任务

In a Java back-end project, I have some (100+) external enums that I can't edit and I need to output them to our front-end. 在Java后端项目中,我有一些(100+)个外部枚举无法编辑,我需要将它们输出到前端。 I wanted to output them in a JSON-object like manner. 我想以类似JSON对象的方式输出它们。 Each enum has different properties name. 每个枚举都有不同的属性名称。

eg for the following enum 例如对于以下枚举

public enum Colors {
  RED(1, "RED", "ff0000", Boolean.TRUE),
  GREEN(2, "GREEN", "00ff00", Boolean.FALSE),
  BLUE(3, "BLUE", "0000ff", Boolean.TRUE);

  private int code;
  private String label;
  private String hexCode;
  private boolean isAwesome;

  // ... getters and other methods
}

i want to output 我想输出

[
  {
    label: "RED"
    hexCode: "ff0000"
    isAwesome: true
  },
  {
    label: "GREEN"
    hexCode: "00ff00"
    isAwesome: false
  },
  ...
]

My attempt 我的尝试

I am new to Java, this is the first time I used reflection and I didn't really study anything before going into this. 我是Java的新手,这是我第一次使用反射,在开始之前,我并没有真正研究任何东西。 Probably there are some major problems with this code (like performance or some other weird stuff that I don't know), but it compiles and does the job. 这段代码可能存在一些主要问题(例如性能或我不知道的其他怪异的东西),但是它可以编译并完成工作。 I don't know if this is safe, so I ask if there are some better ways to do this. 我不知道这是否安全,所以我问是否有更好的方法可以做到这一点。

private <T> List<HashMap<String, Object>> enumInserter(Class<T> clazz, List<String> properties) {
    return valuesToMap(clazz.getEnumConstants(), parserFactory(clazz, properties));
}

/**
* 
* @param <T>    type of the enum class
* @param values enumConstants of the enum
* @param parser a function that take a single enumValue of type <T> and returns
*               an property-value map
* @return the array of the property-value maps of each value
*/
private <T> List<HashMap<String, Object>> valuesToMap(T[] values, Function<T, HashMap<String, Object>> parser) {
  List<HashMap<String, Object>> enumValues = new ArrayList<>();
  for (T enumValue : values) {
    HashMap<String, Object> processedValue = parser.apply(enumValue);
    enumValues.add(processedValue);
  }
  return enumValues;
}

/**
* 
* @param <T>        the type of the enum class
* @param clazz      the enum class
* @param properties the properties to be added in the map
* @return a parser function that take a single enumValue of type <T> as input and
*         returns a property-value map of the given enumValue
*/
private <T> Function<T, HashMap<String, Object>> parserFactory(Class<T> clazz, List<String> properties) {
  return ((T enumValue) -> {
    HashMap<String, Object> map = new HashMap<>();

    properties.stream().forEach(propertyName -> {
      String methodName = getterFromProperty(propertyName);
      try {
        Method method = clazz.getMethod(methodName);
        Object methodResult = method.invoke(enumValue);
        map.put(propertyName, methodResult);
      } catch (Exception e) {
        // ... error logging
      }
    });

    return map;
  });
}

/**
* Return the "standard" property getter of a property. e.g. "example" will
* return "getExample"
* 
* @param property
* @return property getter method name
*/
private String getterFromProperty(String property) {
  return "get" + property.substring(0, 1).toUpperCase() + property.substring(1);
}

The usual approach to this is either through use of annotation @JsonFormat(shape = JsonFormat.Shape.OBJECT) or through usage of a custom tailored serializer. 通常的方法是通过使用批注@JsonFormat(shape = JsonFormat.Shape.OBJECT)或使用定制的量身定制的序列化程序。

Lets say that you are referencing the enum from class A 假设您正在引用A类的枚举

class A {

   @JsonFormat(shape = JsonFormat.Shape.OBJECT)
   private Colors color;

}

this will make the color to be serialized the way you want. 这将使颜色按照您想要的方式进行序列化。

Alternative aproach would to register a custom serializer for your Enum this you can do the following way: 替代方法是为您的Enum注册一个自定义序列化器,您可以通过以下方式进行操作:

public class ColorSerializer extends StdSerializer {

    public ColorSerializer() {
        super(Color.class);
    }

    public ColorSerializer(Class t) {
        super(t);
    }

    public void serialize(Color color, JsonGenerator generator,
      SerializerProvider provider) 
      throws IOException, JsonProcessingException {
        generator.writeStartObject();
        generator.writeFieldName("code");
        generator.writeString(color.getCode());
        generator.writeFieldName("hexCode");
        generator.writeString(color.getHexcode());
        generator.writeFieldName("isAwsome");
        generator.writeNumber(color.isAwsome());
        generator.writeEndObject();
    }
}

Since your enums are external you can always place them in wrappers which are internal to your project and this way control their serialization process. 由于枚举是外部的,因此您始终可以将它们放在项目内部的包装器中,并以此方式控制其序列化过程。

If you want to serialize them using the same strategy you can place your reflection code in the serializer. 如果要使用相同的策略来序列化它们,则可以将反射代码放入序列化器中。 This way you will get a single generic serializer, instead of writing for each enum. 这样,您将获得一个通用的序列化器,而不是为每个枚举编写代码。

This is how you can register the custom serializer: 这是注册自定义序列化器的方法:

ObjectMapper mapper = new ObjectMapper();

SimpleModule module = new SimpleModule();
module.addSerializer(Color.class, new ColorSerializer ());
mapper.registerModule(module);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM