Ares91
Ares91

Reputation: 536

Spring Boot manipulate http parameters on runtime

I'm trying, without success, to manipulate some http parameters (in query, body ...) before the call is received by the final endpoint. For example, we have this post call:

curl -X POST "http://localhost:8080/insertBody/" -H "accept: application/json" -H "Content-Type: application/json" -H "Date-Format: yyyy-MM-dd" -d "{ \"isUniform\": true, \"myDate\": \"2020-01-14T08:55:07.013Z\", \"myInt\": 0, \"uniform\": true}"

What I'm trying to do is converting myDate -> 2020-01-14T08:55:07.013Z inside the post body in this format yyyy-MM-dd passed in the header. The manipulation has to involve all objects of type OffsetDateTime (in this case) present in this call.

When the call is received by the microservice:

Header:
  Date-Format: yyyy-MM-dd
Body
  {
    "isUniform": true,
    "myDate": "2020-01-14T08:55:07.013Z",
    "myInt": 0,
    "uniform": true
  }

After data manipulation and what is received by the controller:

Header:
  Date-Format: yyyy-MM-dd
Body
  {
    "isUniform": true,
    "myDate": "2020-01-14",   <---
    "myInt": 0,
    "uniform": true
  }

Body class

public class CashBackCampaignRequest   {

  @JsonProperty("uniform")
  private Boolean uniform = true;

  @JsonProperty("myInt")
  private Integer myInt = null;

  @JsonProperty("myDate")
  private OffsetDateTime myDate = null;

  // getter setters ...
}

Upvotes: 0

Views: 1041

Answers (2)

Ares91
Ares91

Reputation: 536

Based on RUARDO answere I canged RequestBodyAdviceAdapter with ResponseBodyAdvice< Object>

@ControllerAdvice
public class ResponseJsonFilterAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // true if want to use this controller
        return true;
    }

    @Override
    public Object beforeBodyWrite(
            Object body, 
            MethodParameter returnType, 
            MediaType selectedContentType,
            Class<? extends HttpMessageConverter<?>> selectedConverterType, 
            ServerHttpRequest request,
            ServerHttpResponse response) {

        List<String> headers = request.getHeaders().get("X-MY-DATE-FORMAT");
        if(headers == null || headers.isEmpty())
            return body;


        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());  
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(OffsetDateTime.class, new JsonSerializer<OffsetDateTime>() {
            @Override
            public void serialize(OffsetDateTime offsetDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
                jsonGenerator.writeString(DateTimeFormatter.ofPattern(headers.get(0)).format(offsetDateTime));
            }
        });
        objectMapper.registerModule(simpleModule);

        try {
            return objectMapper.writeValueAsString(body);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return body;
    }
}

Upvotes: 0

RUARO Thibault
RUARO Thibault

Reputation: 2850

You should use the famous RequestBodyAdviceAdapter. You can, before entering your controller, manipulate the body of your message. You declare a @ControllerAdvice or @RestControllerAdvice (it is just a @Component), and extends the class RequestBodyAdviceAdapter. (you can also implements the interface RequestBodyAdvice, but I'd recommend extending the abstract class).

Here is a quick example:

@RestControllerAdvice
public class WebAdvice extends RequestBodyAdviceAdapter {

    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        // to know whether you will use your advice or not
        return true;
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        String format = inputMessage.getHeaders().get("DATE_FORMAT").get(0);
        if(body instanceof CashBackCampaignRequest) {
            // Do whatever you want
            ((CashBackCampaignRequest) body).setDate()
        }
        return super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
    }
}

Be careful with the type of the request received in the Controller. If your controller receives an object of type CashBackCampaignRequest, then you won't be able to change the format.

Upvotes: 1

Related Questions