springspring-bootspring-mvcjacksonjackson-databind

How to serialize EnumSet with elements in a specific format for a single endpoint only?


Let's say I have a simple enum:

public enum Foo {
  CONST1("Const1 description"),
  CONST2("Const2 description");

  private final String label;

  private Foo(String label) {
    this.label = label;
  }

  public String getLabel() {
    return label;
  }
  
}

Now I have an endpoint that should return all the possible enum values to use this as a drop down in frontend:

@GetMapping
public ResponseEntity<EnumSet<Foo>> allOfFoo() {
  return ResponseEntity.ok(EnumSet.allOf(Foo.class));
}

I want to customize the format of how elements of this enum are returned for this endpoint only (because in different places of the service I might not need the description of each constant), like so:

[
  {
    "name": "CONST1",
    "description": "Const1 description"
  },
  {
    "name": "CONST2",
    "description": "Const2 description"
  }
]

Jackson annotation such as @JsonProperty, @JsonValue, etc seem to require altering the class itself, but I don't want to alter serialization format for the whole class.
I know that there is @JsonSerialize which I've successfully used when EnumSet is wrapped inside another object but I'm not sure if I can make it work with controller methods.
I know there are mix-ins but again they seem to alter the format enum itself and not for just the specific API.
Is there a way to do it? Am I missing something? Maybe that's not a thing in API design in general and I'm trying to solve the wrong problem?


Solution

  • What about a simpler approach:

    Let's create a class:

    public class FooDto {
    
    @NotNull
    private final Foo foo;
    
    public FooDto(Foo foo) {
    
     this.foo = foo;
    
    }
    
    public String getName() {
     return foo.name();
    }
    
    public String getDescription() {
     return foo.getLabel();
    }
    
    }
    

    And then in Controller:

    @GetMapping
    public ResponseEntity<Set<FooDto>> allOfFoo() {
      return ResponseEntity.ok(EnumSet.allOf(Foo.class).stream().map(f -> new FooDto(f)).collect(Collectors.toSet()));
    }