Bet*_*eto 5 java json spring-mvc jackson
我需要在序列化时动态过滤 bean 属性。
这@JsonView对我来说不是一个选择。
假设我的 Bean(作为 Json 表示法):
{
id: '1',
name: 'test',
children: [
{ id: '1.1', childName: 'Name 1.1' },
{ id: '1.2', childName: 'Name 1.2' }
]
}
Run Code Online (Sandbox Code Playgroud)
我想编写具有以下属性的 JSON:
// configure the ObjectMapper to only serialize this properties:
[ "name", "children.childName" ]
Run Code Online (Sandbox Code Playgroud)
预期的 JSON 结果是:
{
name: 'test',
children: [
{ childName: 'Name 1.1' },
{ childName: 'Name 1.2' }
]
}
Run Code Online (Sandbox Code Playgroud)
最后,我将创建一个注释 ( @JsonFilterProperties) 以便在 RestController 中与 Spring 一起使用,如下所示:
@JsonFilterProperties({"name", "children.childName"}) // display only this fields
@RequestMapping("/rest/entity")
@ResponseBody
public List<Entity> findAll() {
return serviceEntity.findAll(); // this will return all fields populated!
}
Run Code Online (Sandbox Code Playgroud)
嗯,这很棘手但可行。您可以使用 JacksonsFilter功能 ( http://wiki.fasterxml.com/JacksonFeatureJsonFilter ) 并进行一些小的更改来完成此操作。首先,我们将使用类名作为过滤器 ID,这样您就不必添加@JsonFIlter到您使用的每个实体中:
public class CustomIntrospector extends JacksonAnnotationIntrospector {
@Override
public Object findFilterId(AnnotatedClass ac) {
return ac.getRawType();
}
}
Run Code Online (Sandbox Code Playgroud)
下一步,使超类的过滤器适用于其所有子类:
public class CustomFilterProvider extends SimpleFilterProvider {
@Override
public BeanPropertyFilter findFilter(Object filterId) {
Class id = (Class) filterId;
BeanPropertyFilter f = null;
while (id != Object.class && f == null) {
f = _filtersById.get(id.getName());
id = id.getSuperclass();
}
// Part from superclass
if (f == null) {
f = _defaultFilter;
if (f == null && _cfgFailOnUnknownId) {
throw new IllegalArgumentException("No filter configured with id '" + filterId + "' (type " + filterId.getClass().getName() + ")");
}
}
return f;
}
}
Run Code Online (Sandbox Code Playgroud)
其自定义版本ObjectMapper利用我们的自定义类:
public class JsonObjectMapper extends ObjectMapper {
CustomFilterProvider filters;
public JsonObjectMapper() {
filters = new CustomFilterProvider();
filters.setFailOnUnknownId(false);
this.setFilters(this.filters);
this.setAnnotationIntrospector(new CustomIntrospector());
}
/* You can change methods below as you see fit. */
public JsonObjectMapper addFilterAllExceptFilter(Class clazz, String... property) {
filters.addFilter(clazz.getName(), SimpleBeanPropertyFilter.filterOutAllExcept(property));
return this;
}
public JsonObjectMapper addSerializeAllExceptFilter(Class clazz, String... property) {
filters.addFilter(clazz.getName(), SimpleBeanPropertyFilter.serializeAllExcept(property));
return this;
}
}
Run Code Online (Sandbox Code Playgroud)
现在看一下MappingJackson2HttpMessageConverter,您将看到它使用ObjectMapper内部的一个实例,因此如果您想要同时使用不同的配置(针对不同的请求),则无法使用它。您需要使用它的请求范围ObjectMapper和适当的消息转换器:
public abstract class DynamicMappingJacksonHttpMessageConverter extends MappingJackson2HttpMessageConverter {
// Spring will override this method with one that provides request scoped bean
@Override
public abstract ObjectMapper getObjectMapper();
@Override
public void setObjectMapper(ObjectMapper objectMapper) {
// We dont need that anymore
}
/* Additionally, you need to override all methods that use objectMapper attribute and change them to use getObjectMapper() method instead */
}
Run Code Online (Sandbox Code Playgroud)
添加一些bean定义:
<bean id="jsonObjectMapper" class="your.package.name.JsonObjectMapper" scope="request">
<aop:scoped-proxy/>
</bean>
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="your.package.name.DynamicMappingJacksonHttpMessageConverter">
<lookup-method name="getObjectMapper" bean="jsonObjectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
Run Code Online (Sandbox Code Playgroud)
最后一部分是实现一些可以检测您的注释并执行实际配置的东西。为此,您可以创建一个@Aspect. 就像是:
@Aspect
public class JsonResponseConfigurationAspect {
@Autowired
private JsonObjectMapper objectMapper;
@Around("@annotation(jsonFilterProperties)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
/* Here you will have to determine return type and annotation value from jointPoint object. */
/* See http://stackoverflow.com/questions/2559255/spring-aop-how-to-get-the-annotations-of-the-adviced-method for more info */
/* If you want to use things like 'children.childName' you will have to use reflection to determine 'children' type, and so on. */
}
Run Code Online (Sandbox Code Playgroud)
}
就我个人而言,我以不同的方式使用它。我不使用注释,只是手动进行配置:
@Autowired
private JsonObjectMapper objectMapper;
@RequestMapping("/rest/entity")
@ResponseBody
public List<Entity> findAll() {
objectMapper.addFilterAllExceptFilter(Entity.class, "name", "children");
objectMapper.addFilterAllExceptFilter(EntityChildren.class, "childName");
return serviceEntity.findAll();
}
Run Code Online (Sandbox Code Playgroud)
PS 这种方法有一个主要缺陷:您不能为一个类添加两个不同的过滤器。
| 归档时间: |
|
| 查看次数: |
7433 次 |
| 最近记录: |