2015-02-08 2 views
5

Я написал обычай JsonDeserializer который содержит autowired службы следующего образом:автоматического связывание в JsonDeserializer: SpringBeanAutowiringSupport против HandlerInstantiator

public class PersonDeserializer extends JsonDeserializer<Person> { 

    @Autowired 
    PersonService personService; 

    @Override 
    public Person deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { 

     // deserialization occurs here which makes use of personService 

     return person; 
    } 
} 

Когда я впервые использовал этот десериализатор я получал неработающие, как personService не будучи autowired , От взгляда на другие ответы SO (в частности, this one) оказалось, что есть два способа заставить autowiring работать.

Вариант 1 является использование SpringBeanAutowiringSupport в конструктор пользовательских десериализатор:

public PersonDeserializer() { 

    SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); 
} 

Вариант 2 является использование HandlerInstantiator и зарегистрировать его с моим ObjectMapper боба:

@Component 
public class SpringBeanHandlerInstantiator extends HandlerInstantiator { 

    @Autowired 
    private ApplicationContext applicationContext; 

    @Override 
    public JsonDeserializer<?> deserializerInstance(DeserializationConfig config, Annotated annotated, Class<? extends JsonDeserializer<?>> deserClass) { 

     try { 

      return (JsonDeserializer<?>) applicationContext.getBean(deserClass); 

     } catch (Exception e) { 

      // Return null and let the default behavior happen 
      return null; 
     } 
    } 
} 

@Configuration 
public class JacksonConfiguration { 

    @Autowired 
    SpringBeanHandlerInstantiator springBeanHandlerInstantiator; 

    @Bean 
    public ObjectMapper objectMapper() { 

     Jackson2ObjectMapperFactoryBean jackson2ObjectMapperFactoryBean = new Jackson2ObjectMapperFactoryBean(); 
     jackson2ObjectMapperFactoryBean.afterPropertiesSet(); 

     ObjectMapper objectMapper = jackson2ObjectMapperFactoryBean.getObject(); 

     // add the custom handler instantiator 
     objectMapper.setHandlerInstantiator(springBeanHandlerInstantiator); 

     return objectMapper; 
    } 
} 

Я попытался оба варианта, и они работают одинаково хорошо. Очевидно, что вариант 1 намного проще, так как это всего лишь три строки кода, но мой вопрос: есть ли недостатки в использовании SpringBeanAutowiringSupport по сравнению с подходом HandlerInstantiator? Мое приложение будет десериализовать сотни объектов в минуту, если это имеет значение.

Любые советы/отзывы приветствуются.

+0

ли вам удалось найти какие-либо недостатки в отношении SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext (это); ? –

ответ

0

Как было предложено в этом comment и нашел на этом link вам нужно создать пользовательский HandlerInstantiator:

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.context.ApplicationContext; 
import org.springframework.stereotype.Component; 

import com.fasterxml.jackson.databind.DeserializationConfig; 
import com.fasterxml.jackson.databind.JsonDeserializer; 
import com.fasterxml.jackson.databind.JsonSerializer; 
import com.fasterxml.jackson.databind.KeyDeserializer; 
import com.fasterxml.jackson.databind.SerializationConfig; 
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; 
import com.fasterxml.jackson.databind.cfg.MapperConfig; 
import com.fasterxml.jackson.databind.introspect.Annotated; 
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver; 
import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; 

@Component 
public class SpringBeanHandlerInstantiator extends HandlerInstantiator { 

    private ApplicationContext applicationContext; 

    @Autowired 
    public SpringBeanHandlerInstantiator(ApplicationContext applicationContext) { 
     this.applicationContext = applicationContext; 
    } 

    @Override 
    public JsonDeserializer<?> deserializerInstance(DeserializationConfig config, 
      Annotated annotated, 
      Class<?> deserClass) { 
     try { 
      return (JsonDeserializer<?>) applicationContext.getBean(deserClass); 
     } catch (Exception e) { 
      // Return null and let the default behavior happen 
     } 
     return null; 
    } 

    @Override 
    public KeyDeserializer keyDeserializerInstance(DeserializationConfig config, 
      Annotated annotated, 
      Class<?> keyDeserClass) { 
     try { 
      return (KeyDeserializer) applicationContext.getBean(keyDeserClass); 
     } catch (Exception e) { 
      // Return null and let the default behavior happen 
     } 
     return null; 
    } 

    @Override 
    public JsonSerializer<?> serializerInstance(SerializationConfig config, Annotated annotated, Class<?> serClass) { 
     try { 
      return (JsonSerializer<?>) applicationContext.getBean(serClass); 
     } catch (Exception e) { 
      // Return null and let the default behavior happen 
     } 
     return null; 
    } 

    @Override 
    public TypeResolverBuilder<?> typeResolverBuilderInstance(MapperConfig<?> config, Annotated annotated, 
      Class<?> builderClass) { 
     try { 
      return (TypeResolverBuilder<?>) applicationContext.getBean(builderClass); 
     } catch (Exception e) { 
      // Return null and let the default behavior happen 
     } 
     return null; 
    } 

    @Override 
    public TypeIdResolver typeIdResolverInstance(MapperConfig<?> config, Annotated annotated, Class<?> resolverClass) { 
     try { 
      return (TypeIdResolver) applicationContext.getBean(resolverClass); 
     } catch (Exception e) { 
      // Return null and let the default behavior happen 
     } 
     return null; 
    } 
} 

Пользовательские ObjectMapper:

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.context.ApplicationContext; 

import com.fasterxml.jackson.annotation.JsonInclude; 
import com.fasterxml.jackson.databind.DeserializationFeature; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import com.fasterxml.jackson.databind.SerializationFeature; 
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; 


public class CustomObjectMapper extends ObjectMapper { 
    private static final long serialVersionUID = -8865944893878900100L; 

    @Autowired 
    ApplicationContext applicationContext; 

    public JamaxObjectMapper() { 
     // Problems serializing Hibernate lazily initialized collections? Fix here. 
//  HibernateModule hm = new HibernateModule(); 
//  hm.configure(com.fasterxml.jackson.module.hibernate.HibernateModule.Feature.FORCE_LAZY_LOADING, true); 
//  this.registerModule(hm); 

     // Jackson confused by what to set or by extra properties? Fix it. 
     this.setSerializationInclusion(JsonInclude.Include.NON_NULL); 
     this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 
     this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); 
    } 

    @Override 
    @Autowired 
    public Object setHandlerInstantiator(HandlerInstantiator hi) { 
     return super.setHandlerInstantiator(hi); 
    } 
} 

и зарегистрировать свой собственный ObjectMapper:

<bean id="jacksonObjectMapper" class="com.acme.CustomObjectMapper" /> 
<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 
    <property name="prefixJson" value="false" /> 
    <property name="supportedMediaTypes" value="application/json" /> 
    <property name="objectMapper" ref="jacksonObjectMapper" /> 
</bean> 

На данный момент вы можете использовать:

@JsonDeserialize(contentUsing=PersonDeserializer.class) 
public void setPerson(Person person) { 
    ... 
} 

... и personService не будет null.

2

Добавляя к ответу Амира Джамака, вам не нужно создавать пользовательский HandlerInstantiator, поскольку Spring уже имеет это SpringHandlerInstantiator.

Что вам нужно сделать, это подключить его к Jackson2ObjectMapperBuilder в конфигурации Spring.

@Bean 
public HandlerInstantiator handlerInstantiator(ApplicationContext applicationContext) { 
    return new SpringHandlerInstantiator(applicationContext.getAutowireCapableBeanFactory()); 
} 

@Bean 
public Jackson2ObjectMapperBuilder objectMapperBuilder(HandlerInstantiator handlerInstantiator) { 
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); 
    builder.handlerInstantiator(handlerInstantiator); 
    return builder; 
} 
0

очистка в ответ выше с помощью загрузки пружины,

@Bean 
public HandlerInstantiator handlerInstantiator(ApplicationContext context) { 
    return new SpringHandlerInstantiator(context.getAutowireCapableBeanFactory()); 
} 

@Bean 
public ObjectMapper objectMapper(HandlerInstantiator handlerInstantiator) { 
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); 
    builder.handlerInstantiator(handlerInstantiator); 
    return builder.build(); 
} 
Смежные вопросы