如何使用构建器Jackson反序列化包含泛型类型的对象?

时间:2016-06-03 08:12:41

标签: java jersey jackson deserialization dropwizard

我目前正在使用dropwizard开发一个小型Web应用程序。另一个应用程序可以向我的应用程序发送几种类型的消这些消息具有共同的基础和特定的内容,具体取决于消息的类型。

以下是消息的共同基础:

@JsonDeserialize(builder = BaseMessageBuilder.class)
public abstract class BaseMessage<T> {
    private String commonFiled;
    private T content;

    protected BaseMessage(BaseMessageBuilder<T> builder) {
        this.commonFiled = builder.getCommonField();
        this.content = builder.getContent();
    }

    public String getCommonField() {
        return commonFiled;
    }

    public T getContent() {
        return content;
    }
}

以下是消息共同基础的构建器:

@JsonPOJOBuilder
public class BaseMessageBuilder<T> {
    private String commonFiled;
    private T content;

    public String getCommonField() {
        return commonFiled;
    }

    public BaseMessageBuilder<T> withCommonField(String commonFiled) {
        this.commonFiled = commonFiled;
        return this;
    }

    public String getContent {
        return participants;
    }

    public BaseMessageBuilder<T> withContent(T content) {
        this.content = content;
        return this;
    }

    public BaseMessage<T> build() {
        return new BaseMessage<T>(this);
    }
}

以下是具体内容:

@JsonDeserialize(builder = SpecificContentBuilder.class)
public abstract class SpecificContent{
    private String field1;
    private Long field2;

    protected SpecificContent(SpecificMessageBuilder builder) {
        this.field1 = builder.getField1();
        this.field2 = builder.getField2();
    }

    public String getField1() {
        return field1;
    }

    public Long getField2() {
        return field2;
    }
}

以下是特定内容的构建者:

@JsonPOJOBuilder
public class SpecificContentBuilder {
    private String field1;
    private Long field2;

    public String getField1() {
        return commonFiled;
    }

    public SpecificContentBuilder withField1(String field1) {
        this.field1 = field1;
        return this;
    }

    public String getField2 {
        return field2;
    }

    public SpecificContentBuilder withField2(Long field2) {
        this.field2 = field2;
        return this;
    }

    public BaseMessage build() {
        return new BaseMessage<T>(this);
    }
}

这是我的资源:

@Path("/test")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class TestResource {

    @POST
    public void test(BaseMessage<SpecificContent> message) {
        // ...
    }

}

目前,当我的资源获取对象时,内容消息实际上并未获得正确的类型。当我调试它时,它自动为LinkedHashMap。我猜有些不对劲。任何人都可以帮助我吗?

编辑:

这是一个杰克逊问题(看看pandaadb的反应)。我删除了我的BaseMessageBuilder,并且我使用了一个静态构造函数来保持我的对象不可变。

public abstract class BaseMessage<T> {
    private String commonFiled;
    private T content;

    @JsonCreator
    public static <T> BaseMessage<T> newInstance(
            @JsonProperty("commonFiled") String commonFiled,
            @JsonProperty("content") T content) {
        return new WebhookEventBuilder()
                .withCommonFied(commonFiled)
                .withContent(content)
                .build();
    }

    protected BaseMessage(BaseMessageBuilder<T> builder) {
        this.commonFiled = builder.getCommonField();
        this.content = builder.getContent();
    }

    public String getCommonField() {
        return commonFiled;
    }

    public T getContent() {
        return content;
    }

    private static class BaseMessageBuilder<T> {
        private String commonFiled;
        private T content;

        public WebhookEventType getCommonFiled() {
            return commonFiled;
        }

        public BaseMessageBuilder withCommonFiled(String commonFiled) {
            this.commonFiled = commonFiled;
            return this;
        }

        public T getContent() {
            return content;
        }

        public BaseMessageBuilder withContent(T content) {
            this.content = content;
            return this;
        }

        public BaseMessage build() {
            return new BaseMessage(this);
        }
    }
}

1 个答案:

答案 0 :(得分:1)

试过这个,目前似乎不支持这个:

https://github.com/FasterXML/jackson-databind/issues/921

但是,对于您的示例,这是不必要的。杰克逊默认做正确的事情,例如,这个代码示例适用于我:

我有1个BaseMessage:

import { bootstrap }    from '@angular/platform-browser-dynamic';
import { provide } from '@angular/core';
import { LoginComponent } from './login.component';
import { ShoppingListComponent } from './shopping-list.component';
import { UserService } from './services/user.service';
import { UserServiceFactory } from './factories/UserServiceFactory';

bootstrap(LoginComponent, [provide(UserService, {useFactory:UserServiceFactory})]);
bootstrap(ShoppingListComponent, [provide(UserService, {useFactory:UserServiceFactory})]);

2种不同的内容类型:

public class BaseMessage<T> {

    @JsonProperty("val1")
    String val1;
    @JsonProperty("val2")
    T val2;
}

使用此资源:

public class Content {

    @JsonProperty("val1")
    String val1;
    @JsonProperty("val2")
    long val2;

}

public class Content2 {

    @JsonProperty("val1")
    String val1;
    @JsonProperty("val2")
    String val2;

}

点击测试网址,jackson成功检测到基本内容的类型T并创建正确的实例。

另一种选择是为BaseMessage类型编写自己的MessageBodyReader

我希望有所帮助,

阿图尔