如何创建一般的JsonDeserializer

时间:2015-09-14 13:01:10

标签: java jackson

我需要创建一个通用的解串器;换句话说,我不知道反序列化的目标类是什么。

我在互联网上看到了一些示例,他们创建了一个反序列化器,例如JsonDeserializer<Customer>,然后在最后返回new Customer(...)。问题是我不知道返回类是什么。

我想我需要使用反射来创建类的实例并填充该字段。我如何从反序列化方法中做到这一点?

public class JsonApiDeserializer extends JsonDeserializer<Object> {

    @Override
    public Object deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {

        //Need to parse the JSON and return a new instance here
    }

}

6 个答案:

答案 0 :(得分:1)

基本上,您只需要处理2个案例,envObject,您可以随时将其反序列化为:

  1. 地图
  2. 一个Map数组
  3. 这样的事情应该有效:

    Object[]

    免责声明:未经编译且未经测试

答案 1 :(得分:1)

我使用ContextualDeserializer

开始工作
public class JsonApiDeserializer extends JsonDeserializer<Object> implements
        ContextualDeserializer {

    private Class<?> targetClass;

    @SneakyThrows
    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        Object clazz = targetClass.newInstance();

        //Now I have an instance of the annotated class I can populate the fields via reflection

        return clazz;
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
            BeanProperty property) throws JsonMappingException {
        //gets the class type of the annotated class
        targetClass = ctxt.getContextualType().getRawClass();
        return this;
    }

}

我仍然不确定为什么会这样,因为我在原始的反序列化方法中已经有DeserializationContext ctxt但是当我执行null时它会返回ctxt.getContextualType()

有人可以解释一下吗?

答案 2 :(得分:1)

经过一些测试,我发现@jax的答案有问题。

正如@Staxman指出的那样,在构造反序列化器时调用createContextual(),而不是在每个反序列化过程中调用createContextual。由public class JsonApiDeserializer extends JsonDeserializer<Object> implements ContextualDeserializer { private Class<?> targetClass; public JsonApiDeserializer() { } public JsonApiDeserializer(Class<?> targetClass) { this.targetClass = targetClass; } @Override public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { Object clazz = targetClass.newInstance(); //Now I have an instance of the annotated class I can populate the fields via reflection return clazz; } @Override public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException { //gets the class type of the annotated class targetClass = ctxt.getContextualType().getRawClass(); //this new JsonApiDeserializer will be cached return new JsonApiDeserializer(targetClass); } } 返回的反序列化器将由Jackson库缓存。因此,如果您的反序列化器使用多于一种类型(例如公共父类型的子类型),它将抛出类型不匹配异常,因为targetClass属性将是Jackson库缓存的最后一种类型。

正确的解决方案应该是:

var User = require('../modules/user');
var config = require('../../config');

var secretKey = config.secretKey;

module.exports = function(app,express){
    var api = express.Router;
    api.post('/signup', function(req,res){
        var user = new User({
            name: req.body.name,
            username: req.body.username,
            password: req.body.password
        });

        user.save(function(err){
            if(err){
                res.send(err);
                return;
            }

            res.json({ message: 'user has been created'});
        })
    });

    return api;
};

答案 3 :(得分:0)

如果您事先知道邮件结构,则可以使用this tool从给定的POJO字符串轻松生成JSON

但是,如果您的消息格式在运行时更改,并且没有其他信息可供您确定类型(例如,header信息),则可以将其反序列化为Map并处理字段手动

例如,杰克逊:

ObjectMapper mapper = new ObjectMapper();
Map<String, Object> userData = mapper.readValue(jsonData, Map.class);

答案 4 :(得分:0)

我不确定我的问题是否正确,但您可以做的是检查deserialiser中json的属性,例如:


ObjectMapper objectMapper = (ObjectMapper) jp.getCodec();
ObjectNode node = objectMapper.readTree(jp);
然后是node.has(“propertyName”),这样你就可以创建,设置和返回你的对象,并让deserialiser的客户端负责演员。

你说“换句话说,我不知道反序列化的目标类是什么。”

所以如果你至少可以推断出来,我就不会得到,更多的信息会有所帮助

答案 5 :(得分:0)

如果您知道哪些类可以在编译时反序列化,但需要在运行时根据JSON内容动态选择正确的类,我可以建议如下。

  1. 在JSON中添加一些分类器字段。此字段将帮助您的代码知道如何处理以下数据。据我所知,您已经拥有了&#34;类型&#34; 字段,因此可以使用。
  2. 引入一个工厂,它将根据JSON的输入实例化特定的类。例如,它可能具有 Object create(string typeFromJson,Map data)之类的方法。这样的工厂也可以使用数据填充新创建的对象。
  3. 如果情况并非如此,并且您已经不知道所需的接口,那么您就遇到了麻烦。可以通过使用 dynamic 关键字在C#中进行一些解决,但Java还没有这样的功能。

    另外,在AFAIK中,杰克逊有一种方法可以指定需要自动反序列化并注入REST资源类中的 @Post 方法调用的类。