Jak powiedzieć Jacksonowi, aby ignorował właściwość, nad którą nie mam kontroli nad kodem źródłowym?


112

Krótko mówiąc, jeden z moich obiektów ma GeometryCollection, który zgłasza wyjątek, gdy wywołujesz „getBoundary” (powodem tego jest kolejna książka, na razie powiedzmy, że tak to działa).

Czy jest sposób, w jaki mogę powiedzieć Jacksonowi, aby nie uwzględniał tego konkretnego pobieracza? Wiem, że mogę używać @JacksonIgnore, gdy posiadam / kontroluję kod. Ale tak nie jest, jackson kończy się osiągając ten punkt poprzez ciągłą serializację obiektów nadrzędnych. Widziałem opcję filtrowania w dokumentacji Jacksona. Czy to wiarygodne rozwiązanie?

Dzięki!

Odpowiedzi:


168

Możesz użyć Jackson Mixins . Na przykład:

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

Dzięki temu Mixin

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

Z tym:

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

Edytować:

Dzięki komentarzom w Jackson 2.5+ API się zmieniło i powinno być wywoływane z objectMapper.addMixIn(Class<?> target, Class<?> mixinSource)


1
A jeśli właściwość jest generowana maszynowo i ma w nazwie nieobsługiwane znaki? Lubić '@'? JVM na to pozwala, ale kompilator Java nie. Czy Jackson ma na to rozwiązanie?
znak

3
A w Jackson 2.2 jestobjectMapper.addMixInAnnotations(Class<?> target, Class<?> mixinSource);
CorayThan

Jak zignorować, podając nazwę właściwości zamiast metody pobierającej?
Erran Morad

68

Inną możliwością jest to, że jeśli chcesz zignorować wszystkie nieznane właściwości, możesz skonfigurować program odwzorowujący w następujący sposób:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

5
Byłoby wspaniale, gdybyśmy mogli skonfigurować objectMapper tak, aby ignorował tylko określone właściwości. tj. zgłoś wyjątek dla wszystkich nowych / nieznanych pól, z wyjątkiem powiedzmy „myfield”. Coś jakmapper.configure(DeserializationFeature.failOnUnknownPropertiesExcep(new String[] {"myField"}));
ms_27

Zauważ, że można to również skonfigurować na czytniku za pomocą without():mapper.reader().without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
Drew Stephens

Zdecydowanie odradzam korzystanie z tego mechanizmu. „Ścisłe” nastawienie Jacksona, powodujące zgłaszanie błędów w nieznanych / nieobsługiwanych polach, jest jedną z jego mocnych stron i dobrze pasuje do statycznego typowania / analizowania czasu kompilacji języka Java. Znacznie lepiej jest zamiast tego zrezygnować z obsługi danego zestawu ignorowanych pól.
Per Lundberg

26

Korzystanie z klasy Java

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

Korzystanie z adnotacji

@JsonIgnoreProperties(ignoreUnknown=true)

11

Podejście oparte na adnotacjach jest lepsze. Ale czasami potrzebna jest obsługa ręczna. W tym celu możesz użyć bez metody ObjectWriter .

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
To podejście nie działa dla mnie, ale mixin tak. Po serializacji nadal otrzymuję ignorowane właściwości. Dlaczego mamy mixiny, skoro bez atrybutu ()?
Erran Morad

9

Dodane adnotacje działają tutaj całkiem dobrze, jak już wspomniano. Inną możliwością wykraczającą poza właściwość @JsonIgnore jest użycie @JsonIgnoreType, jeśli masz typ, który nigdy nie powinien być uwzględniany (tj. Jeśli wszystkie wystąpienia właściwości GeometryCollection powinny być ignorowane). Możesz wtedy dodać go bezpośrednio (jeśli kontrolujesz typ) lub użyć miksu, na przykład:

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

Może to być wygodniejsze, jeśli masz wiele klas, z których wszystkie mają jeden akcesor „IgnoredType getContext ()” lub coś podobnego (co ma miejsce w przypadku wielu frameworków)


5

Miałem podobny problem, ale był on związany z dwukierunkowymi relacjami Hibernate. Chciałem pokazać jedną stronę relacji, a programowo zignorować drugą, w zależności od tego, z jakim poglądem mam do czynienia. Jeśli nie możesz tego zrobić, skończysz z paskudnym StackOverflowExceptions. Na przykład, gdybym miał te obiekty

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

public class B{
  Long id;
  A parent;
}

Chciałbym programowo zignorować parentpole w B, gdybym patrzył na A, i zignorować childrenpole w A, gdybym patrzył na B.

Zacząłem używać do tego mixinów, ale to bardzo szybko staje się okropne; masz tak wiele bezużytecznych klas, które istnieją wyłącznie po to, by formatować dane. Skończyło się na napisaniu własnego serializatora, aby poradzić sobie z tym w bardziej przejrzysty sposób: https://github.com/monitorjbl/json-view .

Pozwala programowo określić, które pola mają być ignorowane:

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

Umożliwia także łatwe określanie bardzo uproszczonych widoków za pomocą dopasowywania symboli wieloznacznych:

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

W moim pierwotnym przypadku potrzeba prostych poglądów, takich jak ten, polegała na pokazaniu absolutnego minimum na temat rodzica / dziecka, ale stało się również przydatne dla naszego bezpieczeństwa opartego na rolach. Mniej uprzywilejowane widoki obiektów wymagały zwrócenia mniejszej ilości informacji o obiekcie.

Wszystko to pochodzi z serializatora, ale w mojej aplikacji używałem Spring MVC. Aby poprawnie obsłużyć te przypadki, napisałem integrację, którą możesz dodać do istniejących klas kontrolerów Spring:

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

Oba są dostępne w Maven Central. Mam nadzieję, że pomoże to komuś innemu, jest to szczególnie brzydki problem z Jacksonem, który nie miał dobrego rozwiązania dla mojej sprawy.


Po co jest import Match.match()?
Pasupathi Rajamanickam

2

Jeśli chcesz ZAWSZE wykluczyć niektóre właściwości dla dowolnej klasy, możesz użyć setMixInResolvermetody:

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.