2012-02-21 9 views
11

Czy można selektywnie określić, kiedy adnotacja @JsonFilter zostanie użyta w czasie wykonywania?@JsonFilter rzuca "JsonMappingException: nie można rozwiązać BeanPropertyFilter"

Otrzymuję wyjątek JsonMappingException (patrz poniżej), gdy nie zapewniam filtru.

Tło:

dowiedziałem od recent StackOverflow post że mogę wykorzystać @JsonFilter dynamiczne filtrowanie właściwości fasoli coraz odcinkach. Działa to świetnie. Po dodaniu @JsonFilter("apiFilter") do mojej klasy domeny i po dodaniu tego kodu w mojej służbie JAX-RS (używając realizację CXF), jestem w stanie dynamicznie filtrować właściwości zwróconych przez moją relaksującego API:

// shortened for brevity 
FilterProvider filters = new SimpleFilterProvider().addFilter("apiFilter", SimpleBeanPropertyFilter.filterOutAllExcept(filterProperties)); 

return mapper.filteredWriter(filters).writeValueAsString(user); 

Problem czy są różne połączenia serwisowe, w których nie chcę w ogóle stosować filtra. W takich przypadkach chcę zwrócić całą klasę domeny bez filtrowania żadnych właściwości. W przypadku, gdy po prostu spróbować, aby powrócić do klasy domeny Dostaję wyjątek w następujący sposób:

Caused by: org.codehaus.jackson.map.JsonMappingException: Can not resolve BeanPropertyFilter with id 'apiFilter'; no FilterProvider configured 

at org.codehaus.jackson.map.ser.BeanSerializer.findFilter(BeanSerializer.java:252) 
at org.codehaus.jackson.map.ser.BeanSerializer.serializeFieldsFiltered(BeanSerializer.java:216) 
at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:140) 

Odpowiedz

6

Myślę, że można oszukać przefiltrowaną pisarza definiowania pusty filtr serialize dla przypadków, w których chcesz wszystkie właściwości seralized:

FilterProvider filters = new SimpleFilterProvider().addFilter("apiFilter", SimpleBeanPropertyFilter.serializeAllExcept(emptySet)); 

w ten sposób, gdy silnik wygląda na „apiFilter” filtr zdefiniowany w @JsonFilter adnotację, że znajdzie to, ale to nie będzie miało żadnego wpływu (jak serializacji wszystkie właściwości).

EDIT Ponadto, można wywołać metodę fabryczną writer() zamiast filteredWriter():

ObjectWriter writer=null; 
if(aplyFilter) { 
    FilterProvider filters = new SimpleFilterProvider().addFilter("apiFilter", SimpleBeanPropertyFilter.filterOutAllExcept(filterProperties)); 
    writer=mapper.filteredWriter(filters); 
} else { 
    writer=mapper.writer(); 
} 

return writer.writeValueAsString(user); 

myślę, że to ostatnie rozwiązanie jest o wiele czystsze, a nawet lepiej.

+0

w twoim edytowanym przykładzie, czy powinienem dołączyć kod, aby sprawdzić, która metoda wywołująca zapisywana jest w każdym wywołaniu usługi jax-rs? w niektórych metodach obsługi zwracam rzeczywisty obiekt użytkownika, a nie ciąg. wielkie dzięki za twój wkład! – Justin

+1

OK, miałem okazję spróbować. "sztuczka", którą zasugerowałeś, działa, ale nie mogłem wykonać drugiej "czystej" sugestii do działania. w takim przypadku nadal otrzymuję błąd "brak FilterProvider skonfigurowany". dzięki jeszcze raz. – Justin

+0

@Justin: Cóż, IMO "nieczystym" rozwiązaniem, które rozwiązuje problem jest lepszy niż "czysty", który nie działa :). Mam nadzieję, że pomogło to rozwiązać twój problem. –

18

Wiem, że to już odpowiedzi, ale za newcommers Jackson faktycznie dodano możliwość nie powiedzie się na brakujących filtrów (JACKSON-650):
wystarczy zadzwonić SimpleFilterProvider.setFailOnUnknownId(false) i nie dostaniesz tego wyjątku.

+0

dzięki za odpowiedź. jest to pomocne – Justin

+4

Oczywiście nadal musisz skonfigurować SimpleFilterProvider, nawet jeśli nie zamierzasz używać filtrowania w ogóle z programem odwzorowującym, którego używasz. No cóż. – Jules

0

Miałem podobny problem z uzyskaniem tego samego wyjątku, ale zaakceptowana odpowiedź tak naprawdę nie pomogła w moim przypadku. Oto rozwiązanie, że pracował dla mnie:

W mojej konfiguracji używałem niestandardowej JacksonSerializer tak:

@JsonSerialize(using = MyCustomSerializer.class) 
private Object someAttribute; 

I serializer został wdrożony tak:

public class MyCustomSerializer extends JsonSerializer<Object> { 
    @Override 
    public void serialize(Object o, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { 
    if (o != null) { 
     jgen.writeObject(o); 
    } 
    } 
} 

Problem z tym jest tak, że dopóki nie używasz żadnych filtrów, działa. Działa również, jeśli serializuje się prymitywy, więc na przykład, jeśli używasz jgen.writeString(..). Jeśli używasz filtrów, ten kod jest nieprawidłowy, ponieważ filtry są przechowywane gdzieś wewnątrz SerializerProvider, a nie w JsonGenerator. Jeśli w tym przypadku użyjesz jsongenerator bezpośrednio, nowy SerializerProvider, który nie wie o filtrach, jest tworzony wewnętrznie. Więc zamiast krótszego jgen.writeObject(o) musisz zadzwonić pod numer provider.defaultSerializeValue(o, jgen).Dzięki temu filtry nie zostaną zgubione i można je zastosować.