Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to serialize list of enums from rest api

I want to return a list of enums from a rest api call, and have it show the value of the enum rather than just the enum names, in JSON format. Currently my rest call returns json looking like:

{
  "responses": [
    "ACTION_TAKEN",
    "IGNORED",
    "UNDETECTED"
  ]
}

But, I want it to be more like (or something like this):

{
  "responses": [
    {
      "name":"ACTION_TAKEN",
      "value":"Action Taken"
    },
    {
      "name":"IGNORED",
      "value":"Ignored"
    },
    {
      "name":"UNDETECTED",
      "value":"Undetected"
    }
   ]
}

My enum looks like:

public enum Response {

  ACTION_TAKEN ("Action Taken"),
  IGNORED ("Ignored"),
  UNDETECTED("Undetected");

  private String value;

  Response(String value) {
    this.value = value;
  }

  public String getValue() {
    return this.value;
  }

  @Override
  public String toString() {
    return value;
  }
}

My model object looks like this. For the sake of this example, it just has a list of enum values.

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class StaticData {

  private List<Response> responses;

  public List<Response> getResponses() {
    return responses;
  }

  public void setResponses(List<Response> responses) {
    this.responses = responses;
  }
}

The web service method looks like:

@Component
@Path("staticData")
@Produces("application/json")
@Consumes("application/json")
public class StaticDataResource {

  @GET
  public Response getCurrentContent() {
    StaticData staticData = new StaticData();
    staticData.setResponses(Arrays.asList(Response.values()));
    return Response.ok(staticData).build();
  }
}

Here are the dependencies from my effective pom (sorry for the bad formatting)

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.2.5.RELEASE</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>com.sun.jersey.contribs</groupId>
    <artifactId>jersey-spring</artifactId>
    <version>1.19.1</version>
    <scope>compile</scope>
    <exclusions>
      <exclusion>
        <artifactId>*</artifactId>
        <groupId>org.springframework</groupId>
      </exclusion>
    </exclusions>
  </dependency>
  <dependency>
    <groupId>com.thetransactioncompany</groupId>
    <artifactId>cors-filter</artifactId>
    <version>2.4</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.2.5.RELEASE</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.2.5.RELEASE</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-expression</artifactId>
    <version>4.2.5.RELEASE</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-oxm</artifactId>
    <version>4.2.5.RELEASE</version>
    <scope>compile</scope>
  </dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-orm</artifactId>
  <version>4.2.5.RELEASE</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.19</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.7.19</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>commons-logging</groupId>
  <artifactId>commons-logging</artifactId>
  <version>1.2</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.4</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>19.0</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.reflections</groupId>
  <artifactId>reflections</artifactId>
  <version>0.9.10</version>
  <scope>compile</scope>
  <exclusions>
    <exclusion>
      <artifactId>guava</artifactId>
      <groupId>com.google.guava</groupId>
    </exclusion>
  </exclusions>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>3.0.1</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>javax.ws.rs</groupId>
  <artifactId>javax.ws.rs-api</artifactId>
  <version>2.0.1</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>org.eclipse.persistence</groupId>
  <artifactId>javax.persistence</artifactId>
  <version>2.1.0</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>javax.ejb</groupId>
  <artifactId>javax.ejb-api</artifactId>
  <version>3.2</version>
  <scope>provided</scope>
</dependency>
  <dependency>
      <groupId>javax.transaction</groupId>
      <artifactId>jta</artifactId>
      <version>1.1</version>
      <scope>provided</scope>
    </dependency>
</dependencies>

I have tried adding @JsonFormat(shape = JsonFormat.Shape.Object) to the top of my enum class. It didn't work. I tried adding @JsonValue to above my getValue() method in the enum class, and that didn't work either. I tried adding a custom serializer extending StdSerializer or JsonSerializer, and referencing that class above my enum using @JsonSerialize(using = ReasonSerializer). I put a breakpoint in the serialize method and didn't hit it, so that didn't work. I looked a little bit at doing implements ContextResolver<ObjectMapper>, but couldn't quite figure that out, or whether that was even the right path to go down or not.

Any help is greatly appreciated! Thanks!

like image 694
Jess Avatar asked Dec 12 '18 23:12

Jess


1 Answers

Final solution

This works with JAX-RS and I have tested it with your code.

Use @JsonFormat with public String getName().

@JsonFormat(shape=JsonFormat.Shape.OBJECT)
public enum Response {
    ACTION_TAKEN ("Action Taken"),
    IGNORED ("Ignored"),
    UNDETECTED("Undetected");

    private String value;

    Response(String value) {
        this.value = value;
    }
    // Getters, Setters

    public String getName() {
        return name();
    }
}

JSON output

{
    "responses": [{
            "value": "Action Taken",
            "name": "ACTION_TAKEN"
        }, {
            "value": "Ignored",
            "name": "IGNORED"
        }, {
            "value": "Undetected",
            "name": "UNDETECTED"
        }
    ]
}

Tested using the following dependency.

import com.fasterxml.jackson.annotation.JsonFormat;

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.9.6</version>
</dependency>

Alternative solution

Jackson docs states that behavior may change depending on what serializer is being used. So if the first solution doesn't work, this one might.

@JsonFormat(shape=JsonFormat.Shape.OBJECT)
public enum Response {
    ACTION_TAKEN ("Action Taken"),
    IGNORED ("Ignored"),
    UNDETECTED("Undetected");

    private String name;
    private String value;

    Response(String value) {
        name = name();
        this.value = value;
    }
    
    public String getName() {
        return name;
    }
    
    public String getValue() {
        return value;
    }
}
like image 144
J.A.P Avatar answered Nov 12 '22 02:11

J.A.P