【问题标题】:Gson to json conversion with two DateFormat使用两个 DateFormat 将 Gson 转换为 json
【发布时间】:2013-03-22 05:09:52
【问题描述】:

我的服务器 JSON 返回两种不同类型的 DateFormat。 "MMM dd, yyyy" 和 "MMM dd, yyyy HH:mm:ss"

当我使用以下内容转换 JSON 时,这很好:

Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy").create();

但是当我想要详细的日期格式并将其更改为此时,它会抛出异常 com.google.gson.JsonSyntaxException: Mar 21, 2013

Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy HH:mm:ss").create();

gson 有没有办法为它的 Json 转换处理两种不同的 DateFormat?

【问题讨论】:

    标签: java gson


    【解决方案1】:

    我遇到了同样的问题。这是我通过自定义反序列化的解决方案:

    new GsonBuilder().registerTypeAdapter(Date.class, new DateDeserializer());
    
    private static final String[] DATE_FORMATS = new String[] {
            "MMM dd, yyyy HH:mm:ss",
            "MMM dd, yyyy"
    };
    
    
    private class DateDeserializer implements JsonDeserializer<Date> {
    
        @Override
        public Date deserialize(JsonElement jsonElement, Type typeOF,
                JsonDeserializationContext context) throws JsonParseException {
            for (String format : DATE_FORMATS) {
                try {
                    return new SimpleDateFormat(format, Locale.US).parse(jsonElement.getAsString());
                } catch (ParseException e) {
                }
            }
            throw new JsonParseException("Unparseable date: \"" + jsonElement.getAsString()
                    + "\". Supported formats: " + Arrays.toString(DATE_FORMATS));
        }
    }
    

    【讨论】:

    • 我在 Retrofit 中使用过这个 sn-p,但是被覆盖的方法永远不会被调用。但是,在 Retrofit 上下文之外(在测试类中)使用它时,它可以正常工作。我仍然对此感到困惑
    • 与改造配合使用没有问题。
    • 有没有办法在不抛出异常的情况下尝试格式化(我认为这对性能来说不是最佳的)?
    • @Ixx 最好的选择是找到一种使用一种格式的方法,但如果您需要多种格式,我认为您可以订购它们以减少异常数量。如果这不起作用,您可以尝试使用正则表达式并在之后应用格式,但是您需要衡量正则表达式与异常以确保值得这样做。
    【解决方案2】:

    虽然答案已被接受,但我想分享一个类似但更可扩展的解决方案。你可以找到gist here

    DateDeserializer.java

    public class DateDeserializer<T extends Date> implements JsonDeserializer<T> {
    
        private static final String TAG = DateDeserializer.class.getSimpleName();
    
        private final SimpleDateFormat mSimpleDateFormat;
        private final Class<T> mClazz;
    
        public DateDeserializer(SimpleDateFormat simpleDateFormat, Class<T> clazz) {
            mSimpleDateFormat = simpleDateFormat;
            mClazz = clazz;
        }
    
        @Override
        public T deserialize(JsonElement element, Type arg1, JsonDeserializationContext context) throws JsonParseException {
            String dateString = element.getAsString();
            try {
                T date = mClazz.newInstance();
                date.setTime(mSimpleDateFormat.parse(dateString).getTime());
                return date;
            } catch (InstantiationException e) {
                throw new JsonParseException(e.getMessage(), e);
            } catch (IllegalAccessException e) {
                throw new JsonParseException(e.getMessage(), e);
            } catch (ParseException e) {
                throw new JsonParseException(e.getMessage(), e);
            }
        }
    }
    

    然后将不同的格式注册为...

    sGson = new GsonBuilder()
                        .registerTypeAdapter(Event.EventDateTime.class,
                                new DateDeserializer<Event.EventDateTime>(
                                        Event.EventDateTime.DATE_FORMAT, Event.EventDateTime.class))
                        .registerTypeAdapter(Event.StartEndDateTime.class,
                                new DateDeserializer<Event.StartEndDateTime>(
                                        Event.StartEndDateTime.DATE_FORMAT, Event.StartEndDateTime.class))
                        .registerTypeAdapter(Event.SimpleDate.class,
                                new DateDeserializer<Event.SimpleDate>(
                                        Event.SimpleDate.DATE_FORMAT, Event.SimpleDate.class))
                        .create();
    

    然后将每种格式映射到一个类...

    public class Event {
    
        @SerializedName("created")
        private EventDateTime mCreated;
    
        //@SerializedName("updated")
        private EventDateTime mUpdated;
    
        ...
    
        @SerializedName("start")
        private ConditionalDateTime mStart;
    
        @SerializedName("end")
        private ConditionalDateTime mEnd;
    
        public static class ConditionalDateTime {
            @SerializedName("dateTime")
            private StartEndDateTime mDateTime;
    
            @SerializedName("date")
            private SimpleDate mDate;
    
            public SimpleDate getDate() {
                return mDate;
            }
    
            public StartEndDateTime getDateTime() {
                return mDateTime;
            }
    
            /**
             * If it is an all day event then only date is populated (not DateTime)
             * @return
             */
            public boolean isAllDayEvent() {
                return mDate != null;
            }
        }
    
        public static class EventDateTime extends Date {
            public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        }
    
        public static class StartEndDateTime extends Date {
            public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ");
        }
    
        public static class SimpleDate extends java.util.Date {
            public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
        }
    }
    

    【讨论】:

    • 非常好的解决方案,而且肯定更具扩展性。
    • 我非常喜欢这个,但我想知道 SimpleDateFormats 和线程安全是否存在问题。如果是这样,也许最简单的方法是存储格式字符串,并在每次调用 DateDeserializer.deserialize() 时创建一个新的 SimpleDateFormat?
    • 哦,我喜欢这个!这真的很干净,就像一个魅力,非常感谢!
    • 正如@BradTofel 提到的,这里确实存在一些线程安全问题,正如我在解析包含大约 300 个日期的 JSON 时发现的那样。存储日期格式字符串并为每个(反)序列化创建一个新的SimpleDateFormat 解决了这个问题!
    【解决方案3】:

    需要自定义反序列化。一个不错的解决方案是使用 Apache Commons DateUtil,它可以同时处理多种日期格式。此外,JodaTime API 可能具有类似的功能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-23
      相关资源
      最近更新 更多