JSON用于多态Java对象序列化

这篇博客探讨了如何使用Jackson JSON处理器处理Java多态对象的序列化和反序列化问题。通过在抽象类上添加注解,可以将类型信息保存在JSON中,从而在解析时能正确重建对象实例。
摘要由CSDN通过智能技术生成
长期以来,JSON已成为客户端和服务器之间各种数据序列化的事实上的标准。 除其他外,它的优势是简单和易于阅读。 但是,简单起了一些限制,我今天要谈的其中一个限制是:存储和检索多态Java对象。

让我们从一个简单的问题开始:过滤器的层次结构。 有一个抽象类AbstractFilter和两个子类RegexFilterStringMatchFilter

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值