Jackson + Builder Modeli?


89

Jackson'ın aşağıdaki kurucu ile bir sınıfı seri halinden çıkarmasını istiyorum:

public Clinic(String name, Address address)

İlk argümanın serisini kaldırmak kolaydır. Sorun, Adresin şu şekilde tanımlanmasıdır:

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

ve şu şekilde inşa edilmiştir: new Address.Builder().setCity("foo").setCountry("bar").create();

Adresi kendim oluşturmak için Jackson'dan anahtar / değer çiftleri almanın bir yolu var mı? Alternatif olarak, Jackson'ın Builder sınıfının kendisini kullanmasını sağlamanın bir yolu var mı?

Yanıtlar:


142

Jackson 2+ kullandığınız sürece, artık bunun için yerleşik bir destek var .

Öncelikle bu ek açıklamayı Addresssınıfınıza eklemeniz gerekir :

@JsonDeserialize(builder = Address.Builder.class)

Sonra bu ek açıklamayı Buildersınıfınıza eklemeniz gerekir :

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

Oluşturucunuzun oluşturmak için oluşturma yöntemini yeniden adlandırmaktan ve Oluşturucunuzun ayarlayıcılarının set yerine önek olarak verilmesinden memnunsanız bu ikinci açıklamayı atlayabilirsiniz.

Tam örnek:

@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
@JsonPOJOBuilderEk açıklamadan hep birlikte kurtulmak isteniyorsa , "oluştur" u "oluşturmak" olarak yeniden adlandırın ve oluşturucu ayarlayıcıların her birine ile açıklama ekleyin @JsonProperty.
Sam Berry

bu altın. Teşekkürler.
Mukul Goel

Bu artık kullanabileceğiniz Lombok 1.18.4 ile, modası geçmiş @Jacksonizediç oluşturucu ve tek şeyle jackson ek açıklamaları değiştirir ki
Randakar

@Randakar Bunun modası geçmiş olduğunu düşünmüyorum çünkü a) Lombok'ta @Jackonized yeni yayınlanan bir deneysel özellik. Deneysel özelliklerin benimsenmesini gereksiz yere teşvik etmenin iyi bir fikir olduğunu düşünmüyorum. b) soru Lombok'tan bahsetmiyor veya kullanmıyor. Bir sorunu çözmek için gereksiz yere bağımlılık getirmenin iyi bir fikir olduğunu düşünmüyorum.
Rupert Madden-Abbott

20

@Rupert Madden-Abbott'ın cevabı işe yarıyor. Ancak, varsayılan olmayan bir kurucunuz varsa, ör.

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

Daha sonra parametreleri aşağıdaki gibi açıklamalısınız:

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

9

Bu durumda benim için uygun olan bir çözüm ("Lombok" oluşturucu açıklamasını kullandım).

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

Umarım sizin için de yararlı olur.


Bu artık modası geçmiş, Lombok 1.18.4 ile @Jacksonizediç inşaatçıyı ve jackson ek açıklamalarını tek bir şeyle değiştiren kullanabilirsiniz
Randakar

7

Bunu @JsonDeserialize kullanarak aşağıdaki gibi uyguladım:

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

Bu, onu nasıl uyguladığınız olabilir, ancak bu cevap aslında soruyu sorulduğu gibi yanıtlamaz. @Rupert Madden-Abbott tarafından gönderilen cevap, kabul edilen cevap olarak işaretlenmelidir.
kelnos

2

Şu anda oluşturucu kalıbı için destek yok, ancak oldukça uzun bir süre önce talep edilmiş (ve son olarak Jira sorunu http://jira.codehaus.org/browse/JACKSON-469 dosyalanmış) - bu eklenebilir bir şeydir Yeterli talep varsa 1.8 sürümü için (Jira'da oy kullandığınızdan emin olun!). Makul bir ek özelliktir ve yalnızca geliştiricilerin sahip olduğu süre kadar gecikir. Ama bunun harika bir katkı olacağını düşünüyorum.


2
Codehaus'ta artık Jira mevcut değil, ancak bağlantılı sorun burada açıklanmaktadır: wiki.fasterxml.com/JacksonFeatureBuilderPattern
Paul

Builder kalıbı desteği, Jackson 2.2 gibi bir şeye çoktan eklendi.
StaxMan

2

Bu benim için çalıştı: @NoArgsConstructor Bunun tek dezavantajı, birinin tekrar = new ADTO () yapabilmesidir. Ama, hey, zaten kod polisini sevmiyorum, bana birilerinin kodunu nasıl kullanacağımı söylemekten hoşlanmıyorum :-) Yani, POJO DTOS'umu istediğiniz şekilde kullanın. Oluşturucu ile veya olmadan. Ben şunu öneririm: Bir İnşaatçı ile yapın, ama misafirim olun ...

@Data
@Builder
//Dont forget this! Otherwise no Jackson serialisation possible!
@NoArgsConstructor
@AllArgsConstructor
public class ADTO {
.....
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.