OpenFeign使用Gson编解码自定义TypeAdapter

OpenFeign使用Gson编解码时,针对日期时间类型的一些bean编解码不支持,可以通过自定义TypeAdapter来解决

自定义TypeAdapter

  • ImprovedDateTypeAdapter
public class ImprovedDateTypeAdapter extends TypeAdapter<Date> {



    public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {

        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {

            @SuppressWarnings("unchecked")
            TypeAdapter<T> typeAdapter = (TypeAdapter<T>) ((typeToken.getRawType() == Date.class) ? new ImprovedDateTypeAdapter()
                    : null);
            return typeAdapter;
        }
    };
    private final DateFormat enUsFormat;
    private final DateFormat localFormat;
    private final DateFormat iso8601Format;
    private final DateFormat commonFormat;

    private List<DateFormat> supportFmt = new ArrayList<>();

    public ImprovedDateTypeAdapter() {
        this.enUsFormat = DateFormat.getDateTimeInstance(2, 2, Locale.US);

        this.localFormat = DateFormat.getDateTimeInstance(2, 2);

        this.iso8601Format = buildIso8601Format();
        this.commonFormat = buildCommonFormat();

        supportFmt.add(commonFormat);
        supportFmt.add(localFormat);
        supportFmt.add(enUsFormat);
        supportFmt.add(iso8601Format);
    }

    private static DateFormat buildCommonFormat() {
        DateFormat commonFormat = new SimpleDateFormat(
                DEFAULT_DATE_TIME_FORMAT, Locale.CHINA);
        commonFormat.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
        return commonFormat;
    }

    private static DateFormat buildIso8601Format() {
        DateFormat iso8601Format = new SimpleDateFormat(
                "yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
        iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
        return iso8601Format;
    }

    @Override
    public Date read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
            in.nextNull();
            return null;
        }
        return deserializeToDate(in.nextString());
    }

    private synchronized Date deserializeToDate(String json) {
        boolean validFastTime = validFastTime(json);
        if (validFastTime) {
            return new Date(Long.parseLong(json));
        }

        for (DateFormat dateFormat : supportFmt) {
            try {
                return dateFormat.parse(json);
            } catch (ParseException parseException) {
                // try next fmt
            }
        }

        throw new JsonSyntaxException(json);
    }


    private boolean validFastTime(String json) {

        try {
            long l = Long.parseLong(json);
            return l >= 0;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    @Override
    public synchronized void write(JsonWriter out, Date value)
            throws IOException {
        if (value == null) {
            out.nullValue();
            return;
        }
        String dateFormatAsString = this.commonFormat.format(value);
        out.value(dateFormatAsString);
    }
}
  • LocalDateTypeAdapter
public class LocalDateTypeAdapter extends TypeAdapter<LocalDate> {
    @Override
    public void write(JsonWriter out, LocalDate value) throws IOException {
        if (value == null) {
            out.nullValue();
            return;
        }

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DateConfig.DEFAULT_DATE_FORMAT);
        String localDate = dateTimeFormatter.format(value);
        out.value(localDate);
    }

    @Override
    public LocalDate read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
            in.nextNull();
            return null;
        }

        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(DateConfig.DEFAULT_DATE_FORMAT);

        return LocalDate.parse(in.nextString(), dateFormatter);

    }
}

编解码器的配置

@Configuration
public class GsonConfig {

    /**
     * FeignClientsConfiguration
     * FeignClientsRegistrar
     * @return
     */
    @Bean("customGsonDecoder")
    public Decoder feignDecoder() {
        return new GsonDecoder(cusTypeAdapters());
    }

    @Bean("customGsonEncoder")
    public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) {
        return new GsonEncoder(cusTypeAdapters());
    }

    public List<TypeAdapter<?>> cusTypeAdapters(){
        List<TypeAdapter<?>> adapters = new ArrayList<>();
        adapters.add(new ImprovedDateTypeAdapter());
        adapters.add(new LocalDateTypeAdapter());
        adapters.add(new LocalTimeTypeAdapter());
        adapters.add(new LocalDateTimeTypeAdapter());
        // todo add cus adapter s
        return  adapters;
    }


}

PS

  • 字段命名注意
    NOT: aBoxLong --> aboxLong
    PREFER: boxLong --> boxLong

  • jackson 日期格式序列化+时区设置
    spring:
    jackson:
    date-format: ‘yyyy/MM/dd HH:mm:ss’
    time-zone: ‘GMT+8’

  • Feign (OKHTTP Client)发送POST请求报错
    Content type application/octet-stream not supported

Feign (OKHTTP Client)尝试通过@Headers添加Content-Type无效
NOT: @Headers({“Content-Type: application/json”})

PREFER: 
@PostMapping(value = "postForm", consumes = "application/x-www-form-urlencoded")
@PostMapping(value = "postJson", consumes = "application/json")
@PostMapping(value = "postJson", headers = {"ContentType=application/json"})

> Content-Type  application/json;charset=UTF-8
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值