ObjectMapper kullanarak varsayılan kurucu olmadan değişmez bir nesneyi nasıl çözülür / serileştirilir?


106

Com.fasterxml.jackson.databind.ObjectMapper kullanarak değişmez bir nesneyi serileştirmek ve serisini kaldırmak istiyorum.

Değişmez sınıf şuna benzer (yalnızca 3 dahili özellik, alıcılar ve yapıcılar):

public final class ImportResultItemImpl implements ImportResultItem {

    private final ImportResultItemType resultType;

    private final String message;

    private final String name;

    public ImportResultItemImpl(String name, ImportResultItemType resultType, String message) {
        super();
        this.resultType = resultType;
        this.message = message;
        this.name = name;
    }

    public ImportResultItemImpl(String name, ImportResultItemType resultType) {
        super();
        this.resultType = resultType;
        this.name = name;
        this.message = null;
    }

    @Override
    public ImportResultItemType getResultType() {
        return this.resultType;
    }

    @Override
    public String getMessage() {
        return this.message;
    }

    @Override
    public String getName() {
        return this.name;
    }
}

Ancak bu birim testini çalıştırdığımda:

@Test
public void testObjectMapper() throws Exception {
    ImportResultItemImpl originalItem = new ImportResultItemImpl("Name1", ImportResultItemType.SUCCESS);
    String serialized = new ObjectMapper().writeValueAsString((ImportResultItemImpl) originalItem);
    System.out.println("serialized: " + serialized);

    //this line will throw exception
    ImportResultItemImpl deserialized = new ObjectMapper().readValue(serialized, ImportResultItemImpl.class);
}

Bu istisnayı anlıyorum:

com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class eu.ibacz.pdkd.core.service.importcommon.ImportResultItemImpl]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
 at [Source: {"resultType":"SUCCESS","message":null,"name":"Name1"}; line: 1, column: 2]
    at 
... nothing interesting here

Bu istisna benden varsayılan bir kurucu oluşturmamı istiyor, ancak bu değişmez bir nesne, bu yüzden ona sahip olmak istemiyorum. Dahili nitelikleri nasıl belirlerdi? API kullanıcısının tamamen kafasını karıştırır.

Öyleyse sorum şu: Varsayılan kurucu olmadan değişmez nesneleri bir şekilde de / serileştirebilir miyim?


Desrialize ederken, desrializer kurucunuzun hiçbirini bilmiyor, bu yüzden varsayılan kurucuya isabet ediyor. Bu nedenle, değişmezliği değiştirmeyecek varsayılan bir kurucu oluşturmanız gerekir. Ayrıca dersin son olmadığını görüyorum, neden öyle? kimse işlevselliği geçersiz kılabilir, değil mi?
Abhinaba Basu 01

Ders bitmedi, çünkü oraya yazmayı unuttum, fark ettiğin için teşekkürler :)
Michal

Yanıtlar:


149

Jackson'a seriyi kaldırma amacıyla bir nesneyi nasıl oluşturacağını bildirmek için, oluşturucularınız için @JsonCreatorve @JsonPropertyek açıklamalarını şu şekilde kullanın:

@JsonCreator
public ImportResultItemImpl(@JsonProperty("name") String name, 
        @JsonProperty("resultType") ImportResultItemType resultType, 
        @JsonProperty("message") String message) {
    super();
    this.resultType = resultType;
    this.message = message;
    this.name = name;
}

1
+1 teşekkürler Sergey. İşe yaradı .. ancak JsonCreator ek açıklamasını kullandıktan sonra bile sorun yaşıyordum .. ancak bazı incelemelerden sonra kaynağımda RequestBody ek açıklamasını kullanmayı unuttuğumu fark ettim. Şimdi çalışıyor .. Bir kez daha teşekkürler.
Rahul

4
Ya bir varsayılan kurucu veya ekleyemezsiniz eğer @JsonCreatorve @JsonPropertybunu değiştirmek için POJO erişimi yok çünkü ek açıklamaları? Nesneyi seri halinden çıkarmanın hala bir yolu var mı?
Jack Straw

1
@JackStraw 1) nesneden altsınıf ve tüm alıcıları ve ayarlayıcıları geçersiz kılın. 2) sınıf için kendi serileştiricinizi / seriyi kaldırıcıyı yazın ve kullanın ("özel serileştirici" yi arayın 3) nesneyi sarın ve yalnızca bir özellik için bir serileştirici / seri çözücü yazın (bu, için bir serileştirici yazmaktan daha az iş yapmanıza izin verebilir sınıfın kendisi, ama belki değil).
ErikE

Yorumunuzu + 1'leyin beni kurtardı! Şimdiye kadar bulduğum her çözüm, varsayılan
kurucuyu

34

Özel bir varsayılan kurucu kullanabilirsiniz, Jackson daha sonra alanları özel nihai olsalar bile yansıtma yoluyla dolduracaktır.

DÜZENLEME: Ve mirasınız varsa, üst sınıflar için korumalı / paket korumalı bir varsayılan kurucu kullanın.


Sadece bu cevaba dayanarak, serisini kaldırmak istediğiniz sınıf başka bir sınıfı genişletirse, süper sınıfın (veya her iki sınıfın) varsayılan kurucusunu korumalı yapabilirsiniz.
KWILLIAMS

4

Sergei Petunin'in ilk cevabı doğrudur. Bununla birlikte, yapıcının her parametresindeki fazlalık @JsonProperty ek açıklamalarını kaldırarak kodu basitleştirebiliriz.

Com.fasterxml.jackson.module.paramnames.ParameterNamesModule'ı ObjectMapper'a ekleyerek yapılabilir:

new ObjectMapper()
        .registerModule(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES))

(Btw: bu modül varsayılan olarak SpringBoot'ta kayıtlıdır. JacksonObjectMapperConfiguration'dan ObjectMapper bean kullanıyorsanız veya Bean Jackson2ObjectMapperBuilder ile kendi ObjectMapper'ınızı yaratırsanız modülün manuel kaydını atlayabilirsiniz)

Örneğin:

public class FieldValidationError {
  private final String field;
  private final String error;

  @JsonCreator
  public FieldValidationError(String field,
                              String error) {
    this.field = field;
    this.error = error;
  }

  public String getField() {
    return field;
  }

  public String getError() {
    return error;
  }
}

ve ObjectMapper bu json'ı herhangi bir hata olmadan seriyi kaldırır:

{
  "field": "email",
  "error": "some text"
}

Mükemmel Cevap, İyi çalışıyor
Ali
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.