Джаксън - JsonMappingException (Не е намерен сериализатор за клас)

1. Общ преглед

В този бърз урок ще анализираме марширането на обекти без гетери и решението за изключението Jackson JsonMappingException .

Ако искате да копаете по-дълбоко и да научите други страхотни неща, които можете да правите с Jackson 2 - преминете към основния урок за Jackson.

2. Проблемът

По подразбиране Jackson 2 ще работи само с полета, които са или публични, или имат публични методи за получаване - сериализирането на обект, който има всички полета private или package private, ще се провали :

public class MyDtoNoAccessors { String stringValue; int intValue; boolean booleanValue; public MyDtoNoAccessors() { super(); } // no getters }
@Test(expected = JsonMappingException.class) public void givenObjectHasNoAccessors_whenSerializing_thenException() throws JsonParseException, IOException { String dtoAsString = new ObjectMapper().writeValueAsString(new MyDtoNoAccessors()); assertThat(dtoAsString, notNullValue()); }

Най- пълен изключение е:

com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class dtos.MyDtoNoAccessors and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) )

3. Решението

Очевидното решение е да добавите гетери за полетата - ако обектът е под наш контрол. Ако случаят не е такъв и промяната на източника на обекта не е възможна - тогава Джаксън ни предоставя няколко алтернативи.

3.1. Глобално автоматично откриване на полета с всякаква видимост

Първото решение на този проблем е глобално конфигуриране на ObjectMapper да открива всички полета, независимо от тяхната видимост:

objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

Това ще позволи частните полета и частните полета да бъдат открити без гетери и сериализацията ще работи правилно:

@Test public void givenObjectHasNoAccessors_whenSerializingWithAllFieldsDetected_thenNoException() throws JsonParseException, IOException { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY); String dtoAsString = objectMapper.writeValueAsString(new MyDtoNoAccessors()); assertThat(dtoAsString, containsString("intValue")); assertThat(dtoAsString, containsString("stringValue")); assertThat(dtoAsString, containsString("booleanValue")); }

3.2. Открити са всички полета на ниво клас

Друга опция, която Jackson 2 предоставя, е - вместо глобалната конфигурация - да контролира видимостта на полето на ниво клас чрез анотацията @JsonAutoDetect :

@JsonAutoDetect(fieldVisibility = Visibility.ANY) public class MyDtoNoAccessors { ... }

С тази анотация сериализацията вече трябва да работи правилно с този конкретен клас:

@Test public void givenObjectHasNoAccessorsButHasVisibleFields_whenSerializing_thenNoException() throws JsonParseException, IOException { ObjectMapper objectMapper = new ObjectMapper(); String dtoAsString = objectMapper.writeValueAsString(new MyDtoNoAccessors()); assertThat(dtoAsString, containsString("intValue")); assertThat(dtoAsString, containsString("stringValue")); assertThat(dtoAsString, containsString("booleanValue")); }

4. Заключение

Тази статия илюстрира как да заобиколите видимостта на полето по подразбиране в Джаксън , като конфигурирате персонализирана видимост или глобално в ObjectMapper или в отделни класове. Джаксън позволява още по-нататъшно персонализиране, като предоставя опции за контрол на това как точно гетерите, сетерите или полетата със специфична видимост се виждат от картографа.

Внедряването на всички тези примери и кодови фрагменти може да се намери в моя проект GitHub - това е проект, базиран на Eclipse, така че трябва да е лесно да се импортира и да се изпълнява както е.