• 2014-02-15

    Jackson雕虫技(三)

    Tag:jackson

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-logs/258185547.html

    Jackson雕虫技(一)
    Jackson雕虫技(二)

    使用Builder模式

    在日常开发中,我们希望自己编写的类尽可能不变的,对于参数比较多的类,我们通常采用的方法是Builder模式。但如果我们使用Builder模式构造这样的不变对象,当我们将json反序列化成Java对象该怎么办呢?

    Jackson已经为这种做法做好了准备,我们可以告诉它这个类是采用Builder模式构建的:

    @JsonDeserialize(builder = DefaultHttpRequest.Builder.class)
    public class DefaultHttpRequest implements HttpRequest {
     ...
    }

    我们使用了一个Annotaiton:@JsonDeserialize,通过builder参数告诉它,用哪个类做Builder。这里用的就是这个类的一个内嵌类:Builder。

    public class DefaultHttpRequest implements HttpRequest {
       ...

      public static final class Builder {

        ...

        public Builder withVersion(String version) {
          this.version = version;
          return this;
       }

        ...

        public DefaultHttpRequest build() {
          ...
          return request;
       }
      }
    }

    其中,以with开头的就是用来传参数的方法,而build方法则用以构建最终的对象,这是一个缺省的约定。我们还可以按照自己的需要进行订制,只不过要给我们的Builder加上另外一个Annotation:@JsonPOJOBuilder。下面是一个例子:

    @JsonPOJOBuilder(buildMethodName="create", withPrefix="con")
    public static final class Builder {
       ...
    }

    这样一来,所有传参的方法都是以con开头,而构建对象的方法名则改成了create。

    使用对象简化解析

    在《Jackson雕虫技(二)》,我们提到了可以用自定义解析的方式解析对象,但一个一个字段解析写起来并不直观。其实,我们还可以借用已有的对象解析机制简化这个过程。下面是MocoProxyContainerDeserializer,它根据当前正在解析的目标进行处理,要么解析成一个URL,要么解析成一个Proxy的配置。

    public class ProxyContainerDeserializer extends JsonDeserializer {
       @Override
       public ProxyContainer deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
        JsonToken currentToken = jp.getCurrentToken();
         if (currentToken == JsonToken.VALUE_STRING) {
          return builder().withUrl(jp.getText().trim()).build();
        } else if (currentToken == JsonToken.START_OBJECT) {
          InternalProxyContainer container = get(jp.readValuesAs(InternalProxyContainer.class), 0);
          return container.toProxyContainer();
       }

        throw ctxt.mappingException(TextContainer.class, currentToken);
      }
    }

    这里的关键是readValuesAs,我们没有直接解析接下来的Token,而是确定解析目标之后,又借用了解析器本身的能力,把它解析成一个对象。至于InternalProxyContainer,它只是一个简单的对象类,用以装载解析的结果。

    private static class InternalProxyContainer {
      public String url;
      public String from;
      public String to;
      public String failover;
      public String playback;

      public ProxyContainer toProxyContainer() {
        ...
      }
    }

    分享到:

    历史上的今天:

    告别外星人 2011-02-15
    引用地址: