Подтвердить что ты не робот

Постконструкция Jackson Mapper

Я использую Jackson ObjectMapper для десериализации некоторого JSON в класс Java, который мы будем называть PlayerData. Я хотел бы добавить немного логики в класс PlayerData, чтобы исправить некоторые данные после того, как поля были загружены. Например, некоторые ранние файлы JSON, используемые для использования "пола", вместо "гендерного" фальца, поэтому, если установлен флаг пола, но гендерный флаг не установлен, я хотел бы установить значение поля пола как значение поля для пола.

Есть ли какая-то аннотация @PostConstruct или @AfterLoad, которую я мог бы привязать к методу? Или, может быть, интерфейс, который я мог бы реализовать? Я не заметил этого в документации, но это казалось очевидной особенностью.

4b9b3361

Ответ 1

Обнаружено по ссылке в комментариях (кредит: fedor.belov). Похоже, это позволяет вам запускать пост-конструкцию кода.

Добавление комментария для людей, которые попадают сюда через http://jira.codehaus.org/browse/JACKSON-645 или http://jira.codehaus.org/browse/JACKSON-538 и ищем метод, который вызывается после завершения десериализации. я мог достичь желаемого эффекта, добавив аннотацию и написав конвертер, который использует тот же класс, что и вход и выход.

@JsonDeserialize(converter=MyClassSanitizer.class)  // invoked after class is fully deserialized
public class MyClass {
    public String field1;
}

import com.fasterxml.jackson.databind.util.StdConverter;
public class MyClassSanitizer extends StdConverter<MyClass,MyClass> {
  @Override
  public MyClass convert(MyClass var1) {
    var1.field1 = munge(var1.field1);
    return var1;
  }
}

Ответ 2

Если вы не используете @JsonCreator, то Джексон будет использовать методы setter и getter для установки полей.

Таким образом, если вы определили следующие методы при условии, что у вас есть Sex и Gender перечисления:

@JsonProperty("sex")
public void setSex(final Sex sex) {
  this.sex = sex;
  if (gender == null) {
    gender = (sex == Sex.WOMAN) ? Gender.WOMAN : Gender.MAN;
  }
}

@JsonProperty("gender")
public void setGender(final Gender gender) {
  this.gender = gender;
  if (sex == null) {
    sex = (gender == Gender.WOMAN) ? Sex.WOMAN : Sex.MAN;
  }
}

это будет работать.

Обновление: Вы можете найти все аннотации библиотеки Джексона здесь.

Обновление 2: Другое решение:

class Example {
  private final Sex sex;
  private final Gender gender;

  @JsonCreator
  public Example(@JsonProperty("sex") final Sex sex) {
    super();
    this.sex = sex;
    this.gender = getGenderBySex(sex)
  }

  @JsonFactory
  public static Example createExample(@JsonProperty("gender") final Gender gender) {
    return new Example(getSexByGender(gender));
  }

  private static Sex getSexByGender(final Gender) {
    return (gender == Gender.WOMAN) ? Sex.WOMAN : Sex.MAN;
  }

  private static Gender getGenderBySex(final Sex) {
    return (sex == Sex.WOMAN) ? Gender.WOMAN : Gender.MAN;
  }

}

Ответ 3

Это то, что на самом деле было предложено пару раз раньше. Поэтому, возможно, оформление RFE будет иметь смысл; существует несколько способов, которыми это может работать: очевидными являются способность комментировать тип (@JsonPostProcess (Processor.class)) и возможность регистрировать постпроцессор через API-интерфейс модуля (так что там в основном обратный вызов, когда Джексон создает десериализатор, чтобы позволить модуль определяет постпроцессор для использования, если таковой имеется). Но, возможно, есть еще лучшие способы сделать это.

Ответ 4

Это не поддерживается сразу после установки, но вы можете легко создать свою аннотацию @JsonPostDeserialize для методов, вызываемых после десериализации.

Сначала определите аннотацию:

/**
 * Annotation for methods to be called directly after deserialization of the object.
 */
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonPostDeserialize {
}

Затем добавьте следующий код регистрации и реализации в свой проект:

public static void addPostDeserializeSupport(ObjectMapper objectMapper) {
    SimpleModule module = new SimpleModule();
    module.setDeserializerModifier(new BeanDeserializerModifier() {
        @Override
        public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDescription,
                JsonDeserializer<?> originalDeserializer) {
            return new CustomAnnotationsDeserializer(originalDeserializer, beanDescription);
        }
    });
    objectMapper.registerModule(module);
}

/**
 * Class implementing the functionality of the {@link JsonPostDeserialize} annotation.
 */
public class CustomAnnotationsDeserializer extends DelegatingDeserializer {
    private final BeanDescription beanDescription;

    public CustomAnnotationsDeserializer(JsonDeserializer<?> delegate, BeanDescription beanDescription) {
        super(delegate);
        this.beanDescription = beanDescription;
    }

    @Override
    protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDelegatee) {
        return new CustomAnnotationsDeserializer(newDelegatee, beanDescription);
    }

    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        Object deserializedObject = super.deserialize(p, ctxt);

        callPostDeserializeMethods(deserializedObject);
        return deserializedObject;
    }

    private void callPostDeserializeMethods(Object deserializedObject) {
        for (AnnotatedMethod method : beanDescription.getClassInfo().memberMethods()) {
            if (method.hasAnnotation(JsonPostDeserialize.class)) {
                try {
                    method.callOn(deserializedObject);
                } catch (Exception e) {
                    throw new RuntimeException("Failed to call @JsonPostDeserialize annotated method in class "
                            + beanDescription.getClassInfo().getName(), e);
                }
            }
        }
    }
}

Наконец, измените ваш экземпляр ObjectMapper с помощью addPostDeserializeSupport, он вызовет весь аннотированный метод @JsonPostDeserialize десериализованных объектов.