让我们从一个简单的问题开始:过滤器的层次结构。 有一个抽象类AbstractFilter和两个子类RegexFilter和StringMatchFilter 。
package bean.json.examples;
public abstract class AbstractFilter {
public abstract void filter();
}
这是RegexFilter类:
package bean.json.examples;
public class RegexFilter extends AbstractFilter {
private String pattern;
public RegexFilter( final String pattern ) {
this.pattern = pattern;
}
public void setPattern( final String pattern ) {
this.pattern = pattern;
}
public String getPattern() {
return pattern;
}
@Override
public void filter() {
// Do some work here
}
}
这是StringMatchFilter类:
package bean.json.examples;
public class StringMatchFilter extends AbstractFilter {
private String[] matches;
private boolean caseInsensitive;
public StringMatchFilter() {
}
public StringMatchFilter( final String[] matches, final boolean caseInsensitive ) {
this.matches = matches;
this.caseInsensitive = caseInsensitive;
}
public String[] getMatches() {
return matches;
}
public void setCaseInsensitive( final boolean caseInsensitive ) {
this.caseInsensitive = caseInsensitive;
}
public void setMatches( final String[] matches ) {
this.matches = matches;
}
public boolean isCaseInsensitive() {
return caseInsensitive;
}
@Override
public void filter() {
// Do some work here
}
}
没什么,纯Java Bean。 现在,如果我们需要将AbstractFilter实例的列表存储到JSON,更重要的是,要从JSON重新构造此列表,该怎么办? 以下类Filters演示了我的意思:
package bean.json.examples;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class Filters {
private Collection< AbstractFilter > filters = new ArrayList< AbstractFilter >();
public Filters() {
}
public Filters( final AbstractFilter ... filters ) {
this.filters.addAll( Arrays.asList( filters ) );
}
public Collection< AbstractFilter > getFilters() {
return filters;
}
public void setFilters( final Collection< AbstractFilter > filters ) {
this.filters = filters;
}
}
由于JSON是文本的,平台无关的格式,因此它不包含任何类型特定的信息。 得益于出色的Jackson JSON处理器,它可以轻松完成。 因此,让我们将Jackson JSON处理器添加到我们的POM文件中:
<project>
<modelversion>
4.0.0
</modelversion>
<groupid>
bean.json
</groupid>
<artifactid>
examples
</artifactid>
<version>
0.0.1-SNAPSHOT
</version>
<packaging>
jar
</packaging>
<properties>
<project.build.sourceencoding>
UTF-8
</project.build.sourceencoding>
</properties>
<dependencies>
<dependency>
<groupid>
org.codehaus.jackson
</groupid>
<artifactid>
jackson-mapper-asl
</artifactid>
<version>
1.9.6
</version>
</dependency>
</dependencies>
</project>
完成此步骤后,我们需要告诉Jackson ,我们打算将类型信息与对象一起存储在JSON中,以便稍后可以从JSON重建确切的对象。 很少有AbstractFilter上的注释可以做到这一点。
import org.codehaus.jackson.annotate.JsonSubTypes;
import org.codehaus.jackson.annotate.JsonSubTypes.Type;
import org.codehaus.jackson.annotate.JsonTypeInfo;
import org.codehaus.jackson.annotate.JsonTypeInfo.Id;
@JsonTypeInfo( use = Id.NAME )
@JsonSubTypes(
{
@Type( name = "Regex", value = RegexFilter.class ),
@Type( name = "StringMatch", value = StringMatchFilter.class )
}
)
public abstract class AbstractFilter {
// ...
}
而且...就是这样! 跟随帮助器类的工作是肮脏的工作,即将过滤器序列化为字符串,然后使用Jackson的 ObjectMapper从字符串反序列化它们:
package bean.json.examples;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import org.codehaus.jackson.map.ObjectMapper;
public class FilterSerializer {
private final ObjectMapper mapper = new ObjectMapper();
public String serialize( final Filters filters ) {
final StringWriter writer = new StringWriter();
try {
mapper.writeValue( writer, filters );
return writer.toString();
} catch( final IOException ex ) {
throw new RuntimeException( ex.getMessage(), ex );
} finally {
try { writer.close(); } catch ( final IOException ex ) { /* Nothing to do here */ }
}
}
public Filters deserialize( final String str ) {
final StringReader reader = new StringReader( str );
try {
return mapper.readValue( reader, Filters.class );
} catch( final IOException ex ) {
throw new RuntimeException( ex.getMessage(), ex );
} finally {
reader.close();
}
}
}
让我们看看实际情况。 以下代码示例
final String json = new FilterSerializer().serialize(
new Filters(
new RegexFilter( "\\d+" ),
new StringMatchFilter( new String[] { "String1", "String2" }, true )
)
);
产生以下JSON:
{ "filters":
[
{"@type":"Regex","pattern":"\\d+"},
{"@type":"StringMatch","matches":["String1","String2"],"caseInsensitive":true}
]
}
如您所见, “ filters”集合中的每个条目都具有属性“ @type” ,该属性具有我们通过注释AbstractFilter类指定的值。 调用new FilterSerializer()。deserialize(json)会生成完全相同的Filters对象实例。
参考:我们的JCG合作伙伴 Andrey Redko在Andriy Redko {devmind}博客上提供了用于多态Java对象序列化的JSON 。
翻译自: https://www.javacodegeeks.com/2012/05/json-for-polymorphic-java-object.html