2015-02-08 58 views
5

我寫了一個自定義的JsonDeserializer它包含一個自動裝配Autowired服務,具體如下:自動裝配在JsonDeserializer:SpringBeanAutowiringSupport VS 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; 
    } 
} 

當我第一次利用這個解串器我得到的NPE作爲personService沒有被自動裝配。從查看其他SO答案(特別是,this one)看來有兩種方法可以使自動裝配工作。

選項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更容易,因爲它只有三行代碼,但我的問題是:與HandlerInstantiator方法相比,使用SpringBeanAutowiringSupport有什麼缺點?如果這有什麼不同,我的應用程序將每分鐘反序列化數百個對象。

任何意見/反饋表示讚賞。

+0

你設法找到針對SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(本)的任何缺點; ? – 2016-02-03 10:38:30

回答

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不會爲空。

2

添加到Amir Jamak的回答中,您不必創建自定義HandlerInstantiator,因爲Spring已經擁有了SpringHandlerInstantiator。

你需要做的是在Spring配置中將它連接到Jackson2ObjectMapperBuilder。

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