Spring, Jackson и Customization (например, CustomDeserializer) - PullRequest
21 голосов
/ 28 августа 2010

Будучи немного незнакомым со Spring, я столкнулся с проблемой , которая делает необходимым реализацию моего специального десериализатора для Джексона.Процедура описана в небольшом учебном пособии , однако я застрял в Spring.Я не понимаю, где

 ObjectMapper mapper = new ObjectMapper();

в Spring MVC выполняется, когда json десериализуется методом класса контроллера.Поэтому я не знаю, что делать, чтобы заменить десериализатор по умолчанию на собственный десериализатор.

Любые предложения приветствуются.

Ответы [ 6 ]

19 голосов
/ 30 августа 2010

Вы не говорите, как используете Джексона в Spring, поэтому я предполагаю, что вы используете его через <mvc:annotation-driven/> и аннотации @RequestBody и / или @ResponseBody.

Одна из вещей, которую делает <mvc:annotation-driven/>, - это регистрация bean-компонента AnnotationMethodHandlerAdapter, который поставляется с несколькими предварительно сконфигурированными bean-компонентами HttpMessageConverter, включая MappingJacksonHttpMessageConverter, который обрабатывает маршаллинг для аннотируемых Джексоном классов моделей .

Теперь MappingJacksonHttpMessageConverter имеет метод setObjectMapper(), который позволяет переопределить значение по умолчанию ObjectMapper. Но поскольку MappingJacksonHttpMessageConverter создается за кулисами <mvc:annotation-driven/>, вы не можете добраться до него.

Однако, <mvc:annotation-driven/> - это просто удобное сокращение. Также можно объявить свой собственный компонент AnnotationMethodHandlerAdapter, добавить в него свой собственный компонент MappingJacksonHttpMessageConverter (через свойство messageConverters) и добавить в него свой собственный настроенный ObjectMapper.

Тогда возникает проблема, как создать пользовательский ObjectMapper, так как это не очень дружественный для Spring класс. Я предлагаю написать собственную простую реализацию FactoryBean.

Таким образом, вы получите что-то вроде этого:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
   <property name="messageConverters">
      <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
         <property name="objectMapper">
            <bean class="com.x.MyObjectMapperFactoryBean"/>
         </property>
      </bean>
   </property>
</bean>
7 голосов
/ 24 января 2013

Новый способ сделать это весной 3.1:
http://magicmonster.com/kb/prg/java/spring/webmvc/mvc_spring_config_namespace.html

http://blog.springsource.org/2011/02/21/spring-3-1-m1-mvc-namespace-enhancements-and-configuration/

Позволяет сделать что-то вроде этого:

<mvc:annotation-driven>
      <mvc:message-converters>
          <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
              <property name="objectMapper" ref="customObjectMapper"/>
          </bean>
      </mvc:message-converters>
  </mvc:annotation-driven>
5 голосов
/ 04 августа 2012

Решение, на которое ссылается Rakesh, вероятно, работает с Spring MVC 3.0, но с 3.1 часть инфраструктуры MVC изменилась .В результате у вас может не быть зарегистрированного компонента AnnotationMethodHandlerAdapter в контексте вашего приложения, и вы получите BeanCreationException во время инициализации.

Для Spring MVC 3.1 элемент mvc:annotation-driven создаст RequestMappingHandlerAdapter для вас, поэтому вы должны вместо этого автоматически подключить этот тип.Он по-прежнему будет предоставлять доступ к списку зарегистрированных HttpMessageConverters и позволит вам установить свойство ObjectMapper для MappingJacksonHttpMessageConverter.Это также требует небольшого изменения в пределах init.метод к типу ссылки HttpMessageConverters.

Обновленный класс выглядит следующим образом:

@Component
public class JacksonFix {
    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
    private CustomObjectMapper objectMapper;

    @PostConstruct
    public void init() {
        List<HttpMessageConverter<?>> messageConverters = requestMappingHandlerAdapter.getMessageConverters();
        for (HttpMessageConverter<?> messageConverter : messageConverters) {
            if (messageConverter instanceof MappingJacksonHttpMessageConverter) {
                MappingJacksonHttpMessageConverter m = (MappingJacksonHttpMessageConverter) messageConverter;
                m.setObjectMapper(objectMapper);
            }
        }
    }

    // this will exist due to the <mvc:annotation-driven/> bean
    @Autowired
    public void setRequestMappingHandlerAdapter(RequestMappingHandlerAdapter requestMappingHandlerAdapter) {
        this.requestMappingHandlerAdapter = requestMappingHandlerAdapter;
    }

    @Autowired
    public void setObjectMapper(CustomObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }
}

UPDATE : Оказывается, что с Spring 3.1 это абсолютно просто сделатьэто добавить некоторую дополнительную конфигурацию к вашей конфигурации MVC:

<mvc:annotation-driven conversion-service="applicationConversionService">
    <mvc:message-converters register-defaults="true">
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
            <property name="objectMapper" ref="customObjectMapper" />
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

Это добавит новый экземпляр MappingJacksonHttpMessageConverter с пользовательским ObjectMapper перед любым из HttpMessageConverters по умолчанию (которые все еще присутствуют из-за register-defaults="true").

2 голосов
/ 12 февраля 2014

В моем случае (Spring 3.2.4 и Jackson 2.3.1) конфигурация XML для настраиваемого сериализатора:

<mvc:annotation-driven>
    <mvc:message-converters register-defaults="false">
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                    <property name="serializers">
                        <array>
                            <bean class="com.example.business.serializer.json.CustomObjectSerializer"/>
                        </array>
                    </property>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

необъяснимым образом перезаписано обратно по умолчанию чем-то.

Это сработало для меня:

CustomObject.java

@JsonSerialize(using = CustomObjectSerializer.class)
public class CustomObject {

    private Long value;

    public Long getValue() {
        return value;
    }

    public void setValue(Long value) {
        this.value = value;
    }
}

CustomObjectSerializer.java

public class CustomObjectSerializer extends JsonSerializer<CustomObject> {

    @Override
    public void serialize(CustomObject value, JsonGenerator jgen,
        SerializerProvider provider) throws IOException,JsonProcessingException {
        jgen.writeStartObject();
        jgen.writeNumberField("y", value.getValue());
        jgen.writeEndObject();
    }

    @Override
    public Class<CustomObject> handledType() {
        return CustomObject.class;
    }
}

В моем решении не требуется настройка XML (<mvc:message-converters>(...)</mvc:message-converters>).

0 голосов
/ 23 октября 2011

Весенние документы для состояния MappingJacksonHttpMessageConverter:

2.4.5 MappingJacksonHttpMessageConverter

Реализация HttpMessageConverter, которая может читать и записывать JSON с помощью ObjectMapper процессора JSON Jackson.Отображение JSON может быть настроено по мере необходимости с помощью предоставленных Джексоном аннотаций.Когда требуется дальнейшее управление, пользовательский ObjectMapper может быть внедрен через свойство ObjectMapper для случаев, когда необходимо предоставить пользовательские сериализаторы / десериализаторы JSON для определенных типов.По умолчанию этот конвертер поддерживает (application / json).

Не могли бы вы просто автоматически подключить доступ к ObjectMapper для изменения его поведения?

0 голосов
/ 30 августа 2010

Хотелось бы, чтобы я знал Spring MVC лучше, но с такими реализациями Jax-RS, как Jersey и RESTeasy, регистрируются поставщики. Может быть, Spring делает что-то подобное?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...