Я реализую веб-службу RESTful, в которой пользователь должен отправить подписанный токен проверки вместе с запросом, чтобы я мог убедиться, что запрос не был изменен посредником. Моя текущая реализация выглядит следующим образом.
Токен проверки - это объект VerifData, сериализованный в строку, а затем хэшированный и зашифрованный.
class VerifData {
int prop1;
int prop2;
}
В своем сервисе я помещаю данные для сериализации в экземпляр VerifData, а затем сериализую их с помощью Jackson ObjectMapper и передаю механизму проверки вместе с токеном проверки.
VerfiData verifData = new VerifData(12345, 67890);
ObjectMapper mapper = new ObjectMapper();
String verifCodeGenerated = mapper.writeValueAsString(verifData);
Но кажется, что каждый раз, когда контейнер приложения запускается, порядок свойств, отображаемых ObjectMapper в строку, изменяется.
Пример: однажды это было бы
{"prop1":12345,"prop2":67890}
а в другой раз это будет
{"prop2":67890,"prop1":12345}
Таким образом, если клиент сериализовал экземпляр VerifData, как в первую строку, есть 50% вероятность того, что он потерпит неудачу, даже если он правильный.
Есть ли способ обойти это? Могу ли я указать порядок свойств для сопоставления с помощью ObjectMapper (например, в порядке возрастания)? Или есть другой способ лучше всего реализовать этот этап проверки. Я разрабатываю как клиентские, так и серверные реализации. Я использую Java Security API для подписи и проверки.
источник
Аннотации полезны, но их сложно применять везде. Вы можете настроить весь свой ObjectMapper для работы таким образом с
Текущие версии Джексона:
objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
Старые версии Джексона:
objectMapper.configure(SerializationConfig.Feature.SORT_PROPERTIES_ALPHABETICALLY, true);
источник
В Jackson 2.x, который вы, вероятно, используете сегодня, используйте:
ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
Если вы заботитесь о внешности, вы также можете подумать
SerializationFeature.INDENT_OUTPUT
.Обратите внимание, что для правильной сортировки вы должны сериализовать карты или объекты . Если вы сериализуете,
JsonNode
например (изreadTree
), он не будет иметь правильный отступ.пример
import com.fasterxml.jackson.databind.*; ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true); mapper.configure(SerializationFeature.INDENT_OUTPUT, true); String input = "{\"hello\": {\"cruel\" : \"world\"} }"; Object pojo = mapper.readValue(input, Object.class); System.out.println(mapper.writeValueAsString(pojo));
приводит к:
{ "hello" : { "cruel" : "world" } }
источник
В Spring Boot вы можете добавить это поведение глобально, добавив следующее в свой
Application
класс точки входа:@Bean public Jackson2ObjectMapperBuilder objectMapperBuilder() { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.featuresToEnable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY); return builder; }
источник
В Spring Boot есть более простой способ, указав свойство (
application.properties
например, в:spring.jackson.mapper.sort_properties_alphabetically=true
источник
Требуются следующие 2 конфигурации ObjectMapper:
ObjectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
или же
ObjectMapper.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
и
ObjectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true)
или же
ObjectMapper.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)
Пример конфигурации Spring Boot (yaml):
spring: jackson: mapper: SORT_PROPERTIES_ALPHABETICALLY: true serialization: ORDER_MAP_ENTRIES_BY_KEYS: true
источник
Из ответа Дункана МакГрегора: лучше использовать его так:
objectMapper.configure(SerializationConfig.Feature.SORT_PROPERTIES_ALPHABETICALLY, true);
поскольку MapperFeature предназначен для XML и поставляется с привязкой данных Джексона, которая не требуется ...
источник
Вместо использования аргумента флага:
источник
Вы можете использовать смешивание и указать порядок свойств по своему усмотрению:
import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; @Component public final class ObjectMapperUtils { private static final ObjectMapper MAPPER = new ObjectMapper(); static { MAPPER.addMixIn(Object.class, IdFirst.class); } @Bean public ObjectMapper objectMapper() { return MAPPER; } @JsonPropertyOrder({"id", "...", "..."}) private abstract static class IdFirst {} }
источник
Я понимаю, что это старая ветка, но поскольку я искал или отвечал и попал сюда, некоторая дополнительная информация может быть полезна другим людям.
Аннотация @JsonProperty, которую я использую в настоящее время (jackson-annotations-2.11.2), принимает, помимо аргумента «значение», аргумент «индекс» (числовой), который указывает порядок полей во время сериализации.
источник