2015-10-18 80 views
2

如何将ObjectIdResolver注册到Spring/Jackson对象映射器,以便ObjectIdResolver类被Spring实例化?我想在我的ObjectIdResolver类中使用依赖注入。JsonIdentityInfo解析器在Spring上下文中实例化

ObjectIdResolver.java

@Component 
public class UserIdResolver implements ObjectIdResolver { 

    @Autowired 
    UserConverter userConverter; 

    @Override 
    public void bindItem(ObjectIdGenerator.IdKey id, Object ob) { } 

    @Override 
    public Object resolveId(ObjectIdGenerator.IdKey id) { 
     return userConverter.convert((Integer)id.key); 
    } 

    @Override 
    public boolean canUseFor(ObjectIdResolver resolverType) { 
     return getClass().isAssignableFrom(resolverType.getClass()); 
    } 

    @Override 
    public ObjectIdResolver newForDeserialization(Object c) { 
     return this; 
    } 

} 

Order.java

public class Order { 

    @JsonIdentityInfo(
      generator = ObjectIdGenerators.PropertyGenerator.class, 
      property = "id", 
      resolver = UserIdResolver.class, 
      scope = User.class 
    ) 
    @JsonIdentityReference(alwaysAsId=true) 
    private User user; 

.. 

} 

弹簧servlet.xml中

<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" 
     p:indentOutput="true" p:simpleDateFormat="yyyy-MM-dd'T'HH:mm:ss.SSSZ" /> 

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" 
     p:targetObject-ref="objectMapper" p:targetMethod="registerModule"> 
    <property name="arguments"> 
     <list> 
      <bean class="com.fasterxml.jackson.datatype.joda.JodaModule" /> 
     </list> 
    </property> 
</bean> 

<mvc:annotation-driven conversion-service="conversionService"> 
    <mvc:message-converters> 
     <bean class="org.springframework.http.converter.StringHttpMessageConverter"/> 
     <bean class="org.springframework.http.converter.ResourceHttpMessageConverter" /> 
     <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 
      <property name="objectMapper" ref="objectMapper" /> 
     </bean> 
    </mvc:message-converters> 
</mvc:annotation-driven> 

回答

0

的Bec因为没有由spring构建和管理(jackson使用对构造函数的反射),所以没有直接的方法来实现这一点。我遇到类似的问题时,我想自动装配某些依赖于JPA EntityListener,发现绝招在: https://guylabs.ch/2014/02/22/autowiring-pring-beans-in-hibernate-jpa-entity-listeners/

/** 
* Helper class which is able to autowire a specified class. It holds a static reference to the {@link org 
* .springframework.context.ApplicationContext}. 
*/ 
public final class AutowireHelper implements ApplicationContextAware { 

    private static final AutowireHelper INSTANCE = new AutowireHelper(); 
    private static ApplicationContext applicationContext; 

    private AutowireHelper() { 
    } 

    /** 
    * Tries to autowire the specified instance of the class if one of the specified beans which need to be autowired 
    * are null. 
    * 
    * @param classToAutowire the instance of the class which holds @Autowire annotations 
    * @param beansToAutowireInClass the beans which have the @Autowire annotation in the specified {#classToAutowire} 
    */ 
    public static void autowire(Object classToAutowire, Object... beansToAutowireInClass) { 
     for (Object bean : beansToAutowireInClass) { 
      if (bean == null) { 
       applicationContext.getAutowireCapableBeanFactory().autowireBean(classToAutowire); 
       return; 
      } 
     } 
    } 

    @Override 
    public void setApplicationContext(final ApplicationContext applicationContext) { 
     AutowireHelper.applicationContext = applicationContext; 
    } 

    /** 
    * @return the singleton instance. 
    */ 
    public static AutowireHelper getInstance() { 
     return INSTANCE; 
    } 

} 

所以,你必须添加此AutowireHelper类,并改变你的方法:

@Override 
    public ObjectIdResolver newForDeserialization(Object c) { 
     AutowireHelper.autowire(this, userConverter); 
     return this; 
    } 
0

您可以尝试另一种更复杂的解决方案,但您可以完全控制反序列化。

步骤1:创建JpaEntityResolver

public class JpaEntityResolver extends SimpleObjectIdResolver { 

    private EntityManager em; 

    private Class<? extends EntityType> entityClass; 

    public JpaEntityResolver() { 

    } 

    public JpaEntityResolver(EntityManager em, Class<? extends EntityType> entityClass) { 
     this.em = em; 
     this.entityClass = entityClass; 
    } 

    @Override 
    public Object resolveId(IdKey id) { 
     Object resolved = super.resolveId(id); 
     if (resolved == null) { 
      resolved = findEntityById(id); 
      bindItem(id, resolved); 
     } 
     return resolved; 
    } 

    private Object findEntityById(IdKey idKey) { 
     Long id = (Long) idKey.key; 
     return em.find(entityClass, id); 
    } 

    @Override 
    public ObjectIdResolver newForDeserialization(Object context) { 
     return new JpaEntityResolver(this.em, this.entityClass); 
    } 
} 

第2步:创建自定义SpringHandlerInstantiator,帮助杰克逊动态地确定哪些

@Component 
public class TsqBeanHandlerInstantiator extends SpringHandlerInstantiator { 

    /** Logger. */ 
    protected static final Logger LOGGER = LoggerFactory.getLogger(TsqBeanHandlerInstantiator.class.getName()); 

    private final AutowireCapableBeanFactory beanFactory; 

    private final EntityManager em; 

    private List<Class<? extends EntityType>> tsqEntities = new ArrayList<>(); 

    /** 
    * Create a new SpringHandlerInstantiator for the given BeanFactory. 
    * @param beanFactory the target BeanFactory 
    */ 
    public TsqBeanHandlerInstantiator(AutowireCapableBeanFactory beanFactory, EntityManager em) { 
     super(beanFactory); 
     this.beanFactory = beanFactory; 
     this.em = em; 
    } 

    @PostConstruct 
    public void init() 
    { 
     //We record all available entity for futur use. 
     for (EntityType<?> entity : em.getMetamodel().getEntities()) { 
      Class<? extends EntityType> entityClass = (Class<? extends EntityType>) entity.getJavaType(); 
      String className = entityClass.getName(); 
      tsqEntities.add(entityClass); 
     }  
    } 

    @Override 
    public JsonDeserializer<?> deserializerInstance(DeserializationConfig config, Annotated annotated, Class<?> implClass) { 
     Class entityClass = annotated.getRawType(); 
     LOGGER.debug("deserializerInstance : " + entityClass); 
     return (JsonDeserializer<?>) this.beanFactory.createBean(implClass); 
    } 

    /** @since 4.3 */ 
    @Override 
    public ObjectIdGenerator<?> objectIdGeneratorInstance(MapperConfig<?> config, Annotated annotated, Class<?> implClass) { 
     Class entityClass = annotated.getRawType(); 
     LOGGER.debug("objectIdGeneratorInstance : " + entityClass); 
     return (ObjectIdGenerator<?>) this.beanFactory.createBean(implClass); 
    } 

    /** @since 4.3 */ 
    @Override 
    public ObjectIdResolver resolverIdGeneratorInstance(MapperConfig<?> config, Annotated annotated, Class<?> implClass) { 
     Class entityClass = annotated.getRawType(); 
     if(!tsqEntities.contains(entityClass)) 
     { 
      return super.resolverIdGeneratorInstance(config, annotated, implClass); 
     } 
     LOGGER.debug("resolverIdGeneratorInstance : " + entityClass); 
     return new JpaEntityResolver(em, entityClass); 
    } 
} 

第3步:注册您的处理程序到杰​​克逊的ObjectMapperHttpMessageConverter

@Configuration 
public class WebMvcConfig extends WebMvcConfigurerAdapter { 

    private @Autowired MappingJackson2HttpMessageConverter jacksonHttpMessageConverter; 

    private @Autowired TsqBeanHandlerInstantiator tsqBeanHandlerInstantiator; 

    @PostConstruct 
    public void init(){ 
     ObjectMapper objectMapper = jacksonHttpMessageConverter.getObjectMapper(); 
     objectMapper.setHandlerInstantiator(tsqBeanHandlerInstantiator); 
    } 
} 

第4步:享受使用它的控制器上

@RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) 
public ResponseEntity<Bean> create(HttpServletRequest request) throws IOException { 
    // getting the posted value 
    String body = CharStreams.toString(request.getReader()); 
    Bean bean = jacksonHttpMessageConverter.getObjectMapper().readValue(body, service.getBeanClass()); 
    Bean saved = service.save(bean); 

    URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(saved.getId()).toUri(); 
    return ResponseEntity.created(location).body(saved); 
} 
相关问题