I am having an issue where my Spring Boot response Entity is mostly being converted to JSON but the body is staying as a string.
I have read many of the other questions on this site, but they all seem to point to the same thing.
pom.xml Dependencies
<dependencies>
<!--OpenAPI Generator Dependencies-->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.2</version>
</dependency>
<!--Http Dependencies-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<!--Log4j Dependencies-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!--Spring Framework Dependencies-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--Dotenv Dependencies-->
<dependency>
<groupId>io.github.cdimascio</groupId>
<artifactId>java-dotenv</artifactId>
<version>${dotenv.version}</version>
</dependency>
<!--JSON Object Dependencies-->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20220924</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.14.1</version>
</dependency>
</dependencies>
ApiResponse Class
public class ApiResponse {
// class used to model api response data
public Integer statusCode;
public String statusReason;
public String statusLine;
public String url;
public String body;
public ProtocolVersion protocolVersion;
public String getStatusLine() {
return statusLine;
}
public void setStatusLine(String statusLine) {
this.statusLine = statusLine;
}
public ProtocolVersion getProtocolVersion() {
return protocolVersion;
}
public String getStatusReason() {
return statusReason;
}
public void setStatusReason(String statusReason) {
this.statusReason = statusReason;
}
public void setProtocolVersion(ProtocolVersion protocolVersion) {
this.protocolVersion = protocolVersion;
}
public Integer getStatusCode() {
return statusCode;
}
public void setStatusCode(Integer statusCode) {
this.statusCode = statusCode;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
processResponse method
public ApiResponse processResponse(CloseableHttpResponse response) throws IOException {
// process custom apache httpClient response
ApiResponse apiResponse = new ApiResponse();
apiResponse.setProtocolVersion(response.getProtocolVersion());
apiResponse.setStatusCode(response.getStatusLine().getStatusCode());
apiResponse.setStatusReason(response.getStatusLine().getReasonPhrase());
apiResponse.setStatusLine(response.getStatusLine().toString());
HttpEntity entity = response.getEntity();
if (entity != null) {
// return it as a String
String result = EntityUtils.toString(entity);
apiResponse.setBody(result);
}
response.close();
return apiResponse;
}
getCall method
@GetMapping(value = "/getHealth", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ApiResponse> getClientHealth() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
Client clientSetup = new Client(dotEnv.get("URL"), 80);
try {
ApiResponse response = clientSetup.getHealth();
return new ResponseEntity<>(response, HttpStatusCode.valueOf(response.getStatusCode()));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
The response
{
"statusCode": 200,
"statusReason": "OK",
"statusLine": "HTTP/1.1 200 OK",
"url": null,
"body": "{"status":"Healthy!"}",
"protocolVersion": {
"protocol": "HTTP",
"major": 1,
"minor": 1
}
}
The problem is with "body": "{"status":"Healthy!"}"
I have been unsuccessful in getting the body to be converted from a string to JSON when returned through my Spring Boot ResponseEntity.
2
Answers
You are getting exactly what you asked for with the definition of
ApiResponse
.If you want Jackson to serialize that as a part of the object. It needs to be defined as part of the object.
This may be as simple as changing it to
JsonNode
.And generating a
JsonNode
from the entity.Although it would probably be better if your
ApiResponse
object more accurately modeled what it is holding.As others have said, by declaring the type of
ApiResponse.body
as String, that’s exactly what’s being stored there; the JSON serializer doesn’t have any knowledge of the content of the String, so it just serializes it out (with required escaping to make it a valid string value).I can think of 2 options to make that a more useful object that can be serialized: A) transform the response
HttpEntity
you get from the downstream API into a simple DTO with just the properties you care about; or B) useHttpEntity<>
directly and instruct the serializer to ignore properties you don’t care about (such as theEofSensorInputStream
from the exception you reported).Option A seems fairly obvious so I won’t show code for that. Here’s how you can accomplish Option B:
That instructs the serializer to only include
body
andheaders
when it serializes thebody
ofApiResponse
, ignoring anything else in theHttpEntity
.