Skip to content
Advertisement

Rest API ResponseEntity add extra attribute to response

I’m trying to figure out response of a GET method API, it is returning extra attribute with name “attributesMap”

Reponse entity return code is return ResponseEntity.ok(document);

document model class

  private String id;
  private String format;
  private List<Attribute> attributes;
  private String type;
  private String accessright;

  public Document() {
  }

  /**
   * Copy constructor.
   */
  public Document(Document source) {
      this.id = source.id;
      this.format = source.format;
      this.type = source.type;
      this.accessright = source.accessright;
      this.attributes = source.attributes;
  }

  public static Document newDocument(String type, String id, String format, String accessright, List<Attribute> attributes) {
      Document document = new Document();
      document.type = type;
      document.id = id;
      document.format = format;
      document.accessright = accessright;
      document.attributes = attributes;

      return document;
  }

  public static Document newCompleteDocument(String id, String type, String format, String accessright, List<Attribute> attributes) {
      Document document = new Document();
      document.id = id;
      document.type = type;
      document.format = format;
      document.accessright = accessright;
      document.attributes = attributes;

      return document;
  }

  //
  // Getters and setters ahead

  public String getId() {
      return id;
  }

  public void setId(String id) {
      this.id = id;
  }

  public String getFormat() {
      return format;
  }

  public void setFormat(String format) {
      this.format = format;
  }

  public String getType() {
      return type;
  }

  public void setType(String type) {
      this.type = type;
  }

  public List<Attribute> getAttributes() {
      return attributes;
  }

  public void setAttributes(List<Attribute> attributes) {
      this.attributes = attributes;
  }

  public String getAccessright() {
      return accessright;
  }

  public void setAccessright(String accessright) {
      this.accessright = accessright;
  }
  
  public Map<String, List<String>> getAttributesMap() {
      Map<String, List<String>> attributesMap = getAttributes().stream().collect(Collectors.toMap(Attribute::getName, Attribute::getValues));
      return attributesMap;
  }

  @Override
  public String toString() {
      final StringBuffer sb = new StringBuffer("Document{");
      sb.append("id='").append(id).append(''');
      sb.append(", type='").append(type).append(''');
      sb.append(", format='").append(format).append(''');
      sb.append(", accessright='").append(accessright).append(''');
      sb.append(", attributes=[").append(attributes);
      if (attributes != null) {
          for (Attribute attribute:attributes) {
              sb.append(attribute.getName()).append(":").append(attribute.getValues().toArray()).append(",");
          }
      }

      sb.append("]}");
      return sb.toString();
  }

  @Override
  public boolean equals(Object o) {
      if (this == o) {
          return true;
      }
      if (o == null || getClass() != o.getClass()) {
          return false;
      }

      Document document = (Document) o;

      if (id != null ? !id.equals(document.id) : document.id != null) {
          return false;
      }
      if (type != null ? !type.equals(document.type) : document.type != null) {
          return false;
      }
      if (format != null ? !format.equals(document.format) : document.format != null) {
          return false;
      }
      if (accessright != null ? !accessright.equals(document.accessright) : document.accessright != null) {
          return false;
      }
      return attributes != null ? attributes.equals(document.attributes) : document.attributes == null;

  }

  @Override
  public int hashCode() {
      int result = id != null ? id.hashCode() : 0;
      result = 31 * result + (type != null ? type.hashCode() : 0);
      result = 31 * result + (format != null ? format.hashCode() : 0);
      result = 31 * result + (accessright != null ? accessright.hashCode() : 0);
      result = 31 * result + (attributes != null ? attributes.hashCode() : 0);
      return result;
  }
}

but the API reponse JSON as an extra attribute “attributesMap”. Sample JSON as below:

   {
      "id": "xxx",
       "format": "xx",
       "attributes": [
    {
      "name": "attr1",
      "values": [
        "val1"
      ]
    }
  ],
  "type": "test type",
  "accessright": "DELETE",
  "attributesMap": {
    "name": "attr1",
      "values": [
        "val1"
      ]
    }
    }

Can anyone help me figure out how to check where this attribute coming from , when I debugged till the return return ResponseEntity.ok(document); there is no attributesMap in the document model object.

Advertisement

Answer

The problem in your case is that you have the getter getAttributesMap. What will jackson serialize by default?

  1. All public fields
  2. All getter methods

What can you do?

  1. Rename the method
  2. Exclude the getter with @JsonIgnore
  @JsonIgnore
  public Map<String, List<String>> getAttributesMap() {
      Map<String, List<String>> attributesMap = getAttributes().stream().collect(Collectors.toMap(Attribute::getName, Attribute::getValues));
      return attributesMap;
  }

You could also provide your own ObjectMapper bean with the following settings:

var mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
mapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);

or

var mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);

This would only serialize fields, not getters.

Advertisement