Из STRICT_DUPLICATE_DETECTION
документации:
Функция, определяющая, будет ли JsonParser явно проверять,
повторяющихся имен полей JSON Object не обнаружено. Если включено,
Парсер проверит все имена в контексте и сообщит дубликаты
бросая JsonParseException; если отключено, парсер не сделает такого
проверка. В последнем случае предполагается, что вызывающий абонент заботится о
обработка дубликатов на более высоком уровне: привязка данных, например , имеет
функции для определения обнаружения, которые будут сделаны там. Обратите внимание, что включение
эта функция повлечет за собой снижение производительности из-за необходимости хранить
и проверьте дополнительную информацию: это обычно добавляет 20-30% к
время выполнения основного синтаксического анализа.
JSON
по умолчанию чувствителен к регистру, и это одна из основных причин, по которой его нечувствительность не включена по умолчанию в Jackson
. Но мы можем расширить базовую реализацию и добавить проверку. Нам нужно расширить com.fasterxml.jackson.databind.deser.BeanDeserializerModifier
и com.fasterxml.jackson.databind.deser.BeanDeserializer
, которые десериализуют POJO
классов. Приведенное ниже решение зависит от версии, которую вы используете, потому что я скопировал некоторый код из базового класса, который не готов к перехвату дополнительной функциональности. Если у вас нет дополнительной конфигурации для вашего метода POJO
classes vanillaDeserialize
, будет вызван этот метод, который мы постараемся улучшить. Давайте реализуем это:
class InsensitiveBeanDeserializerModifier extends BeanDeserializerModifier {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
JsonDeserializer<?> base = super.modifyDeserializer(config, beanDesc, deserializer);
if (base instanceof BeanDeserializer) {
return new InsensitiveBeanDeserializer((BeanDeserializer) base);
}
return base;
}
}
class InsensitiveBeanDeserializer extends BeanDeserializer {
public InsensitiveBeanDeserializer(BeanDeserializerBase src) {
super(src);
}
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
// common case first
if (p.isExpectedStartObjectToken()) {
if (_vanillaProcessing) {
return vanillaDeserialize(p, ctxt, p.nextToken());
}
// 23-Sep-2015, tatu: This is wrong at some many levels, but for now... it is
// what it is, including "expected behavior".
p.nextToken();
if (_objectIdReader != null) {
return deserializeWithObjectId(p, ctxt);
}
return deserializeFromObject(p, ctxt);
}
return _deserializeOther(p, ctxt, p.getCurrentToken());
}
protected Object vanillaDeserialize(JsonParser p, DeserializationContext ctxt, JsonToken t) throws IOException {
final Object bean = _valueInstantiator.createUsingDefault(ctxt);
// [databind#631]: Assign current value, to be accessible by custom serializers
p.setCurrentValue(bean);
Map<String, String> names = new HashMap<>();
if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {
String propName = p.getCurrentName();
do {
String oldName = names.put(propName.toLowerCase(), propName);
if (oldName != null) {
String msg = "Properties '" + propName + "' and '" + oldName + "' are the same!";
throw new DuplicateInsensitiveKeysException(p, msg);
}
defaultImplementation(p, ctxt, bean, propName);
} while ((propName = p.nextFieldName()) != null);
}
return bean;
}
private void defaultImplementation(JsonParser p, DeserializationContext ctxt, Object bean, String propName) throws IOException {
p.nextToken();
SettableBeanProperty prop = _beanProperties.find(propName);
if (prop != null) { // normal case
try {
prop.deserializeAndSet(p, ctxt, bean);
} catch (Exception e) {
wrapAndThrow(e, bean, propName, ctxt);
}
return;
}
handleUnknownVanilla(p, ctxt, bean, propName);
}
public static class DuplicateInsensitiveKeysException extends JsonMappingException {
public DuplicateInsensitiveKeysException(Closeable processor, String msg) {
super(processor, msg);
}
}
}
Пример использования:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.JsonTokenId;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.BeanDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializerBase;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new InsensitiveBeanDeserializerModifier());
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
mapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
System.out.println(mapper.readValue(jsonFile, User.class));
}
}
Для вышеупомянутых JSON
распечаток полезных нагрузок:
Exception in thread "main" InsensitiveBeanDeserializer$DuplicateInsensitiveKeysException: Properties 'NAME' and 'Name' are the same!