102

我希望杰克逊使用以下构造函数反序列化一个类:

public Clinic(String name, Address address)

反序列化第一个参数很容易。问题是地址被定义为:

public class Address {
  private Address(Map<LocationType, String> components)
  ...

  public static class Builder {
    public Builder setCity(String value);
    public Builder setCountry(String value);
    public Address create();
  }
}

并且是这样构造的:new Address.Builder().setCity("foo").setCountry("bar").create();

有没有办法从杰克逊那里获取键值对以便自己构建地址?或者,有没有办法让杰克逊使用 Builder 类本身?

4

6 回答 6

158

只要您使用的是 Jackson 2+,那么现在就内置了对此的支持

首先,您需要将此注释添加到您的Address类中:

@JsonDeserialize(builder = Address.Builder.class)

然后您需要将此注释添加到您的Builder类中:

@JsonPOJOBuilder(buildMethodName = "create", withPrefix = "set")

如果您愿意将 Builder 的 create 方法重命名为 build,并且您的 Builder 的 setter 以 with 为前缀,而不是 set,则可以跳过第二个注释。

完整示例:

@JsonDeserialize(builder = Address.Builder.class)
public class Address
{
  private Address(Map<LocationType, String> components)
  ...

  @JsonPOJOBuilder(buildMethodName = "create", withPrefix = "set")
  public static class Builder
  {
    public Builder setCity(String value);
    public Builder setCountry(String value);
    public Address create();
  }
}
于 2014-02-07T10:01:31.297 回答
22

@Rupert Madden-Abbott 的回答很有效。但是,如果您有一个非默认构造函数,例如,

Builder(String city, String country) {...}

然后你应该如下注释参数:

@JsonCreator
Builder(@JsonProperty("city")    String city, 
        @JsonProperty("country") String country) {...}
于 2014-08-01T17:35:17.553 回答
10

在这种情况下适合我的解决方案(我使用了“Lombok”构建器注释)。

@Getter
@Builder(builderMethodName = "builder")
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@JsonAutoDetect(
    fieldVisibility = JsonAutoDetect.Visibility.ANY,
    creatorVisibility = JsonAutoDetect.Visibility.ANY
)

我希望对你也有用。

于 2018-03-06T06:50:13.643 回答
7

我最终使用@JsonDeserialize 实现了这一点,如下所示:

@JsonDeserialize(using = JacksonDeserializer.class)
public class Address
{...}

@JsonCachable
static class JacksonDeserializer extends JsonDeserializer<Address>
{
    @Override
    public Address deserialize(JsonParser parser, DeserializationContext context)
        throws IOException, JsonProcessingException
    {
        JsonToken token = parser.getCurrentToken();
        if (token != JsonToken.START_OBJECT)
        {
            throw new JsonMappingException("Expected START_OBJECT: " + token, parser.getCurrentLocation());
        }
        token = parser.nextToken();
        Builder result = new Builder();
        while (token != JsonToken.END_OBJECT)
        {
            if (token != JsonToken.FIELD_NAME)
            {
                throw new JsonMappingException("Expected FIELD_NAME: " + token, parser.getCurrentLocation());
            }
            LocationType key = LocationType.valueOf(parser.getText());

            token = parser.nextToken();
            if (token != JsonToken.VALUE_STRING)
            {
                throw new JsonMappingException("Expected VALUE_STRING: " + token, parser.getCurrentLocation());
            }
            String value = parser.getText();

            // Our Builder allows passing key-value pairs
            // alongside the normal setter methods.
            result.put(key, value);
            token = parser.nextToken();
        }
        return result.create();
    }
}
于 2011-02-14T03:53:36.463 回答
3

目前没有对构建器模式的支持,尽管它已经在很久以前被请求过(最后 Jira 问题http://jira.codehaus.org/browse/JACKSON-469被提交)——它可能会被添加如果有足够的需求,则发布 1.8 版本(确保在 Jira 投票!)。这是一个合理的附加功能,只是延迟了开发人员的时间。但我认为这将是一个很好的补充。

于 2011-02-13T07:21:36.000 回答
3

这对我有用:@NoArgsConstructor 唯一的缺点是可以再次执行 = new ADTO() 。但是,嘿,无论如何,我不喜欢解码警察,告诉我如何使用某人的代码 :-) 所以,按照你喜欢的方式使用我的 POJO DTOS。有或没有建造者。我建议:和 Builder 一起做,但做我的客人......

@Data
@Builder
//Dont forget this! Otherwise no Jackson serialisation possible!
@NoArgsConstructor
@AllArgsConstructor
public class ADTO {
.....
}
于 2019-12-12T08:56:14.393 回答