«Расслабленные» имена полей для Джексона - PullRequest
1 голос
/ 25 апреля 2019

Я работаю над конфигурацией Jackson, и мне интересно, есть ли возможность десериализации различных типов шаблонов полей.

Например, у меня есть объект:

class DeserializeIt {
    String fieldOne;
    String fieldOneAndHalf;
    String fieldTwo;
    String fieldThree;
    String fieldFour;

   //getters setters etc.
}

А у меня ниже JSON Полезная нагрузка:

{
    "fieldOne" : "value1",
    "field_ONE-and_Half": "value15",
    "FIELD_TWO": "value2",
    "FIELD_THREE" : "value3",
    "field_four": "value4"
}

Я хотел бы десериализовать все эти имена полей для случая верблюда без исключения.

Я пытался создать свой пользовательский PropertyNamingStrategy, но он идет в другом направлении: он не преобразует разделенные поля в регистр верблюдов, он пытается преобразовать поля объектов и искать их в разобранной строке.

И поскольку я не могу передать список возможных строк вместо одного варианта (fieldOne может стать field-one, field_one, field-ONE и т. Д.), Это не работает.

Знаете ли вы, что еще я могу настроить для такой расслабленной десериализации?

Ответы [ 3 ]

0 голосов
/ 25 апреля 2019

В Jackson 2.9 вы можете указать несколько возможных имен свойств для десериализации, используя @ JsonAlias ​​аннотация . На вашем примере это было бы так:

class DeserializeIt {
  @JsonAlias("fieldOne") 
  String fieldOne;

  @JsonAlias("field_ONE-and_Half") 
  String fieldOneAndHalf;

  @JsonAlias("FIELD_TWO") 
  String fieldTwo;

  @JsonAlias("FIELD_THREE") 
  String fieldThree;
  // and so on...
}
0 голосов
/ 26 апреля 2019

Что сработало для меня: я добавил компонент AOP, который переименовывает все поля входящего объекта в корпус Camel.

0 голосов
/ 25 апреля 2019

Нам нужно расширить com.fasterxml.jackson.databind.deser.BeanDeserializerModifier и com.fasterxml.jackson.databind.deser.BeanDeserializer, которые десериализуют POJO классы. Приведенное ниже решение зависит от version, который вы используете, потому что я скопировал некоторый код из базового класса, который не готов к перехвату дополнительной функциональности. Если у вас нет дополнительной конфигурации для вашего метода POJO classes vanillaDeserialize, будет вызван этот метод, который мы постараемся улучшить.

В другом случае вам необходимо отладить этот десериализатор и обновить другие места, если это необходимо. Ниже в решении используется версия 2.9.8.

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.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.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 relaxedModule = new SimpleModule();
        relaxedModule.setDeserializerModifier(new RelaxedBeanDeserializerModifier());

        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(relaxedModule);

        System.out.println(mapper.readValue(jsonFile, DeserializeIt.class));
    }
}

class RelaxedBeanDeserializerModifier 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 RelaxedBeanDeserializer((BeanDeserializer) base);
        }

        return base;
    }
}

class RelaxedBeanDeserializer extends BeanDeserializer {

    private Map<String, String> properties = new HashMap<>();

    public RelaxedBeanDeserializer(BeanDeserializerBase src) {
        super(src);
        _beanProperties.forEach(property -> {
            properties.put(property.getName().toLowerCase(), property.getName());
        });
    }

    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);

        if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {
            String propName = p.getCurrentName();

            do {
                String relaxedName = getRelaxedName(propName);
                String mappedName = properties.get(relaxedName);
                defaultImplementation(p, ctxt, bean, mappedName);
            } 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);
    }

    private String getRelaxedName(String name) {
        return name.replaceAll("[_\\-]", "").toLowerCase();
    }
}

Над отпечатками кодов:

DeserializeIt{fieldOne='value1', fieldOneAndHalf='value15', fieldTwo='value2', fieldThree='value3', fieldFour='value4'}

Смотри также:

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