如何将派生属性添加到Jackson 2序列化类? [英] How to add derived properties to a Jackson 2 serialized class?

查看:167
本文介绍了如何将派生属性添加到Jackson 2序列化类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Jackson 2.22序列化一些现有对象,使用MixIn功能将真实对象与Jackson注释配置分离。



实际上我的mixin是一个界面声明了目标类的相同方法并对它们进行了注释,这是一个例子。



目标类:

  public class Product {

// ...

public String getName();

public String getDescription();

public String getPrice();

public String getFinalPrice();

public String getDiscount();

// ...

}

和mixin:

  public interface ProductApi {

@JsonProperty
public String getName();

@JsonProperty(price)
public String getFinalPrice();

}

我的JSON应该有更多的信息,从几种方法计算出来或目标类别的字段。



杰克逊甚至可以这样做吗?



我试过把混合物转入一个类,并在那里添加一个新方法,但是没有用。

  public class ProductApi {

@JsonProperty
public String getName();

@JsonProperty(price)
public String getFinalPrice();

@JsonProperty(images)
public List< String> getImages(){/ * ... * /}

}

我想这是因为mixin只为目标类提供注释,但后者是为序列化而读取的。



当然,如果我将对象更改为使用包含我需要的新方法的新子类序列化,但是这些对象来自我们的服务层,这意味着我必须重写所有这些方法。



<我正在使用杰克逊与泽西岛,所以不想用另一个图书馆改变杰克逊。

解决方案

这是我的方式做到了。



解决方案是指定一个自定义 JsonSerializer 实现到字段getter。



首先,我更改了mixin 接口到扩展实体的(目标t)类,以便它可以访问目标类数据。

 公共类ProductApi扩展产品{

@JsonProperty
@Override
public String getName(){
return super.getName();
};

// ...

}

接下来,我实现了 JsonSerializer ,它将创建我想要的派生属性:

  public static class ImagesSerializer扩展JsonSerializer< String> {

@Override
public void serialize(String value,JsonGenerator jgen,SerializerProvider provider)抛出IOException,JsonProcessingException {
Product p =(Product)jgen.getCurrentValue();

int num = p.getNumberOfImages();

List< String> imgs = new ArrayList< String>(num);

for(int i = 0; i< num; i ++){
String src =/include/images/showImage.jsp?\"+\"id=\"+p.getId ()+ &安培;数= + I;
imgs.add(src);
}

provider.defaultSerializeValue(imgs,jgen);
}

}

这是真的简单的实现,应该进行更多的安全检查。



这样做基本上是从JSON生成器检索整个实体实例,构建一个自定义对象,然后让杰克逊序列化它。

我在我的 ProductApi 中实现了它作为静态类,但为了简单起见。



最后,序列化器需要绑定到 JsonProperty 带注释的字段:



< pre class =lang-java prettyprint-override> public class ProductApi extends Product {

@JsonProperty
@Override
public String getName(){
返回super.getName();
};

// ...

@JsonSerialize(using = ImagesSerializer.class)
@JsonProperty(images)
@Override
public String getImage(){//在我的实体中返回一个图像编号,而在我的JSON中我想要一个URL列表
返回;
}

// ...

}

作为附注,似乎没有使用 getImage()方法的返回值。


I'm serializing some existing objects with Jackson 2.22, leveragin the MixIn feature to decouple the real object from the Jackson annotations configuration.

Actually my mixin is an interface that declares the same methods of the target class and annotates them, here's an example.

Target class:

public class Product {

    // ...

    public String getName();

    public String getDescription();

    public String getPrice();

    public String getFinalPrice();

    public String getDiscount();

    // ...

}

and the mixin:

public interface ProductApi {

    @JsonProperty
    public String getName();

    @JsonProperty("price")
    public String getFinalPrice();

}

My JSON should have some more informations, computed from several methods or fields of the target class.

Is this even possible in Jackson?

I tried turning the mixin in a class and adding a new method there, but that didn't work.

public class ProductApi {

    @JsonProperty
    public String getName();

    @JsonProperty("price")
    public String getFinalPrice();

    @JsonProperty("images")
    public List<String> getImages() { /* ... */ }

}

I guess this is because the mixin only provides annotations for the target class, but is the latter that is read for serialization.

Of course, if I change the object to be serialized with a new subclass that contains the new method I need, that works, but the objects come from our services layers, and this would mean I have to rewrite all those methods.

I'm using Jackson with Jersey, so don't want to change Jackson with another library.

解决方案

Here's how I did it.

The solution is to specify a custom JsonSerializer implementation to the field getter.

First of all, I changed the mixin interface to a class that extends the entity (target) class, so that it can access the target class data.

public class ProductApi extends Product {

    @JsonProperty
    @Override
    public String getName() {
        return super.getName();
    };

    // ...

}

Next, I implemented the JsonSerializer that would create the derived property I want:

public static class ImagesSerializer extends JsonSerializer<String> {

    @Override
    public void serialize(String value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
        Product p = (Product) jgen.getCurrentValue();

        int num = p.getNumberOfImages();

        List<String> imgs = new ArrayList<String>(num);

        for(int i = 0; i < num; i++) {
            String src = "/include/images/showImage.jsp?"+"id="+p.getId()+"&number="+i;
            imgs.add(src);
        }

        provider.defaultSerializeValue(imgs, jgen);
    }

}

This is a really simple implementation, more safety checks should be done.

What this does is, basically, retrieve the whole entity instance from the JSON generator, build up a custom object and then ask Jackson to serialize it.
I implemented it inside my ProductApi as a static class, but just for simplicity.

Finally, the serializer needs to be bound to the JsonProperty annotated field:

public class ProductApi extends Product {

    @JsonProperty
    @Override
    public String getName() {
        return super.getName();
    };

    // ...

    @JsonSerialize(using=ImagesSerializer.class)
    @JsonProperty("images")
    @Override
    public String getImage() { // in my entity this returns an image number, whereas in my JSON I want a list of URLs
        return "";
    }

    // ...

}

As a side note, it seems that the returned value of the getImage() method is not used.

这篇关于如何将派生属性添加到Jackson 2序列化类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆