잭슨 + 빌더 패턴?


89

Jackson이 다음 생성자를 사용하여 클래스를 역 직렬화하기를 원합니다.

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에서 키-값 쌍을 얻는 방법이 있습니까? 또는 Jackson이 Builder 클래스 자체를 사용하도록하는 방법이 있습니까?

답변:


140

Jackson 2+를 사용하는 한 이제 이를 지원하는 기능이 내장되어 있습니다.

먼저이 주석을 Address클래스 에 추가해야합니다 .

@JsonDeserialize(builder = Address.Builder.class)

그런 다음이 주석을 Builder클래스 에 추가해야합니다 .

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

빌드 할 Builder의 create 메서드와 set 대신 접두사가 붙을 Builder의 setter의 이름을 바꾸고 싶다면이 두 번째 주석을 건너 뛸 수 있습니다.

전체 예 :

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

14
@JsonPOJOBuilder주석을 모두 제거하려면 "create"의 이름을 "build"로 바꾸고 각 빌더 setter에 @JsonProperty.
Sam Berry

이것은 황금색입니다. 감사.
Mukul Goel

이것은 이제 구식입니다. Lombok 1.18.4를 사용 @Jacksonized하면 내부 빌더와 jackson 주석을 단일 항목으로 대체 할 수 있습니다
Randakar

@Randakar 나는 a) @Jackonized 가 롬복에서 방금 출시 된 실험적 기능 이기 때문에 이것이 구식이라고 생각하지 않습니다 . 불필요하게 실험적 기능의 채택을 장려하는 것은 좋은 생각이 아니라고 생각합니다. b) 질문이 롬복을 언급하거나 사용하지 않습니다. 문제를 해결하기 위해 불필요하게 의존성을 도입하는 것은 좋은 생각이 아니라고 생각합니다.
Rupert Madden-Abbott

19

@Rupert Madden-Abbott의 답변이 작동합니다. 그러나 기본이 아닌 생성자가있는 경우 (예 :

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

그런 다음 아래와 같이 매개 변수에 주석을 추가해야합니다.

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

9

이 경우 저에게 적합한 솔루션입니다 ( "Lombok"빌더 주석 사용).

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

나는 당신에게도 유용하기를 바랍니다.


이것은 이제 구식입니다. Lombok 1.18.4를 사용 @Jacksonized하면 내부 빌더와 jackson 주석을 단일 항목으로 대체 할 수 있습니다
Randakar

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

이것은 당신이 그것을 구현 한 방법 일 수 있지만이 답변은 실제로 제기 된 질문에 대한 답변이 아닙니다. @Rupert Madden-Abbott가 게시 한 답변은 수락 된 답변으로 표시되어야합니다.
kelnos

2

현재 빌더 패턴에 대한 지원은 없지만 꽤 오래 전에 요청되었습니다 (그리고 마지막으로 Jira 문제 http://jira.codehaus.org/browse/JACKSON-469 가 제출되었습니다)-추가 될 수 있습니다. 충분한 수요가있는 경우 1.8 릴리스를 위해 (Jira에서 투표해야합니다!) 합리적인 추가 기능이며 개발자가 보유한 시간만큼만 지연됩니다. 그러나 나는 그것이 큰 도움이 될 것이라고 생각합니다.


2
Codehaus는 더 이상 Jira를 사용할 수 없지만 링크 된 문제는 여기에 설명되어 있습니다. wiki.fasterxml.com/JacksonFeatureBuilderPattern
Paul

Builder 패턴에 대한 지원은 Jackson 2.2와 같이 추가 된 지 오래되었습니다.
StaxMan

2

이것은 나를 위해 일했습니다 : @NoArgsConstructor 이것의 유일한 단점은 = new ADTO ()를 다시 할 수 있다는 것입니다. 그러나 야, 나는 어떻게 든 코드 경찰을 좋아하지 않는다. 누군가의 코드를 사용하는 방법을 말하면서 :-) 그래서, 내 POJO DTOS를 당신이 좋아하는 방식으로 사용하십시오. 빌더 유무에 관계없이. 나는 제안한다 : 건축업자와 함께하되 나의 손님이 되어라 ...

@Data
@Builder
//Dont forget this! Otherwise no Jackson serialisation possible!
@NoArgsConstructor
@AllArgsConstructor
public class ADTO {
.....
}

다른 사람의 코드를 사용하는 방법을 알고 싶지 않습니까?
masterxilo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.