package io.kaif.web.v1;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.kaif.web.support.ErrorResponse;
import io.kaif.web.support.SingleWrapper;
/**
* wrap all json response as
* <pre>
* {
* "data": ...
* }
* </pre>
* <p>
* note that if return type is byte array or Resource, it won't do wrapping
*/
@ControllerAdvice(basePackageClasses = V1ResponseWrapperAdvice.class)
public class V1ResponseWrapperAdvice implements ResponseBodyAdvice<Object> {
private final ObjectMapper stringMapper;
public V1ResponseWrapperAdvice() {
this.stringMapper = new ObjectMapper();
}
/**
* for POJO or primitive response, the converterType is MappingJackson2HttpMessageConverter, so
* it can be translated to other object such as SingleWrapper.
* <p>
* for String response, the convertType is StringHttpMessageConverter and it is before jackson
* converter. so we have to manually wrapped as string include "data"
*/
@Override
public boolean supports(MethodParameter returnType,
Class<? extends HttpMessageConverter<?>> converterType) {
return converterType.equals(MappingJackson2HttpMessageConverter.class) || converterType.equals(
StringHttpMessageConverter.class);
}
@Override
public Object beforeBodyWrite(Object body,
MethodParameter returnType,
MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request,
ServerHttpResponse response) {
if (body == null) {
if (CharSequence.class.isAssignableFrom(returnType.getMethod().getReturnType())) {
return prepareStringResponse(response, null);
}
return SingleWrapper.of(null);
}
if (body instanceof CharSequence) {
//for StringHttpMessageConverter
return prepareStringResponse(response, (CharSequence) body);
}
if (body instanceof ErrorResponse) {
return body;
}
if (body instanceof SingleWrapper) {
return body;
}
return SingleWrapper.of(body);
}
private String prepareStringResponse(ServerHttpResponse response, CharSequence body) {
response.getHeaders()
.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8");
try {
return stringMapper.writeValueAsString(SingleWrapper.of(body));
} catch (JsonProcessingException e) {
throw new IllegalStateException(e);
}
}
}