java - 有没有办法让retrofit/gson将双时间戳转换为long?

标签 java json casting gson retrofit2

我正在开发一个 Android 应用。我正在使用带有 Gson 的改造来调用服务器并序列化/反序列化。在请求中,有一个响应类,其中包含时间戳(long)。有时它是一个 double,因为 iOS 版本的应用程序使用 double 来存储时间戳。

有没有办法强制Gson反序列化响应并转换为Response类(长)上存在的对象?

异常(exception):

Caused by com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: Expected a long but was 1555323142345.364 at line 1 column 1002 path $.userSettings.stories[4].readTimestamp
       at com.google.gson.internal.bind.TypeAdapters$11.read(TypeAdapters.java:323)
       at com.google.gson.internal.bind.TypeAdapters$11.read(TypeAdapters.java:313)
       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
       at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41)
       at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82)
       at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
       at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:37)
       at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:25)
       at retrofit2.ServiceMethod.toResponse(ServiceMethod.java:119)
       at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:218)
       at retrofit2.OkHttpCall.execute(OkHttpCall.java:180)
       at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:91)
       at inesc_id.pt.motivandroid.motviAPIClient.MotivAPIClientManager$CheckOnboardingNeededAndRetrieve.doInBackground(MotivAPIClientManager.java:909)
       at inesc_id.pt.motivandroid.motviAPIClient.MotivAPIClientManager$CheckOnboardingNeededAndRetrieve.doInBackground(MotivAPIClientManager.java:711)
       at android.os.AsyncTask$2.call(AsyncTask.java:307)
       at java.util.concurrent.FutureTask.run(FutureTask.java:237)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
       at java.lang.Thread.run(Thread.java:833)

类(class):



public class StoryStateful implements Serializable{

    @Expose
    int storyID;

    @Expose
    boolean read;

    @Expose
    long readTimestamp;

    @Expose
    long availableTimestamp;
}


最佳答案

为简单起见,假设您的 JSON 有效负载为:

{
    "timestamp": 1555323142345.345
}

它应该适合:

class Pojo {

    private long timestamp;

    // getters, setters, toString
}

解决方案取决于您是否可以更改 Pojo 模型。如果是,并且您想存储 doublelong ,可以将类型更改为 Number:

private Number timestamp;

并且您应该能够解析 doublelong 的时间戳。如果您总是想要long,您需要实现自定义反序列化器:

class LongOrDoubleJsonDeserializer implements JsonDeserializer<Long> {

    @Override
    public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json.isJsonPrimitive()) {
            Number number = json.getAsNumber();

            return number.longValue();
        }

        return null;
    }
}

您的 Pojo 属性应如下所示:

@JsonAdapter(LongOrDoubleJsonDeserializer.class)
private long timestamp;

如果您无法更改 Pojo 类,则需要实现自定义 TypeAdapterFactory 并使用 GsonBuilder 注册。请参阅此链接:Creating the Retrofit instance 。自定义实现可能如下所示:

class LongOrDoubleTypeAdapterFactory implements TypeAdapterFactory {

    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        Class<? super T> rawType = type.getRawType();
        if (rawType == Long.class || rawType == long.class) {
            return new TypeAdapter<T>() {
                @Override
                public void write(JsonWriter out, T value) {
                }

                @Override
                public T read(JsonReader in) throws IOException {
                    try {
                        return (T) new Long(in.nextLong());
                    } catch (NumberFormatException e) {
                        return (T) new Long(((Double) in.nextDouble()).longValue());
                    }
                }
            };
        }
        return null;
    }
}

并按如下方式注册:

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(new LongOrDoubleTypeAdapterFactory())
    .create();

关于java - 有没有办法让retrofit/gson将双时间戳转换为long?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55716058/

相关文章:

java - 有没有办法在 JVM 中找到加载的类文件?

java - 通过VTD-XML将多个元素写入XML

c++ - 删除指向派生对象的基指针

java - 添加 Openfeign 依赖时出现 java.lang.IllegalStateException

java - com.android.phone 停止工作

java - 如何避免使用许多 @SerializedName ?

python - 错误: 'str' object has no attribute 'read'

json - 获取 YouTube 直播的当前观看人数

将 NSObject 子类转换为非 objc 协议(protocol)时,Swift 崩溃

c# - 为什么我不能将泛型类型的一个实例化转换为另一个实例化?