jackson 自定义解析类,处理复杂类型

本文简介

当jackson默认的解析方法不能成功将你的对象转换成json时,需要自定义解析器,去解决这个问题。可以自己转换成json,也可以把自己的对象转换成jackson能处理的对象。比如把 Multimap 转换成 Map。

引出问题

jackson默认的解析方法基本够大多数我使用了,但是有时候会遇到有一些情况,它不能解析的。会得到结果{"empty":false},在这种情况下,我们需要自定义处理方法。

问题说明

我们知道Map是 key-value 类型的,如果一个Map<String,String>,这样子的话,多次put 同一个key,会覆盖掉前面的value,但是有些情况下我们需要多个value,这时我们会用到 google guava 包下面的 Multimap 类,这个类的value,默认是个集合,多次put会自动添加到value的集合中而不会覆盖。
但是在 SpringMVC 框架中,@ResponseBody 的返回值是由 org.springframework.http.converter.json.MappingJackson2HttpMessageConverter类处理的,这时会出现问题。

jackson默认不支持Multimap类,所以转换结果就是 {"empty":false},这并不是我们想要的。

解决方法

jackson中有注解 @JsonSerialize,此注解中有两个值是我们需要使用的。使用方法如下:

public class Bean{

    //处理List的泛型
    @JsonSerialize(contentUsing = MultiMapSerializer.class)
    private List<Multimap> list;

    //处理属性本身
    @JsonSerialize(using = MultiMapSerializer.class)
    private Multimap map;
}

如上两种方法,一个是处理泛型,一个是处理属性。只需要添加在你的bean的属性上即可,另外需要再添加一个MultiMapSerializer类。

MultiMapSerializer类是参照 MapSerializer 实现的。

package com.util.jackson;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.ContainerSerializer;
import com.google.common.collect.Multimap;

import java.io.IOException;
import java.util.Map;

/**
 * 此类用于让jackson可以解析google guava 的 multimap, 而不至于出现 {"empty":false} 这样的结果
 * 使用方法:在 Multimap的属性上添加 @JsonSerialize(using = MultiMapSerializer.class)
 * 在Multimap作为泛型的属性上(如List<Multimap>)添加 @JsonSerialize(contentUsing = MultiMapSerializer.class)
 * <p/>
 * Created by liuyibo on 15/9/8.
 * E-Mail:zhanlanstar@163.com
 */

public class MultiMapSerializer extends ContainerSerializer<Multimap<?, ?>> {
    public MultiMapSerializer() {
        super(Map.class, false);
    }

    @Override
    public JavaType getContentType() {
        return null;
    }

    @Override
    public JsonSerializer<?> getContentSerializer() {
        return null;
    }

    @Override
    public boolean isEmpty(Multimap<?, ?> value) {
        return false;
    }

    @Override
    public boolean hasSingleElement(Multimap<?, ?> value) {
        return false;
    }

    @Override
    protected ContainerSerializer<?> _withValueTypeSerializer(TypeSerializer vts) {
        return null;
    }

    @Override
    public void serialize(Multimap<?, ?> value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
        //这里直接把value转换成map,jackson能处理map,交给它去处理
        jgen.writeObject(value.asMap());
    }
}

在这个类里只需要写好构造函数,并在serialize(Multimap<?, ?> value, JsonGenerator jgen, SerializerProvider provider)方法中写好处理方法就可以了。
处理方法有两种:一种是自己转换成json,写入到JsonGenerator jgen对象中。
另一种是把自己的对象转换成jackson能处理的对象。
这里我使用第二种。
推荐使用第二种,可以避免发生不可预料的错误。

总结

写得好的代码,写得好的框架,或者工具,都是可扩展的。而可扩展的代码,在一开始看的时候总是会有各种各样不理解的东西出现在眼前。看得多了就能看懂了,但是最重要的还是要思考,看看别人怎么写的,如何能在自己的代码中,也可以实现轻松自如的扩展。
可能一开始你的想法并不会被所有人理解,你要习惯,你要坚持,同时也要面对自己的错误,你会被别人认可的,只是并不会从一开始就会。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
自定义字段类型解析器是一种用于处理复杂对象的方式。通过自定义字段类型解析器,我们可以将复杂对象转换为数据库中的特定类型,或者将数据库中的特定类型转换为复杂对象。 下面是一个示例,演示如何自定义字段类型解析器: ```java import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.TypeHandler; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class MyFieldTypeHandler implements TypeHandler<Object> { @Override public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException { // 将复杂对象转换为数据库中的特定类型,并设置到PreparedStatement中 // 例如,将对象转换为JSON字符串,将JSON字符串设置到PreparedStatement中 ps.setString(i, convertObjectToJson(parameter)); } @Override public Object getResult(ResultSet rs, String columnName) throws SQLException { // 从ResultSet中获取数据库中的特定类型,并将其转换为复杂对象 // 例如,从JSON字符串中解析出对象 return convertJsonToObject(rs.getString(columnName)); } @Override public Object getResult(ResultSet rs, int columnIndex) throws SQLException { // 从ResultSet中获取数据库中的特定类型,并将其转换为复杂对象 // 例如,从JSON字符串中解析出对象 return convertJsonToObject(rs.getString(columnIndex)); } @Override public Object getResult(CallableStatement cs, int columnIndex) throws SQLException { // 从CallableStatement中获取数据库中的特定类型,并将其转换为复杂对象 // 例如,从JSON字符串中解析出对象 return convertJsonToObject(cs.getString(columnIndex)); } private String convertObjectToJson(Object object) { // 将对象转换为JSON字符串的逻辑 // 例如,使用Jackson库将对象转换为JSON字符串 return jsonConverter.convertToJson(object); } private Object convertJsonToObject(String json) { // 将JSON字符串转换为对象的逻辑 // 例如,使用Jackson库将JSON字符串转换为对象 return jsonConverter.convertToObject(json); } } ``` 在上面的示例中,我们实现了`TypeHandler`接口,并重写了其中的方法。在`setParameter`方法中,我们将复杂对象转换为数据库中的特定类型,并将其设置到`PreparedStatement`中。在`getResult`方法中,我们从`ResultSet`中获取数据库中的特定类型,并将其转换为复杂对象。 通过使用自定义字段类型解析器,我们可以灵活地处理复杂对象,并将其存储到数据库中或从数据库中读取出来。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值