Java JodaTime LocalDate/LocalTime未使用自定义JSON序列化程序类进行解析

Java JodaTime LocalDate/LocalTime未使用自定义JSON序列化程序类进行解析,java,android,json,gson,jodatime,Java,Android,Json,Gson,Jodatime,我有一个名为ReportEvent的对象,它从JodaTimeAPI/framework获取LocalTime和LocalDate。这个ReportEvent可以通过谷歌的GSON转换API写入JSON。但是,反序列化JodaTime部分时会导致问题 Logcat错误报告: 10-16 13:23:01.812: E/AndroidRuntime(8884): FATAL EXCEPTION: main 10-16 13:23:01.812: E/AndroidRuntime(8884): ja

我有一个名为
ReportEvent
的对象,它从
JodaTime
API/framework获取
LocalTime
LocalDate
。这个
ReportEvent
可以通过谷歌的
GSON
转换API写入
JSON
。但是,反序列化
JodaTime部分时会导致问题

Logcat错误报告:

10-16 13:23:01.812: E/AndroidRuntime(8884): FATAL EXCEPTION: main
10-16 13:23:01.812: E/AndroidRuntime(8884): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.nanospark.cnc/com.nanospark.cnc.MainActivity}: java.lang.IllegalArgumentException: Invalid format: "{"iChronology":{"iBase":{"iMinDa..."
10-16 13:23:01.812: E/AndroidRuntime(8884):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at android.app.ActivityThread.access$600(ActivityThread.java:141)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at android.os.Handler.dispatchMessage(Handler.java:99)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at android.os.Looper.loop(Looper.java:137)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at android.app.ActivityThread.main(ActivityThread.java:5103)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at java.lang.reflect.Method.invokeNative(Native Method)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at java.lang.reflect.Method.invoke(Method.java:525)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at dalvik.system.NativeStart.main(Native Method)
10-16 13:23:01.812: E/AndroidRuntime(8884): Caused by: java.lang.IllegalArgumentException: Invalid format: "{"iChronology":{"iBase":{"iMinDa..."
10-16 13:23:01.812: E/AndroidRuntime(8884):     at org.joda.time.format.DateTimeFormatter.parseLocalDateTime(DateTimeFormatter.java:854)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at org.joda.time.format.DateTimeFormatter.parseLocalDate(DateTimeFormatter.java:798)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.nanospark.cnc.LocalDateSerializer.deserialize(LocalDateSerializer.java:32)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.nanospark.cnc.LocalDateSerializer.deserialize(LocalDateSerializer.java:1)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.google.gson.TreeTypeAdapter.read(TreeTypeAdapter.java:58)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:95)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:183)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:81)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:60)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.google.gson.Gson.fromJson(Gson.java:805)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.google.gson.Gson.fromJson(Gson.java:770)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.google.gson.Gson.fromJson(Gson.java:719)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.nanospark.cnc.GlobalData.retrieveGlobalDataFromStorage(GlobalData.java:118)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at com.nanospark.cnc.MainActivity.onCreate(MainActivity.java:35)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at android.app.Activity.performCreate(Activity.java:5133)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
10-16 13:23:01.812: E/AndroidRuntime(8884):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)
10-16 13:23:01.812: E/AndroidRuntime(8884):     ... 11 more
守则的有关章节:

本地时间序列化程序/反序列化程序

package com.nanospark.cnc;

import java.lang.reflect.Type;

import org.joda.time.LocalTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;


public class LocalTimeSerializer implements JsonDeserializer<LocalTime>, JsonSerializer<LocalTime>
{

   private static final DateTimeFormatter TIME_FORMAT = ISODateTimeFormat.timeNoMillis();

   @Override
   public LocalTime deserialize(final JsonElement je, final Type type,
                           final JsonDeserializationContext jdc) throws JsonParseException
   {
      final String dateAsString = je.toString();
      if (je.isJsonNull() || dateAsString.length() == 0)
      {
         return null;
      }
      else
      {
         return TIME_FORMAT.parseLocalTime(dateAsString);         
      }
   }

   @Override
   public JsonElement serialize(final LocalTime src, final Type typeOfSrc,
                                final JsonSerializationContext context)
   {
      String retVal;
      if (src == null)
      {
         retVal = "";
      }
      else
      {
         retVal = TIME_FORMAT.print(src);
      }
      return new JsonPrimitive(retVal);
   }

}
public class LocalDateSerializer implements JsonSerializer<LocalDate>, JsonDeserializer<LocalDate>
{

  private static final String PATTERN = "yyyy-MM-dd";
  final DateTimeFormatter fmt = DateTimeFormat.forPattern(PATTERN);


  @Override
  public JsonElement serialize(LocalDate src, Type typeOfSrc, JsonSerializationContext context)
  {
    String retVal = fmt.print(src);
    Log.v("MY LOCALDATE SERIALIZED", retVal);
    return new JsonPrimitive(retVal);
  }


  @Override
  public LocalDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException
  {

    Log.v("MY LOCALDATE DESERIALIZED",json.toString());
    return fmt.parseLocalDate(json.toString());
  }
}
package com.nanopark.cnc;
导入java.lang.reflect.Type;
导入org.joda.time.LocalTime;
导入org.joda.time.format.DateTimeFormatter;
导入org.joda.time.format.ISODateTimeFormat;
导入com.google.gson.JsonDeserializationContext;
导入com.google.gson.JsonDeserializer;
导入com.google.gson.JsonElement;
导入com.google.gson.JsonParseException;
导入com.google.gson.JsonPrimitive;
导入com.google.gson.JsonSerializationContext;
导入com.google.gson.JsonSerializer;
公共类LocalTimeSerializer实现JsonDeserializer、JsonSerializer
{
私有静态final DateTimeFormatter TIME_FORMAT=ISODateTimeFormat.timenomilis();
@凌驾
公共本地时间反序列化(最终JsonElement je,最终类型,
最终JsonDeserializationContext(jdc)抛出JsonParseException
{
最后一个字符串dateAsString=je.toString();
if(je.isJsonNull()| | dateAsString.length()==0)
{
返回null;
}
其他的
{
返回时间\格式.parseLocalTime(dateAsString);
}
}
@凌驾
公共JsonElement序列化(最终LocalTime src,最终类型typeOfSrc,
最终JsonSerializationContext(上下文)
{
字符串检索;
如果(src==null)
{
retVal=“”;
}
其他的
{
retVal=时间\格式打印(src);
}
返回新的JsonPrimitive(retVal);
}
}
LocalDate序列化程序/反序列化程序

package com.nanospark.cnc;

import java.lang.reflect.Type;

import org.joda.time.LocalTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;


public class LocalTimeSerializer implements JsonDeserializer<LocalTime>, JsonSerializer<LocalTime>
{

   private static final DateTimeFormatter TIME_FORMAT = ISODateTimeFormat.timeNoMillis();

   @Override
   public LocalTime deserialize(final JsonElement je, final Type type,
                           final JsonDeserializationContext jdc) throws JsonParseException
   {
      final String dateAsString = je.toString();
      if (je.isJsonNull() || dateAsString.length() == 0)
      {
         return null;
      }
      else
      {
         return TIME_FORMAT.parseLocalTime(dateAsString);         
      }
   }

   @Override
   public JsonElement serialize(final LocalTime src, final Type typeOfSrc,
                                final JsonSerializationContext context)
   {
      String retVal;
      if (src == null)
      {
         retVal = "";
      }
      else
      {
         retVal = TIME_FORMAT.print(src);
      }
      return new JsonPrimitive(retVal);
   }

}
public class LocalDateSerializer implements JsonSerializer<LocalDate>, JsonDeserializer<LocalDate>
{

  private static final String PATTERN = "yyyy-MM-dd";
  final DateTimeFormatter fmt = DateTimeFormat.forPattern(PATTERN);


  @Override
  public JsonElement serialize(LocalDate src, Type typeOfSrc, JsonSerializationContext context)
  {
    String retVal = fmt.print(src);
    Log.v("MY LOCALDATE SERIALIZED", retVal);
    return new JsonPrimitive(retVal);
  }


  @Override
  public LocalDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException
  {

    Log.v("MY LOCALDATE DESERIALIZED",json.toString());
    return fmt.parseLocalDate(json.toString());
  }
}
公共类LocalDateSerializer实现JsonSerializer、JsonDeserializer { 私有静态最终字符串模式=“yyyy-MM-dd”; final DateTimeFormatter fmt=DateTimeFormat.forPattern(模式); @凌驾 公共JsonElement序列化(LocalDate src,类型typeOfSrc,JsonSerializationContext) { 字符串retVal=fmt.print(src); Log.v(“我的LOCALDATE序列化”,retVal); 返回新的JsonPrimitive(retVal); } @凌驾 公共LocalDate反序列化(JsonElement json,类型typeOfT,JsonDeserializationContext) 抛出JsonParseException { v(“MyLocalDate反序列化”,json.toString()); 返回fmt.parseLocalDate(json.toString()); } }
问题在于序列化数据的代码

在最初的问题中,当您要反序列化(
retrieveGlobalDataFromStorage
)时,您有以下代码:

但是当您要序列化(
storeGlobalData
)时,您只需要:

Gson gson = new Gson();

您应该在这两个位置注册类型适配器。我将把代码(
Gson
initialization)提取到一个单独的方法中,您可以从两个方法中调用该方法

使用

    return fmt.parseLocalDate(json.toString());
因为它可能会产生意外的引号
“2014-10-28”

最好改为使用:

    return fmt.parseLocalDate(json.getAsString());

我发布的另一个相关问题是,GSON/JSON位在这里是否真的相关,或者你能用一段简单得多的代码重现这个问题,它只是构建了一个格式化程序,然后解析了一个硬编码字符串?这将更容易帮助您。为什么不在尝试解析它之前记录它呢?这样,您只需要在解析调用之前添加一条语句……不,绝对不是。有关
ISODateFormat
希望解析的内容,请参阅我前面的评论。现在看看你的数据。他们一点也不像。这在JSON中是一个非常奇怪的日期表示形式——我强烈建议您更改序列化代码,使其输出ISO 8601格式的日期。我回到了您的第一个修订版本,查看并添加了一个答案。请注意,通过日志记录和调试,您应该能够自己完成相当多的诊断工作。。。我在这里没有给出太多的实际信息,除了建议诊断应该做什么,没有一个是特别有洞察力的。是的,我后来发现了这个发现。不过,让别人知道是件好事。