Jackson Mapper后期构建

时间:2011-07-26 18:24:45

标签: java mapping jackson

我正在使用Jackson ObjectMapper将一些JSON反序列化为Java类,我们将其称为PlayerData。我想在PlayerData类中添加一些逻辑来在加载字段后修复一些数据。例如,一些早期的JSON文件用于使用“性别”标志而不是“性别” “falg,所以如果设置了性别标志但未设置性别标志,我想将性别字段的值设置为性别字段的值。

是否有某种@PostConstruct或@AfterLoad注释可以粘贴到方法中?或者也许是我可以实现的界面?我没有注意到文档中的一个,但它似乎是一个显而易见的特征。

4 个答案:

答案 0 :(得分:15)

通过评论中的link找到了这一点(信用卡: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;
  }
}

答案 1 :(得分:6)

如果您没有使用@JsonCreator,那么Jackson将使用setter和getter方法设置字段。

因此,如果您定义以下方法,假设您有SexGender枚举:

@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;
  }
}

它会起作用。

更新:您可以找到杰克逊图书馆here的所有注释。

Update2 :其他解决方案:

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

}

答案 2 :(得分:4)

这实际上已经提前几次提出过。因此,提交RFE可能有意义;有多种方法可以使用:显而易见的是注释类型的能力(@JsonPostProcess(Processor.class))以及通过模块API注册后处理器的能力(因此当Jackson构造反序列化器时,基本上有一个回调,让模块指定后处理器使用(如果有的话)。但也许还有更好的方法可以做到这一点。

答案 3 :(得分:0)

开箱即用不支持此功能,但是您可以轻松地为反序列化后调用的方法创建@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带注释的反序列化对象的方法。