Превратите строковую дату из json в объект Date с помощью Moshi

с Гсоном ты бы сделал это

Gson gson = new GsonBuilder()
            .setDateFormat("yyyy-MM-dd'T'HH:mm")
            .create();

и передайте его модификационному компоновщику, и Гсон создаст для вас объект Date. Есть ли способ заставить Moshi сделать это тоже в классе kotlin?


person tyczj    schedule 09.06.2017    source источник
comment
Будет github.com/square/moshi /tree/master/adapters/src/main/java/com/ делать то, что вы хотите? Этот адаптер опубликован в артефакте moshi-adapters.   -  person Eric Cochran    schedule 10.06.2017


Ответы (2)


Если вы хотите использовать стандартный адаптер даты ISO-8601/RFC 3339 (вероятно, так оно и есть), вы можете использовать встроенный адаптер:

Moshi moshi = new Moshi.Builder()
    .add(Date.class, new Rfc3339DateJsonAdapter().nullSafe())
    .build();

JsonAdapter<Date> dateAdapter = moshi.adapter(Date.class);
assertThat(dateAdapter.fromJson("\"1985-04-12T23:20:50.52Z\""))
    .isEqualTo(newDate(1985, 4, 12, 23, 20, 50, 520, 0));

Вам понадобится эта зависимость Maven, чтобы сделать эту работу:

<dependency>
  <groupId>com.squareup.moshi</groupId>
  <artifactId>moshi-adapters</artifactId>
  <version>1.5.0</version>
</dependency>

Если вы хотите использовать пользовательский формат (вероятно, вы этого не сделаете), есть еще код. Напишите метод, который принимает дату и форматирует ее в строку, и другой метод, который принимает строку и анализирует ее как дату.

Object customDateAdapter = new Object() {
  final DateFormat dateFormat;
  {
    dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm");
    dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
  }

  @ToJson synchronized String dateToJson(Date d) {
    return dateFormat.format(d);
  }

  @FromJson synchronized Date dateToJson(String s) throws ParseException {
    return dateFormat.parse(s);
  }
};

Moshi moshi = new Moshi.Builder()
    .add(customDateAdapter)
    .build();

JsonAdapter<Date> dateAdapter = moshi.adapter(Date.class);
assertThat(dateAdapter.fromJson("\"1985-04-12T23:20\""))
    .isEqualTo(newDate(1985, 4, 12, 23, 20, 0, 0, 0));

Вы должны помнить об использовании synchronized, потому что SimpleDateFormat не является потокобезопасным. Также вам необходимо настроить часовой пояс для SimpleDateFormat.

person Jesse Wilson    schedule 10.06.2017
comment
Спасибо за ответ. :) Вот зависимости Gradle для удобства: implementation("com.squareup.moshi:moshi:1.8.0") implementation("com.squareup.moshi:moshi-adapters:1.8.0") - person Filip Savic; 28.06.2019

В kotlin вы можете расширить класс JsonAdapter и создать свой собственный адаптер:

class CustomDateAdapter : JsonAdapter<Date>() {
    private val dateFormat = SimpleDateFormat(SERVER_FORMAT, Locale.getDefault())

    @FromJson
    override fun fromJson(reader: JsonReader): Date? {
        return try {
            val dateAsString = reader.nextString()
            synchronized(dateFormat) {
                dateFormat.parse(dateAsString)
            }
        } catch (e: Exception) {
            null
        }
    }

    @ToJson
    override fun toJson(writer: JsonWriter, value: Date?) {
        if (value != null) {
            synchronized(dateFormat) {
                writer.value(value.toString())
            }
        }
    }

    companion object {
        const val SERVER_FORMAT = ("yyyy-MM-dd'T'HH:mm") // define your server format here
    }
}

Затем при инициализации Retrofit вы можете установить адаптер с помощью Moshi.Builder, выполнив:

 private val moshiBuilder = Moshi.Builder().add(CustomDateAdapter()) // Your custom date adapter here

        val service: ApiService by lazy {
            val loggingInterceptor = HttpLoggingInterceptor()
            loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY

            val httpClient = OkHttpClient.Builder()
                .addInterceptor(loggingInterceptor)
                .build()

            val retrofit = Retrofit.Builder()
                .baseUrl(BuildConfig.API_URL)
                .client(httpClient)
                .addConverterFactory(MoshiConverterFactory.create(moshiBuilder.build())) // And don`t forget to add moshi class when creating MoshiConverterFactory 
                .addCallAdapterFactory(CoroutineCallAdapterFactory())
                .build()

            retrofit.create(ApiService::class.java)
        }
person Nicola Gallazzi    schedule 08.07.2019
comment
Здравствуйте, спасибо за ответ, он мне действительно очень помог! Меня интересует одно: когда именно работает toJson? fromJson работает при извлечении свойства и возвращает Date, однако я не могу манипулировать этим Date в соответствии с новым форматом. У меня есть эти форматы; ``` private const val SERVER_DATE_FORMAT = yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z' private const val APP_DATE_FORMAT = yyyy-MM-dd ``` И этот блок кода не работает ``` @ToJson переопределить fun toJson (автор: JsonWriter, значение: Дата?) { Writer.value (appFormatter.format (значение!!)) } ``` - person nuhkoca; 14.10.2019
comment
toJson полезен для сериализации вашего класса POJO в формате json. Притворитесь, что вам нужно создать документ json из вашего объекта, в этом случае вам нужно добавить сериализатор в ваш сборщик моши. - person Nicola Gallazzi; 14.10.2019