在 Jackson VirtualBeanPropertyWriter 中注入 Spring Bean
Posted
技术标签:
【中文标题】在 Jackson VirtualBeanPropertyWriter 中注入 Spring Bean【英文标题】:Inject Spring Bean in Jackson VirtualBeanPropertyWriter 【发布时间】:2018-12-26 07:51:06 【问题描述】:tldr; 我想在使用 Jackson @JsonAppend
将 JPA 实体序列化为 JSON 时添加虚拟字段。虚拟字段的值必须通过 Spring 管理的服务来确定。如何在 Jackson 类中注入我的 Spring 管理服务?
技术:Spring Boot 1.5.10、Spring Data Rest、JPA 2.1、Jackson 2.8.10
详情:
我有一个 Spring Data 托管的 JPA 实体:
@Entity
public class Stream
...
我使用 Mixin 创建了一个自定义 Jackson 模块,以添加 @JsonAppend
虚拟字段,如下所示:
@Bean
public Module customModule()
return new CustomModule();
@Component
class CustomModule extends SimpleModule
CustomModule()
setMixInAnnotation(Stream.class, StreamMixin.class);
@JsonAppend(
props =
@JsonAppend.Prop(name = "canEdit", value = ABACInspector.class)
)
abstract class StreamMixin
ABACInspector
类扩展了 Jackson 的 VirtualBeanPropertyWriter
以确定虚拟字段 canEdit
的值。如果此类不使用 Spring 服务(例如设置硬编码值),它可以正常工作,并且该字段显示在 REST API JSON 响应中。但是自动装配 Spring bean 不起作用,对象仍然是 null
。
@Component
class ABACInspector extends VirtualBeanPropertyWriter
@Autowired
private PermissionEvaluator permissionEvaluator;
public ABACInspector()
public ABACInspector(BeanPropertyDefinition propDef, Annotations contextAnnotations, JavaType declaredType)
super(propDef, contextAnnotations, declaredType);
@Override
protected Object value(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
boolean permission = permissionEvaluator.hasPermission(authentication, bean, Action.STREAM_VIEW);
System.out.println("evaluated permission is " + permission);
return permission;
@Override
public VirtualBeanPropertyWriter withConfig(MapperConfig<?> config, AnnotatedClass declaringClass, BeanPropertyDefinition propDef, JavaType type)
return new ABACInspector(propDef, null, type);
下面是 NPE 错误(因为permissionEvaluator
从未注入):
"status":"INTERNAL_SERVER_ERROR","message":"Could not write JSON:
(was java.lang.NullPointerException); nested exception is com.fasterxml.jackson.databind.JsonMappingException:
(was java.lang.NullPointerException) (through reference chain: org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$PersistentEntityResourceSerializer$1[\"content\"]->com.example.streammanagement.Stream[\"canView\"])"
我知道 Spring Data Rest 的 HalHandlerInstantiator
包含 AutowireCapableBeanFactory
,但我不确定这如何/是否可以提供帮助。参考DATAREST-840
【问题讨论】:
【参考方案1】:Jackson 在内部调用组件的 withConfig
函数来构建 VirtualBeanPropertyWriter
。
因此,如果您使用断点,您可以看到首先创建了一个带有注入 bean 的组件,然后调用 withConfig 函数并创建了新的 VirtualBeanPropertyWriter 对象,该对象由 jackson 使用,当然没有注入的 bin(因为您调用了构造函数手动)。
所以你可以这样改:
@Component
class ABACInspector extends VirtualBeanPropertyWriter
private PermissionEvaluator permissionEvaluator;
@Autowired
public ABACInspector(PermissionEvaluator permissionEvaluator)
this.permissionEvaluator = permissionEvaluator;
public ABACInspector(BeanPropertyDefinition propDef, Annotations contextAnnotations, JavaType declaredType, PermissionEvaluator permissionEvaluator)
super(propDef, contextAnnotations, declaredType);
this.permissionEvaluator = permissionEvaluator;
@Override
protected Object value(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
boolean permission = permissionEvaluator.hasPermission(authentication, bean, Action.STREAM_VIEW);
System.out.println("evaluated permission is " + permission);
return permission;
@Override
public VirtualBeanPropertyWriter withConfig(MapperConfig<?> config, AnnotatedClass declaringClass, BeanPropertyDefinition propDef, JavaType type)
return new ABACInspector(propDef, null, type, permissionEvaluator);
【讨论】:
你的ABACInspector
初始化不是因为没有这样的构造函数而无效吗?构造函数注入也不起作用,因为还有另一个没有任何 PermissionEvaluator
参数的构造函数。
@xsreality 感谢您的评论。我修好了。以上是关于在 Jackson VirtualBeanPropertyWriter 中注入 Spring Bean的主要内容,如果未能解决你的问题,请参考以下文章
Maven 构建错误 org.codehaus.jackson:jackson-core-asl:jar:[1.8,1.9) 在指定范围内没有可用的版本