I have a generic record that I use to send enum values with a description to my front-end:
public record EnumJson<E extends Enum<E>>(E value, String description) {
}
I have a single endpoint in which I provide many different enums in one response. It looks a bit like this (but more complex):
public record Enums(
List<YesNo> yesNo,
List<RedBlue> redBlue,
List<UpDown> upDown, ...) {
}
For many of these enums, Jackson's default serialization mechanism of this E
is fine (serialize using Enum.name()
). However, for a handful of these enums, I'd like to customize serialization. I'm looking for some method to control the way E
is serialized from Enums
. Perhaps with an annotation like:
public record Enums(
List<YesNo> yesNo,
List<RedBlue> redBlue,
List<@SomeInstructionToCustomizeSerialization UpDown> upDown, ...) {
}
I currently have a copy of EnumJson
as follows:
public record SpecialEnumJson<E extends Enum<E>>(@JsonSerialize(...) E value, String description) {
}
However, it feels like there must be a better alternative.
Things that are not a solution in my case:
@JsonValue
to those handful of enums, because this would have an effect on how these enums are serialized throughout my entire application (which I do not want)If you need a custom serialization/deserialization logic only for some enum fields, then you could still employ the StdDeserializer
and StdSerializer
classes, customize the logic specifically for those fields, and finally add the @JsonSerialize
and @JsonDeserialize
annotations before the interested attributes.
In your case, a customization for the List<UpDown>
field in Enums
could look like this:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Enums {
List<YesNo> yesNo;
List<RedBlue> redBlue;
@JsonSerialize(using = SerializerListUpDown.class)
@JsonDeserialize(using = DeserializerListUpDown.class)
List<UpDown> upDown;
}
public class SerializerListUpDown extends StdSerializer<List<UpDown>> {
public SerializerListUpDown() {
this(null);
}
public SerializerListUpDown(Class<List<UpDown>> l) {
super(l);
}
@Override
public void serialize(List<UpDown> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
int[] upDownValues = value.stream().mapToInt(UpDown::getId).toArray();
gen.writeArray(upDownValues, 0, upDownValues.length);
}
}
public class DeserializerListUpDown extends StdDeserializer<List<UpDown>> {
public DeserializerListUpDown() {
this(null);
}
public DeserializerListUpDown(Class<List<UpDown>> vc) {
super(vc);
}
@Override
public List<UpDown> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
ObjectCodec codec = p.getCodec();
JsonNode root = codec.readTree(p);
List<UpDown> list = new ArrayList<>();
for (int i = 0; i < root.size(); i++) {
for (UpDown e : UpDown.values()) {
if (root.get(i).asInt() == e.getId()) {
list.add(e);
}
}
}
return list;
}
}
Here is also a demo at OneCompiler. As you can see from the output, the annotations manage to customize the serialization and deserialization for a List<UpDown>
field by using the enum's value instead of its name.
Json => {"yesNo":["YES","NO","YES"],"redBlue":["BLUE","RED","RED"],"upDown":[2,2,8]}
Object => Enums{yesNo=[YES, NO, YES], redBlue=[BLUE, RED, RED], upDown=[DOWN, DOWN, UP]}