2011-02-13 90 views
39

我想杰克逊反序列化类下面的构造:Jackson + Builder模式?

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();

有没有一种办法,以构建自己的地址从杰克逊获得键值对?或者,有没有办法让Jackson使用Builder类本身?

回答

6

我结束了实施这一使用@JsonDeserialize如下:只要你使用的是杰克逊2+,再有就是现在built in support for this

@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(); 
    } 
} 
2

目前尚不支持构建器模式,虽然它已被要求相当一段时间(最终Jira问题http://jira.codehaus.org/browse/JACKSON-469已提交) - 如果有足够的需求,它可以添加到1.8版本中一定要在Jira投票!)。这是一个合理的附加功能,只会延误开发人员的时间。但我认为这将是很好的补充。

+1

Codehaus不再有Jira可用,但链接的问题在这里描述:http://wiki.fasterxml.com/JacksonFeatureBuilderPattern – Paul 2016-02-26 14:10:06

+0

支持Builder模式已经很久以来,像杰克逊2.2一样。 – StaxMan 2016-03-16 05:17:33

66

首先,你需要这个注释添加到您的Address类:

@JsonDeserialize(builder = Address.Builder.class) 

然后,你需要这个注释添加到您的Builder类:

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

,如果你可以跳过第二个注解很乐意重新命名你的Builder的create方法来构建,而你的Builder的setter将被设置为前缀而不是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(); 
    } 
} 
15

从@Rupert劲爆雅培答案的作品。但是,如果你有一个非默认的构造函数,例如,

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

那么你应该标注的参数如下:

@JsonCreator 
Builder(@JsonProperty("city") String city, 
     @JsonProperty("country") String country) {...} 
0

这是适合我这种情况下的解决方案(我用“龙目岛“建造者注释)。

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

我希望对你也有用。