国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Gson int類型被轉(zhuǎn)換成double問題解決(完美解決)

這篇具有很好參考價(jià)值的文章主要介紹了Gson int類型被轉(zhuǎn)換成double問題解決(完美解決)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

一、問題復(fù)現(xiàn)

1.1、BaseResponse類

class BaseResponse<T>(
    val code: Int = -1,
    val message: String? = null
) {
    var data: T? = null

    fun isSuccess(): Boolean {
        return code == 0
    }
}

1.2、不做任何處理,直接用Gson.fromJson解析

val json = "{\"code\":200,\"message\":\"成功\",\"data\":{\"ints\":200,\"doubles\":200.98,\"floats\":29.0986,\"longs\":29323627832875342,\"string\":\"字符串\"}}"
val baseResponse = Gson().fromJson(json, BaseResponse::class.java)
println(JsonUtils.toJson(baseResponse))

1.3、解析結(jié)果

I/System.out: {"code":200,"data":{"ints":200.0,"doubles":200.98,"floats":29.0986,"longs":2.9323627832875344E16,"string":"字符串"},"message":"成功"}

1.4、問題

Int類型的"ints"被轉(zhuǎn)換成了double類型、Long類型的"longs"也被轉(zhuǎn)換了

二、解決方案

2.1、舊的(網(wǎng)上千篇一律的復(fù)制方案,其實(shí)沒有任何卵用)

網(wǎng)上千篇一律就是新建TypeAdapter接口的子類,手動(dòng)轉(zhuǎn)換。MyDataTypeAdapter?

package com.xxx.baseapp.net;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.ToNumberPolicy;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.internal.LinkedTreeMap;
import com.google.gson.internal.bind.ObjectTypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;


public final class MyDataTypeAdapter extends TypeAdapter<Object> {
    public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
        @SuppressWarnings("unchecked")
        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
            if (type.getRawType() == Object.class) {
                return (TypeAdapter<T>) new MapTypeAdapter(gson);
            }
            return null;
        }
    };

    private final Gson gson;

    private MyDataTypeAdapter(Gson gson) {
        this.gson = gson;
    }

    @Override
    public Object read(JsonReader in) throws IOException {
        JsonToken token = in.peek();
        //判斷字符串的實(shí)際類型
        switch (token) {
            case BEGIN_ARRAY:
                List<Object> list = new ArrayList<>();
                in.beginArray();
                while (in.hasNext()) {
                    list.add(read(in));
                }
                in.endArray();
                return list;

            case BEGIN_OBJECT:
                Map<String, Object> map = new LinkedTreeMap<>();
                in.beginObject();
                while (in.hasNext()) {
                    map.put(in.nextName(), read(in));
                }
                in.endObject();
                return map;
            case STRING:
                return in.nextString();
            case NUMBER:
                String s = in.nextString();
                if (s.contains(".")) {
                    return Double.valueOf(s);
                } else {
                    try {
                        return Integer.valueOf(s);
                    } catch (Exception e) {
                        return Long.valueOf(s);
                    }
                }
            case BOOLEAN:
                return in.nextBoolean();
            case NULL:
                in.nextNull();
                return null;
            default:
                throw new IllegalStateException();
        }
    }

    @Override
    public void write(JsonWriter out, Object value) throws IOException {
        if (value == null) {
            out.nullValue();
            return;
        }
        //noinspection unchecked
        TypeAdapter<Object> typeAdapter = (TypeAdapter<Object>) gson.getAdapter(value.getClass());
        if (typeAdapter instanceof ObjectTypeAdapter) {
            out.beginObject();
            out.endObject();
            return;
        }
        typeAdapter.write(out, value);
    }

    /**
     * 使用自定義工廠方法取代 Gson 實(shí)例中的工廠方法
     */
    public Gson getGson() {
        Gson gson = new GsonBuilder().create();
        try {
            Field factories = Gson.class.getDeclaredField("factories");
            factories.setAccessible(true);
            Object o = factories.get(gson);
            Class<?>[] declaredClasses = Collections.class.getDeclaredClasses();
            for (Class c : declaredClasses) {
                if ("java.util.Collections$UnmodifiableList".equals(c.getName())) {
                    Field listField = c.getDeclaredField("list");
                    listField.setAccessible(true);
                    List<TypeAdapterFactory> list = (List<TypeAdapterFactory>) listField.get(o);
                    int i = list.indexOf(ObjectTypeAdapter.getFactory(ToNumberPolicy.DOUBLE));
                    list.set(i, MyDataTypeAdapter.FACTORY);
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return gson;
    }

} 

2.2、修改方案(看了源碼就快要解決了)

2.2.1、分析

通過分析GsonBuilder的構(gòu)造方法源碼:

   /**
   * Creates a GsonBuilder instance that can be used to build Gson with various configuration
   * settings. GsonBuilder follows the builder pattern, and it is typically used by first
   * invoking various configuration methods to set desired options, and finally calling
   * {@link #create()}.
   */
  public GsonBuilder() {
  }

  /**
   * Constructs a GsonBuilder instance from a Gson instance. The newly constructed GsonBuilder
   * has the same configuration as the previously built Gson instance.
   *
   * @param gson the gson instance whose configuration should by applied to a new GsonBuilder.
   */
  GsonBuilder(Gson gson) {
    ......
    this.objectToNumberStrategy = gson.objectToNumberStrategy;
    this.numberToNumberStrategy = gson.numberToNumberStrategy;
    this.reflectionFilters.addAll(gson.reflectionFilters);
  }


  /**
   * Configures Gson to apply a specific number strategy during deserialization of {@link Object}.
   *
   * @param objectToNumberStrategy the actual object-to-number strategy
   * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
   * @see ToNumberPolicy#DOUBLE The default object-to-number strategy
   * @since 2.8.9
   */
  public GsonBuilder setObjectToNumberStrategy(ToNumberStrategy objectToNumberStrategy) {
    this.objectToNumberStrategy = Objects.requireNonNull(objectToNumberStrategy);
    return this;
  }

可以發(fā)現(xiàn),在構(gòu)造的時(shí)候默認(rèn)了Object和Number類轉(zhuǎn)換成數(shù)字類型的處理策略,可以看到,Object轉(zhuǎn)換默認(rèn)為ToNumberPolicy.DOUBLE的dobule的類型,因此不單單是int會(huì)被轉(zhuǎn)換成double,Long類型等等數(shù)值類型都會(huì)默認(rèn)被轉(zhuǎn)換成dobule類型。

2.2.2、策略類

/**
 * An enumeration that defines two standard number reading strategies and a couple of
 * strategies to overcome some historical Gson limitations while deserializing numbers as
 * {@link Object} and {@link Number}.
 *
 * @see ToNumberStrategy
 * @since 2.8.9
 */
public enum ToNumberPolicy implements ToNumberStrategy {

  /**
   * Using this policy will ensure that numbers will be read as {@link Double} values.
   * This is the default strategy used during deserialization of numbers as {@link Object}.
   */
  DOUBLE {
    @Override public Double readNumber(JsonReader in) throws IOException {
      return in.nextDouble();
    }
  },

  /**
   * Using this policy will ensure that numbers will be read as a lazily parsed number backed
   * by a string. This is the default strategy used during deserialization of numbers as
   * {@link Number}.
   */
  LAZILY_PARSED_NUMBER {
    @Override public Number readNumber(JsonReader in) throws IOException {
      return new LazilyParsedNumber(in.nextString());
    }
  },

  /**
   * Using this policy will ensure that numbers will be read as {@link Long} or {@link Double}
   * values depending on how JSON numbers are represented: {@code Long} if the JSON number can
   * be parsed as a {@code Long} value, or otherwise {@code Double} if it can be parsed as a
   * {@code Double} value. If the parsed double-precision number results in a positive or negative
   * infinity ({@link Double#isInfinite()}) or a NaN ({@link Double#isNaN()}) value and the
   * {@code JsonReader} is not {@link JsonReader#isLenient() lenient}, a {@link MalformedJsonException}
   * is thrown.
   */
  LONG_OR_DOUBLE {
    @Override public Number readNumber(JsonReader in) throws IOException, JsonParseException {
      String value = in.nextString();
      try {
        return Long.parseLong(value);
      } catch (NumberFormatException longE) {
        try {
          Double d = Double.valueOf(value);
          if ((d.isInfinite() || d.isNaN()) && !in.isLenient()) {
            throw new MalformedJsonException("JSON forbids NaN and infinities: " + d + "; at path " + in.getPreviousPath());
          }
          return d;
        } catch (NumberFormatException doubleE) {
          throw new JsonParseException("Cannot parse " + value + "; at path " + in.getPreviousPath(), doubleE);
        }
      }
    }
  },

  /**
   * Using this policy will ensure that numbers will be read as numbers of arbitrary length
   * using {@link BigDecimal}.
   */
  BIG_DECIMAL {
    @Override public BigDecimal readNumber(JsonReader in) throws IOException {
      String value = in.nextString();
      try {
        return new BigDecimal(value);
      } catch (NumberFormatException e) {
        throw new JsonParseException("Cannot parse " + value + "; at path " + in.getPreviousPath(), e);
      }
    }
  }

}

通過上面的策略類源碼,我們發(fā)現(xiàn):LAZILY_PARSED_NUMBER?就是處理數(shù)值類型的枚舉,查看LazilyParsedNumber源碼,發(fā)現(xiàn)確實(shí)進(jìn)行了細(xì)致的數(shù)值類型處理劃分:

/**
 * This class holds a number value that is lazily converted to a specific number type
 *
 * @author Inderjeet Singh
 */
@SuppressWarnings("serial") // ignore warning about missing serialVersionUID
public final class LazilyParsedNumber extends Number {
  private final String value;

  /** @param value must not be null */
  public LazilyParsedNumber(String value) {
    this.value = value;
  }

  @Override
  public int intValue() {
    try {
      return Integer.parseInt(value);
    } catch (NumberFormatException e) {
      try {
        return (int) Long.parseLong(value);
      } catch (NumberFormatException nfe) {
        return new BigDecimal(value).intValue();
      }
    }
  }

  @Override
  public long longValue() {
    try {
      return Long.parseLong(value);
    } catch (NumberFormatException e) {
      return new BigDecimal(value).longValue();
    }
  }

  @Override
  public float floatValue() {
    return Float.parseFloat(value);
  }

  @Override
  public double doubleValue() {
    return Double.parseDouble(value);
  }

  @Override
  public String toString() {
    return value;
  }

  /**
   * If somebody is unlucky enough to have to serialize one of these, serialize
   * it as a BigDecimal so that they won't need Gson on the other side to
   * deserialize it.
   */
  private Object writeReplace() throws ObjectStreamException {
    return new BigDecimal(value);
  }

  private void readObject(ObjectInputStream in) throws IOException {
    // Don't permit directly deserializing this class; writeReplace() should have written a replacement
    throw new InvalidObjectException("Deserialization is unsupported");
  }

  @Override
  public int hashCode() {
    return value.hashCode();
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj instanceof LazilyParsedNumber) {
      LazilyParsedNumber other = (LazilyParsedNumber) obj;
      return value == other.value || value.equals(other.value);
    }
    return false;
  }
}

?2.2.2、最終解決方案

既然知道構(gòu)造的時(shí)候設(shè)置了默認(rèn)的?ToNumberPolicy.DOUBLE ,那修改起來就簡(jiǎn)單了,我們調(diào)用設(shè)置轉(zhuǎn)換的策略方法即可:

fun getGson(): Gson {
    val gsonBuilder = GsonBuilder()
    gsonBuilder.setObjectToNumberStrategy(ToNumberPolicy.LAZILY_PARSED_NUMBER)
    return gsonBuilder.create()
}

調(diào)用修改策略方案后的getGson解析?

val json = "{\"code\":200,\"message\":\"成功\",\"data\":{\"ints\":200,\"doubles\":200.98,\"floats\":29.0986,\"longs\":29323627832875342,\"string\":\"字符串\"}}"
val baseResponse = getGson().fromJson(json, BaseResponse::class.java)
println(JsonUtils.toJson(baseResponse))

測(cè)試結(jié)果:

I/System.out: {"code":200,"data":{"ints":200,"doubles":200.98,"floats":29.0986,"longs":29323627832875342,"string":"字符串"},"message":"成功"}

至此完美解決!?。?!

網(wǎng)上千篇一律的復(fù)制粘貼說這可以解決那個(gè)可以解決,結(jié)果然并卵。這個(gè)問題困擾了我2天,最后還是完美解決文章來源地址http://www.zghlxwxcb.cn/news/detail-501356.html

到了這里,關(guān)于Gson int類型被轉(zhuǎn)換成double問題解決(完美解決)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • char類型與int類型的轉(zhuǎn)換

    ? ? 在c語言中,char類型與int類型可以轉(zhuǎn)換,如何轉(zhuǎn)換我在此做一個(gè)粗略的總結(jié) 首先是char轉(zhuǎn)換為int 結(jié)果為:n 110 110 即將ASC碼強(qiáng)制轉(zhuǎn)換為int 但當(dāng)輸入的數(shù)字大于127(ASC碼的最大值)時(shí),-128和127就像轉(zhuǎn)盤一樣連在一起,如果上述代碼中a=128,則輸出? ?一個(gè)意義不明的符號(hào)(因

    2024年02月11日
    瀏覽(30)
  • 天坑!python【numpy.int64和int類型轉(zhuǎn)換】

    numpy.int64和int是不一樣的?。。?!一定要注意,這個(gè)坑我踩了好幾天才發(fā)現(xiàn)?。。。?! 比如說 :在處理dataframe的時(shí)候,讀取出來的可能是numpy.int64,但是后邊的程序需要int類型,你把numpy.int64喂給它,就會(huì)導(dǎo)致程序運(yùn)行不出你想要的結(jié)果,但又不報(bào)錯(cuò)。這個(gè)時(shí)候可以檢查一下

    2024年02月16日
    瀏覽(24)
  • C語言字符串轉(zhuǎn)換double等類型(sscanf,atof,strod)

    C語言字符串轉(zhuǎn)換double等類型(sscanf,atof,strod)

    例子: 注意: 忽略空格 ? 例子: 注意: sscanf解析字符串時(shí),空格通常被用作分隔符,可以用它來分隔字符串中的不同部分。 例如,以下代碼將把字符串\\\"123 456\\\"中的兩個(gè)整數(shù)讀入a和b中,空格用作分隔符: 在這個(gè)例子中,sscanf會(huì)忽略字符串中的多余空格,并將\\\"123\\\"解析為a的

    2024年02月14日
    瀏覽(21)
  • java中char類型轉(zhuǎn)換成int類型的方法

    java中char類型轉(zhuǎn)換成int類型的方法

    java中,需要對(duì)輸入進(jìn)行一些判斷,比如需要輸入的是數(shù)字,而用戶輸入了字符,那么就會(huì)報(bào)錯(cuò),因此用char或者String類型接收輸入的數(shù)據(jù)就不會(huì)報(bào)錯(cuò),但是問題來了:如何讓輸入的char或者String類型變?yōu)閿?shù)字呢? 以下是一些方法: 第一種利用Integer 包裝類 的方法 Integer.parseIn

    2024年02月13日
    瀏覽(69)
  • Java中將String類型轉(zhuǎn)換為int類型的方法

    在Java編程中,經(jīng)常需要將字符串類型(String)轉(zhuǎn)換為整數(shù)類型(int)。這在處理用戶輸入、讀取文件或進(jìn)行數(shù)值計(jì)算時(shí)非常常見。本文將詳細(xì)介紹如何在Java中進(jìn)行這種類型轉(zhuǎn)換,并提供相應(yīng)的源代碼示例。 Java提供了幾種方法來實(shí)現(xiàn)String到int的轉(zhuǎn)換。下面將介紹其中的兩種常

    2024年02月05日
    瀏覽(44)
  • Java 中將 String 類型轉(zhuǎn)換為 int 類型的方法

    在Java中將 String 類型轉(zhuǎn)換為 int 類型是一個(gè)常見的操作,因?yàn)樵趯?shí)際開發(fā)中,我們經(jīng)常需要從用戶輸入或者外部數(shù)據(jù)源中獲取字符串形式的數(shù)字,并將其轉(zhuǎn)換為整數(shù)進(jìn)行計(jì)算和處理。在Java中,有幾種方法可以實(shí)現(xiàn)這種轉(zhuǎn)換,下面我將逐一介紹這些方法。 Integer.parseInt() 方法是

    2024年04月22日
    瀏覽(78)
  • C語言中的char類型和int類型的相互轉(zhuǎn)換

    C語言是一種廣泛使用的編程語言,它具有高效、靈活、可移植等特點(diǎn)。C語言中有多種數(shù)據(jù)類型,用來表示不同的數(shù)據(jù)和信息。本文將介紹C語言中的兩種基本數(shù)據(jù)類型:char類型和int類型,以及它們之間的相互轉(zhuǎn)換的方法和原理。 char類型是一種字符類型,用來表示單個(gè)字符,

    2024年02月03日
    瀏覽(28)
  • C++中string類型和int類型之間的相互轉(zhuǎn)換【全網(wǎng)最全】

    字符串操作是各種算法題中的??停芏鄶?shù)據(jù)常常以字符串形式給出,其中有的需要自己轉(zhuǎn)化成整數(shù),而一些整型數(shù)據(jù)有時(shí)轉(zhuǎn)換成字符串處理起來更加方便,比如判斷一個(gè)整數(shù)是否是回文數(shù),所以字符串和整數(shù)的轉(zhuǎn)換是一些問題處理的基礎(chǔ)步驟, C++ ?在處理這類問題時(shí)并不像

    2024年02月04日
    瀏覽(31)
  • python中str與int類型的相互轉(zhuǎn)換

    1. str轉(zhuǎn)換成int 方法:使用int()函數(shù) 3. int轉(zhuǎn)換成str 方法:使用str()函數(shù)

    2024年02月13日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包