Сконфигурируйте FAIL_ON_UNKNOWN_PROPERTIES для каждого RequestMapping по-разному в контроллере - PullRequest
1 голос
/ 08 октября 2019

Я хочу по-разному обрабатывать преобразование json в объекты на разных @RequestMapping в моем контроллере.

Я полагаю, что если мы добавим зависимость Джексона в наш проект весенней загрузки, он будет обрабатывать преобразование json в Object, а свойство #spring.jackson.deserialization.fail-on-unknown-properties=true будет гарантировать, что преобразование завершится неудачно, если в json присутствует какое-то неизвестное свойство (пожалуйста, исправьтеменя, если я ошибаюсь).

Можем ли мы указать Джексону локально, когда происходит сбой неизвестных свойств и когда игнорировать это свойство.

Ниже приведен фрагмент кода для использованияflag.

    @GetMapping(value = "sample")
    public @ResponseBody UserDTO test(@RequestParam String str, @RequestParam boolean failFast) {
        ObjectMapper map = new ObjectMapper();
        if( failFast) {
            map.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
        } else {
            map.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        }
        UserDTO userDTO = null;
        try {
            userDTO = map.readValue(str, UserDTO.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return userDTO;
    }

Мне не нужно обрабатывать его во время выполнения, как я использую @RequestParam. Есть ли какое-либо свойство, с помощью которого я могу отмечать сопоставления, где проверять неизвестные свойства и гдеигнорировать их.

Редактировать : я ищу, чтобы изменить существующее приложение для обработки неизвестного свойства для сопоставления. Например:

        @PostMapping(value = "fail/fast")
        public @ResponseBody UserDTO test(@FAIL_ON_UNKNOWN @RequestBody UserDTO userDTO, @RequestParam boolean failFast) {
            ..///processing...
            return userDTO;
        }

        @PostMapping(value = "fail/safe")
        public @ResponseBody UserDTO test( @RequestBody UserDTO userDTO, @RequestParam boolean failFast) {
                ..///processing...
                return userDTO;
        }

Если для каждого сопоставления можно добавить какой-либо тип проверки, то мне не нужно изменять все существующие сопоставления для настройки неизвестного свойства, и изменение кода будет минимальным.

Ответы [ 2 ]

1 голос
/ 10 октября 2019

Я смог достичь желаемого результата, реализовав свой собственный HttpMessageConverter . Спасибо @ MichalZiober за предложение.

Я создал пользовательский HttpMessageConvertor и зарегистрировал его с моим собственным MediaType: {"application", "json-failFast"}.

Как это работает, когда присутствует Header: Content-Type:application/json-failFast, тогда неизвестные свойства в @RequestBody/@ResponseBody не будут приняты при преобразовании из json в Object и UnrecognizedPropertyException будет брошено.

И всякий раз, когда присутствует Header: Content-Type:application/json, нераспознанные свойства в @RequestBody/ResponseBody будут игнорироваться.

Вот мой кастом HttpMessageConverter :

@Component
public class CustomJsonMessageConverter extends AbstractJackson2HttpMessageConverter {

    @Nullable
    private String jsonPrefix;

    public CustomJsonMessageConverter() {
        this(Jackson2ObjectMapperBuilder.json().build().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,true));
    }
    public CustomJsonMessageConverter(ObjectMapper objectMapper) {
        super(objectMapper, new MediaType[]{ new MediaType("application", "json-failFast")});
    }

    public void setJsonPrefix(String jsonPrefix) {
        this.jsonPrefix = jsonPrefix;
    }

    public void setPrefixJson(boolean prefixJson) {
        this.jsonPrefix = prefixJson ? ")]}', " : null;
    }

    protected void writePrefix(JsonGenerator generator, Object object) throws IOException {
            if (this.jsonPrefix != null) {
            generator.writeRaw(this.jsonPrefix);
        }
    }
}
1 голос
/ 09 октября 2019

Jackson ObjectMapper позволяет создавать новые ObjectReader с пользовательской конфигурацией. Вы можете создать один общий ObjectMapper экземпляр в своем приложении и для некоторых контроллеров использовать его в качестве базового объекта для создания пользовательских считывателей. Это позволит вам использовать все общие функции и зарегистрированные модули и изменить несколько при необходимости. См. Ниже контроллер:

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.util.Objects;

@RestController
@RequestMapping(value = "/options")
public class JacksonOptionsController {

    private final ObjectMapper objectMapper;

    @Autowired
    public JacksonOptionsController(ObjectMapper objectMapper) {
        this.objectMapper = Objects.requireNonNull(objectMapper);
    }

    @PostMapping(path = "/fail")
    public ResponseEntity<String> readAndFastFail(HttpServletRequest request) throws IOException {
        String json = readAsRawJSON(request);
        Payload payload = createFailFastReader().readValue(json);

        return ResponseEntity.ok("SUCCESS");
    }

    @PostMapping(path = "/success")
    public ResponseEntity<String> readAndIgnore(HttpServletRequest request) throws IOException {
        String json = readAsRawJSON(request);
        Payload payload = createSafeReader().readValue(json);

        return ResponseEntity.ok("SUCCESS");
    }

    private ObjectReader createFailFastReader() {
        return objectMapper
                .readerFor(Payload.class)
                .with(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    }

    private ObjectReader createSafeReader() {
        return objectMapper
                .readerFor(Payload.class);
    }

    private String readAsRawJSON(HttpServletRequest request) throws IOException {
        try (InputStreamReader reader = new InputStreamReader(request.getInputStream())) {
            try (StringWriter out = new StringWriter(64)) {
                reader.transferTo(out);
                return out.toString();
            }
        }
    }
}

Payload класс имеет только одно свойство - id. В одном контроллере мы используем ObjectReader с включенным DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES. В других мы используем ObjectReader с конфигурацией по умолчанию с отключенным DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES.

Для тестового запроса:

curl -i -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"id":"some-value","id1":1}' http://localhost:8080/options/fail

приложение выдает исключение и для запроса:

curl -i -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"id":"some-value"}' http://localhost:8080/options/fail

возвращает SUCCESS значение. Когда мы отправляем две вышеуказанные полезные нагрузки на http://localhost:8080/options/success URL, приложение в обоих случаях возвращает SUCCESS значение.

См. Также:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...