Заменить поля URL Ури Джексоном - PullRequest
1 голос
/ 06 марта 2020

У меня есть несколько объектов с URL-адресами в полях, например, таких как:

class A {

    val url1 : URL
    val url2 : URL
    val urls : ArrayList<URL>

}

Я хотел бы заменить URL-адреса на Uri, но я использую Jackson и SQLite для сериализации объектов и сохранения их в БД , Поэтому, если я изменяю тип, я не могу получить сохраненные объекты.

Итак, я реализовал пользовательскую десериализацию следующим образом:

class UriDeserializer : StdDeserializer<Uri>(Uri::class.java) {

    override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): Uri {

        return Uri.parse(p?.valueAsString)
    }

}

class UriArrayDeserializer : StdDeserializer<ArrayList<Uri>>(ArrayList::class.java) {

    override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): ArrayList<Uri> {

        val uriArray = arrayListOf<Uri>()

        p?.nextToken()
        while (p?.currentToken != JsonToken.END_ARRAY) {

            val uri = Uri.parse(p?.text)
            uriArray.add(uri)

            p?.nextToken()
        }

        return uriArray
    }


}

И затем я добавил UriDeserializer для полей в моем классе:

class A {

    @JsonDeserialize(using = UriDeserializer::class)
    val url1 : Uri

    @JsonDeserialize(using = UriDeserializer::class)
    val url2 : Uri

    @JsonDeserialize(using = UriArrayDeserializer::class)
    val urls : ArrayList<Uri>

}

С помощью этого кода я могу десериализовать свои старые объекты, но теперь я не могу сериализовать новые, я получаю эту ошибку:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: com.package.A["url2"]->android.net.Uri$StringUri["canonicalUri"])

должны реализовать Custom Serialises тоже? Может быть, есть самый простой способ заменить URL на Uri?

РЕШЕНИЕ

Благодаря проверенному ответу я нашел решение своей проблемы: поэтому я использовал интерфейс MixIn с Custom Serializer и Deserializer.

@JsonSerialize(using = UriSerializer::class)
@JsonDeserialize(using = UriDeserializer::class)
interface UriMixIn

class UriDeserializer : StdDeserializer<Uri>(Uri::class.java) {

    override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): Uri {
        return Uri.parse(p?.valueAsString)
    }
}

class UriSerializer : StdSerializer<Uri>(Uri::class.java) {

    override fun serialize(value: Uri?, gen: JsonGenerator?, provider: SerializerProvider?) {
        gen?.writeString(value?.toString())
    }
}

Затем я добавил UriMixIn везде, где это необходимо, например:

val jackson = jacksonObjectMapper()
jackson.addMixIn(Uri::class.java, UriMixIn::class.java)

Это решение работает как шарм! Большое спасибо за вашу помощь, хорошего дня!

1 Ответ

2 голосов
/ 07 марта 2020

Вы можете реализовать пользовательский сериализатор или использовать функцию MixIn.

Чтобы понять почему, нам нужно посмотреть, как реализован класс android. net .Uri . Мы можем проверить источники в Android Googlesource . Беглый взгляд, и мы заметили, что метод parse возвращает StringUri объект:

public static Uri parse(String uriString) {
    return new StringUri(uriString);
}

Во внутренней документации упоминается:

Этот класс стремится сделать как можно меньше фронтальная работа по возможности. Для этого мы меняем реализацию в зависимости от того, что пользователь передает. Например, у нас есть одна реализация, если пользователь передает строку URI (StringUri), и другую, если пользователь передает отдельные компоненты (OpaqueUri)

Давайте проанализируем дальше. StringUri - это private static class, который не похож на обычный POJO. С другой стороны, поле canonicalUri, с которым у вас возникла проблема, возвращает this в случае, если Uri построено из String, поэтому по этой причине нам нужен пользовательский сериализатор или мы используем MixIn Feature . может игнорировать это field/getter.

Это очень распространенная проблема, когда Jackson используется для serialise не обычных POJO объектов. Подобные вопросы:

  1. Почему исключение отображения Джексона JSON при сериализации / десериализации типа геометрии
  2. Сериализация / десериализация исключений без трассировки стека с использованием Джексона
  3. Есть ли в org.kohsuke.github встроенный механизм для сериализации объектов GHRepository в JSON?
  4. Сериализация и десериализация Джексона / Гсона Свойства JavaFX для json
  5. Java InvalidDefinitionException при сериализации объекта с привязкой данных Джексона

Некоторые примеры использования MixIn:

  1. Заставить сериализатор Джексона переопределить указанные c пропущенные поля
  2. Пользовательский сериализатор Джексона для указанного c типа в определенном классе
  3. Что такое эквивалентные настройки кода для аннотации @JSonIgnore?
  4. Анализ Джексона json с разверткой root, но без возможности установки @JsonRootName
* 10 78 * Кроме того, вы можете использовать функцию MixIn для регистрации serialiser/deserialiser глобально для типа Uri. В этом случае вам не нужно реализовывать UriArrayDeserializer класс.

См .:

  1. Джексон - Custom Serializer
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...