Json文字列をJavaオブジェクトに変換し、それをlongとして表示する必要があります。json文字列は、長い数値の固定配列です。
{numbers
[ 268627104, 485677888, 506884800 ] }
変換するコードは、0で終わる数値を除くすべてのケースで正常に機能します。これらは、科学表記の数値形式に変換されます。
public static Object fromJson(HttpResponse response, Class<?> classOf)
throws IOException {
InputStream instream = response.getResponseInputStream();
Object obj = null;
try {
Reader reader = new InputStreamReader(instream, HTTP.UTF_8);
Gson gson = new Gson();
obj = gson.fromJson(reader, classOf);
Logger.d(TAG, "json --> "+gson.toJson(obj));
} catch (UnsupportedEncodingException e) {
Logger.e(TAG, "unsupported encoding", e);
} catch (Exception e) {
Logger.e(TAG, "json parsing error", e);
}
return obj;
}
実際の結果:Javaオブジェクト:268627104、485677888、5.068848E + 8
最後の数値が科学表記形式に変換されていることに注意してください。誰かがそれを回避したり、それを防止したり、元に戻したりするために何ができるかを提案できますか? Gson v1.7.1を使用しています
文字列へのシリアル化がオプションである場合は、GSONを構成して次のようにすることができます。
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setLongSerializationPolicy( LongSerializationPolicy.STRING );
Gson gson = gsonBuilder.create();
これは次のようなものを生成します:
{numbers : [ "268627104", "485677888", "506884800" ] }
別の回避策は、代わりにJsonParserクラスを使用することです。これにより、ユーザー定義のクラスではなくGsonオブジェクト表現(JsonElement)が返されますが、科学表記への変換の問題は回避されます。
import Java.lang.reflect.Type;
import Java.util.Map;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
public class GsonTest
{
public static void main(String[] args)
{
String json = "{numbers:[268627104,485677888,506884800]}";
Gson gson = new Gson();
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> jsonMap = gson.fromJson(json, type);
System.out.println("Gson output:");
System.out.println(jsonMap);
JsonParser jsonParser = new JsonParser();
JsonElement jsonElement = jsonParser.parse(json);
System.out.println("JsonParser output:");
System.out.println(jsonElement);
}
}
コード出力:
Gson output:
{numbers=[2.68627104E8, 4.85677888E8, 5.068848E8]}
JsonParser output:
{"numbers":[268627104,485677888,506884800]}
同様の問題がありました。これは整数をdoubleに変換するだけでなく、この 関連する質問 で説明されているように、実際には特定の長い数値の精度を失います。
具体的には、この変換をObjectTypeAdapter
のread
メソッドに追跡しました。
_case NUMBER:
return in.nextDouble();
_
TypeAdapter
の変更されたObject
をプラグインすることは可能かもしれませんが、それを機能させることができなかったため、代わりにread
メソッド(Object read(JsonReader in)
)を自分のコードに追加し、上記の行を次のように変更します。
_case NUMBER:
final String s = in.nextString();
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
// ignore
}
try {
return Long.parseLong(s);
} catch (NumberFormatException e) {
// ignore
}
return Double.parseDouble(s);
_
Gsonがデフォルトでこれを実行したいと思います。
次に、他の接続部分を次のようなヘルパーメソッドに配置します。
_public static Object parse(final Reader r) {
try (final JsonReader jr = new JsonReader(r)) {
jr.setLenient(true);
boolean empty = true;
Object o = null;
try {
jr.peek();
empty = false;
o = read(jr);
} catch (EOFException e) {
if (!empty) {
throw new JsonSyntaxException(e);
}
}
if (o != null && jr.peek() != JsonToken.END_DOCUMENT) {
throw new JsonIOException("JSON document was not fully consumed.");
}
return o;
} catch (IOException e) {
throw new JsonIOException(e);
}
}
_
そこで、今ではnew Gson().fromJson(r, Object.class)
の代わりにparse(r)
を呼び出します。
これは、jsonデータを任意の構造で解析できるようにしたいのでうまくいきますが、ターゲットにしている特定のクラスがある場合は、おそらくそのクラスのメンバー内のObject
の出現を排除する必要があるだけです。
同じ問題がありました。調査の結果、私が見つけたものです。
動作:
Gson
はDouble
に変換します。Jackson
はInteger
またはLong
に変換します。数値の大きさによって異なります。可能な解決策:
Gson
の戻り値をDouble
からLong
に明示的に変換します。Jackson
を使用してください。コード-Jackson
のテスト
ParseNumberTest.Java:
import Java.util.List;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* test - jackson parse numbers,
*
* @author eric
* @date Jan 13, 2018 12:28:36 AM
*/
public class ParseNumberTest {
@Test
public void test() throws Exception {
String jsonFn = "numbers.json";
ObjectMapper mapper = new ObjectMapper();
DummyData dd = mapper.readValue(this.getClass().getResourceAsStream(jsonFn), DummyData.class);
for (Object data : dd.dataList) {
System.out.printf("data type: %s, value: %s\n", data.getClass().getName(), data.toString());
Assert.assertTrue(data.getClass() == Double.class || data.getClass() == Long.class || data.getClass() == Integer.class);
System.out.printf("%s\n\n", "------------");
}
}
static class DummyData {
List<Object> dataList;
public List<Object> getDataList() {
return dataList;
}
public void setDataList(List<Object> dataList) {
this.dataList = dataList;
}
}
}
numbers.json:
{
"dataList": [
150000000000,
150778742934,
150000,
150000.0
]
}
実行方法:
Jackson
&TestNG
に基づいています。numbers.json
と同じパッケージでParseNumberTest.Java
。出力:
data type: Java.lang.Long, value: 150000000000
------------
data type: Java.lang.Long, value: 150778742934
------------
data type: Java.lang.Integer, value: 150000
------------
data type: Java.lang.Double, value: 150000.0
------------
PASSED: test
スマートではありませんが、まだ機能している方法は、番号の最初と最後に "を追加することです。その後、処理が完了したら削除します。
以下のコードソリューションを番号Longに使用できます。
Document doc = documentCursor.next();
JsonWriterSettings relaxed = JsonWriterSettings.builder().outputMode(JsonMode.RELAXED).build();
CustomeObject obj = gson.fromJson(doc.toJson(relaxed), CustomeObject.class);