Jackson'a kaynak kodu üzerinde kontrolüm olmayan bir özelliği göz ardı etmesini nasıl söyleyebilirim?


112

Uzun lafın kısası, varlıklarımdan birinde "getBoundary" dediğinizde bir istisna atan bir GeometryCollection var (bunun nedeni başka bir kitap, şimdilik böyle çalıştığını varsayalım).

Jackson'a o belirli alıcıyı dahil etmemesini söylememin bir yolu var mı? Kodun sahibi / kontrolünü yaptığımda @ JacksonIgnore kullanabileceğimi biliyorum. Ancak durum bu değil, jackson bu noktaya ana nesnelerin sürekli serileştirilmesi yoluyla ulaşmayı bitiriyor. Jackson belgelerinde bir filtreleme seçeneği gördüm. Bu makul bir çözüm mü?

Teşekkürler!

Yanıtlar:


168

Jackson Mixins'i kullanabilirsiniz . Örneğin:

class YourClass {
  public int ignoreThis() { return 0; }    
}

Bu Mixin ile

abstract class MixIn {
  @JsonIgnore abstract int ignoreThis(); // we don't need it!  
}

Bununla:

objectMapper.getSerializationConfig().addMixInAnnotations(YourClass.class, MixIn.class);

Düzenle:

Yorumlar sayesinde, Jackson 2.5+ ile API değişti ve objectMapper.addMixIn(Class<?> target, Class<?> mixinSource)


1
Ve özellik makine oluşturulmuşsa ve adında desteklenmeyen karakterler varsa? Sevmek '@'? JVM buna izin verir, ancak Java derleyicisi izin vermez. Jackson'ın bunun için bir çözümü var mı?
mark

3
Ve jackson 2.2'de buobjectMapper.addMixInAnnotations(Class<?> target, Class<?> mixinSource);
CorayThan

Alıcı yerine özellik adını belirterek nasıl yoksayabilirim?
Erran Morad

68

Diğer bir olasılık da, tüm bilinmeyen özellikleri yok saymak istiyorsanız, eşleyiciyi aşağıdaki gibi yapılandırabilirsiniz:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

5
ObjectMapper'ı yalnızca belirli özellikleri yoksayacak şekilde yapılandırabilirsek harika olurdu. yani, 'alanım' diyelim hariç tüm yeni / bilinmeyen alanlar için istisnayı bildirin. Gibi bir şeymapper.configure(DeserializationFeature.failOnUnknownPropertiesExcep(new String[] {"myField"}));
ms_27

Bunun aşağıdaki without()gibi kullanılarak bir okuyucu üzerinde yapılandırılabileceğini unutmayın :mapper.reader().without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
Drew Stephens

Bu mekanizmayı kullanmamanızı şiddetle tavsiye ederim. Jackson'da bilinmeyen / işlenmemiş alanlarda hataların ortaya çıkmasına neden olan "katı" zihniyet, güçlü yönlerinden biridir ve Java'nın statik olarak yazılan / derleme zamanı analiz edilen doğasıyla iyi bir şekilde eşleşir. Bunun yerine, belirli bir göz ardı edilen alan kümesini işlemekten vazgeçmek çok daha iyidir.
Lundberg'e göre

26

Java Sınıfını Kullanma

new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

Ek Açıklamayı Kullanma

@JsonIgnoreProperties(ignoreUnknown=true)

11

Ek açıklamaya dayalı yaklaşım daha iyidir. Ancak bazen manuel işlem gereklidir. Bu amaçla ObjectWriter yöntemi olmadan kullanabilirsiniz .

ObjectMapper mapper   = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
ObjectWriter writer   = mapper.writer().withoutAttribute("property1").withoutAttribute("property2");
String       jsonText = writer.writeValueAsString(sourceObject);

9
Bu yaklaşım benim için işe yaramıyor, ancak karışım işe yarıyor. Serileştirmeden sonra hala göz ardı edilen özellikleri alıyorum. Sahip olduğumuzAttribute () yokken neden karışımlarımız var?
Erran Morad

9

Karışık ek açıklamalar daha önce de belirtildiği gibi burada oldukça iyi çalışıyor. Özellik başına @JsonIgnore'un ötesinde başka bir olasılık, asla dahil edilmemesi gereken bir türünüz varsa (yani, tüm GeometryCollection özelliklerinin göz ardı edilmesi gerekiyorsa) @JsonIgnoreType'ı kullanmaktır. Daha sonra doğrudan ekleyebilirsiniz (türü kontrol ediyorsanız) veya mix-in kullanarak, örneğin:

@JsonIgnoreType abstract class MixIn { }
// and then register mix-in, either via SerializationConfig, or by using SimpleModule

Tümünün tek bir 'IgnoredType getContext ()' erişimcisine sahip olduğu çok sayıda sınıfınız varsa bu daha kullanışlı olabilir (birçok çerçeve için durum budur)


5

Benzer bir sorunum vardı ama bu Hibernate'in çift yönlü ilişkileriyle ilgiliydi. Hangi görüşle uğraştığıma bağlı olarak ilişkinin bir tarafını göstermek ve diğer tarafını programlı olarak görmezden gelmek istedim. Eğer bunu yapamazsan, kötü StackOverflowExceptione- postalarla sonuçlanırsın . Örneğin, bu nesnelere sahip olsaydım

public class A{
  Long id;
  String name;
  List<B> children;
}

public class B{
  Long id;
  A parent;
}

parentA'ya bakıyorsam B'deki alanı programlı olarak yok saymak, B'ye bakıyorsam A'daki childrenalanı görmezden gelmek isterdim.

Bunu yapmak için mixins kullanmaya başladım, ama bu çok çabuk korkunç hale geliyor; sadece verileri biçimlendirmek için var olan birçok işe yaramaz sınıfınız var. Bunu daha temiz bir şekilde ele almak için kendi serileştiricimi yazdım: https://github.com/monitorjbl/json-view .

Hangi alanların yok sayılacağını programlı olarak belirlemenize olanak tanır:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(JsonView.class, new JsonViewSerializer());
mapper.registerModule(module);

List<A> list = getListOfA();
String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(B.class, match()
        .exclude("parent")));

Ayrıca, joker eşleştiriciler aracılığıyla çok basitleştirilmiş görünümleri kolayca belirlemenize olanak tanır:

String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(A.class, match()
        .exclude("*")
         .include("id", "name")));

Benim orijinal durumumda, bunun gibi basit görüşlere duyulan ihtiyaç, ebeveyn / çocuk hakkında en az şeyi göstermekti, ama aynı zamanda rol tabanlı güvenliğimiz için de faydalı oldu. Nesne hakkında daha az bilgi döndürmek için nesnelerin daha az ayrıcalıklı görünümleri gerekir.

Bunların hepsi serileştiriciden geliyor, ancak uygulamamda Spring MVC kullanıyordum. Bu durumları düzgün bir şekilde ele almasını sağlamak için, mevcut Spring denetleyici sınıflarına bırakabileceğiniz bir entegrasyon yazdım:

@Controller
public class JsonController {
  private JsonResult json = JsonResult.instance();
  @Autowired
  private TestObjectService service;

  @RequestMapping(method = RequestMethod.GET, value = "/bean")
  @ResponseBody
  public List<TestObject> getTestObject() {
    List<TestObject> list = service.list();

    return json.use(JsonView.with(list)
        .onClass(TestObject.class, Match.match()
            .exclude("int1")
            .include("ignoredDirect")))
        .returnValue();
  }
}

Her ikisi de Maven Central'da mevcuttur. Umarım dışarıdaki birine yardımcı olur, bu, Jackson için özellikle çirkin bir problemdir ve davam için iyi bir çözümü yoktur.


İthalat ne içindir Match.match()?
Pasupathi Rajamanickam

2

Herhangi bir sınıf için HER ZAMAN belirli özellikleri dışlamak istiyorsanız, setMixInResolveryöntemi kullanabilirsiniz :

    @JsonIgnoreProperties({"id", "index", "version"})
    abstract class MixIn {
    }

    mapper.setMixInResolver(new ClassIntrospector.MixInResolver(){
        @Override
        public Class<?> findMixInClassFor(Class<?> cls) {
            return MixIn.class;  
        }

        @Override
        public ClassIntrospector.MixInResolver copy() {
            return this;
        }
    });

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.