加入依赖包:
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
</dependency>
动态过滤属性
问题描述
ISSUE:双向关联对象转JSON问题 双向关联后使用org.codehaus.jackson.map.ObjectMapper转json时报错(由于两边都关联,会形成死循环)
例如:父子关系引用
Table | Class | Relation |
---|---|---|
user(name,createDate) | user(name,createDate,articles) | oneToMany (One User can post many Articles) |
article(title) | article(title,user) | ManyToOne (one Article can be post by one User) |
=> 直接输出肯定是报循环错误
解决方案
方式一:在类属性上加入注解@JsonManagedReference
,@JsonBackReference
- User类中(父):
@JsonManagedReference public Set<Article> getArticles() { return articles; }
- Article类中(子):
@JsonBackReference public User getUser() { return user; }
- Result:
UserJson {"name":"chris","createDate":"2012-04-18","articles":[{"title":"title"}]} ArticleJson {"title":"title"}
方式二:加在类属性上加入注解@JsonIgnore
- User类中(父):
@JsonIgnore public Set<ArticleB> getArticles() { return articles; }
- Result:
UserJson {"name":"chris","createDate":"2014-07-23 11:03:44"} ArticleJson {"title":"title","user":{"name":"chris","createDate":"2014-07-23 11:03:44"}}
方式三: 在类上加入注解@JsonIgnoreProperties
- User类上(父):
@JsonIgnoreProperties("articles") public class User{...}
- Result(同方式二)
方式四:@JsonFilter
+ Jacksons filter
- User类上:
@JsonFilter ("myFilter" ) public class User{...}
- 测试:
String userJson = Jacksons.me().filter("myFilter" , "articles" ).readAsString(user);
- Result:
UserJson {"name":"chris","createDate":"2014-07-23 11:08:46"}
- 注意:
- 如果用另外一个没有添加该filter的ObjectMapper解析的话会报错
- 如果这个User类已经添加了
@JsonFilter("myFilter")
注解,但在另外一个地方又要解析它并不想过滤name 属性, - 那只能是
Jacksons.me().filter("myFilter", "")
,然后再读出来
方式五:@JsonIgnoreProperties
+Jacksons addMixInAnnotations
- 添加过滤类:
@JsonIgnoreProperties ("articles" ) public interface MixInUser{} // class 或interface都可
- 测试:
String mixInUser = Jacksons.me().addMixInAnnotations(User. class , MixInUser.class ).readAsString(user);
- Result:
UserJson {"name":"chris","createDate":"2014-07-23 11:10:43"}
单向过滤
使用@JsonIgnore
+@JsonProperty
应用: JsonDeserialize时过滤某属性,JsonSerialize时保留属性
@JsonIgnore
private Date createDate;
@JsonProperty
public Date getCreateDate(){
return this.createDate;
}
@JsonIgnore
public void setCreateDate(Date createDate){
this.createDate=createDate;
}
动态解析
@JsonSerialize
: 序列化 Object to JsonString@JsonDeserialize
:反序列化 JsonString to Object
使用举例:
- POJO:
@Column(name = "evalContent", nullable = false) @Lob @JsonSerialize(using=CustomContentSerialize.class) public byte[] getEvalContent(){ return this.evalContent; } @JsonDeserialize(using=CustomContentDeserialize.class) public void setEvalContent(byte[] evalContent){ this.evalContent = evalContent; }
- Serialize:Read Object to JsonString(CustomContentSerialize: byte[] to String)
public class CustomContentSerialize extends JsonSerializer<byte[]> { @Override public void serialize(byte[] value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { System.out.println("CustomContentSerialize------------"); String content=new String(value,"UTF-8"); /*System.out.println(content);*/ jgen.writeString(content); } }
- Deserialize:Read JsonString to Object (CustomContentDeserialize: String to byte[])
public class CustomContentDeserialize extends JsonDeserializer<byte[]> { @Override public byte[] deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { //System.out.println("CustomContentDeserialize-----------"); String content=jp.getText(); //System.out.println(content); return content.getBytes("UTF-8"); } }
SpringMVC中扩展应用
自定义
ObjectMapper
- 序列化时自动转换时间格式为
yyyy-MM-dd HH:mm:ss
序列化时对一些特殊字符进行转换(为防止Xss恶意攻击)
public class MyDateObjectMapper extends ObjectMapper implements InitializingBean { private static final long serialVersionUID = 293736193275041317L; public MyDateObjectMapper() { _serializationConfig = _serializationConfig.with(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); this.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } private boolean doHtmlXssSerializer=false; public boolean isDoHtmlXssSerializer(){ return doHtmlXssSerializer; } public void setDoHtmlXssSerializer(boolean doHtmlXssSerializer){ this.doHtmlXssSerializer = doHtmlXssSerializer; } @Override public void afterPropertiesSet() throws Exception{ System.out.println("doHtmlXssSerializer-----------"); if(doHtmlXssSerializer){ SimpleModule module = new SimpleModule("HTML XSS Serializer"); module.addSerializer(new JsonHtmlXssSerializer(String.class)); this.registerModule(module); } } } public class JsonHtmlXssSerializer extends StdSerializer<String>{ protected JsonHtmlXssSerializer(Class<String> t){ super(t); } @Override public void serialize(String value, JsonGenerator jgen,SerializerProvider provider) throws IOException,JsonProcessingException{ if (value != null) { String encodedValue=value.replaceAll("<", "<").replaceAll(">", ">"); System.out.println("encodedValue:"+encodedValue); jgen.writeString(encodedValue); } } }
- 序列化时自动转换时间格式为
Spring MVC 中注入自定义的
ObjectMapper
(配置xxx-servlet.xml
)<!-- Jackson ObjectMapper --> <bean id="myObjectMapper" class="com.cj.support.jackson.MyDateObjectMapper"> <property name="serializationInclusion"> <value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value> </property> <property name="doHtmlXssSerializer" value="false"/> </bean> <mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <!-- 这里注入自定义的ObjectMapper --> <property name="objectMapper" ref="myObjectMapper"/> </bean> </mvc:message-converters> </mvc:annotation-driven> <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> <property name="mediaTypes"> <map> <entry key="json" value="application/json"/> </map> </property> <property name="viewResolvers"> <list> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/"/> <property name="suffix" value=".jsp"/> </bean> </list> </property> <property name="defaultViews"> <list> <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" > <!-- 这里注入自定义的ObjectMapper --> <property name="objectMapper" ref="myObjectMapper" /> </bean> </list> </property> </bean>