2013-02-13 5 views
3

При сериализации следующего класса case элемент val не включен. Почему это, и могу ли я включить его?Как я могу сериализовать элемент val в Json

case class Asset(id: Option[Int], description: Option[String]= None) { 
    val url = "images/" + id.toString+".png" 
} 

Обновление: Добавлена ​​Json библиотека, и спецификация/предполагаемое использование URL "собственности".

Я использую библиотеку Json, поставляемую с Play 2.1/Scala 2.10.

На самом деле свойство url предназначено для функции, которая будет искать алгоритм преобразования в соответствии с конфигурацией, например, изображение может быть доступно локально или доступно с внешнего хоста.

ответ

2

Хотя вы sould действительно указать, какие JSON сериализации библиотеки вы используете, это в значительной степени гарантирует, что только делает следующее будет работать:

case class Asset(id: Option[Int], description: Option[String]= None, url = "images/" + id.toString+".png") 

Учитывая, что url имеет значение по умолчанию в любом случае, превращая его в параметр не будет отрицательно влиять на ваш код (вы все равно можете сделать Asset(None) на примере, как и раньше). Единственным недостатком является то, что теперь клиентский код может создать экземпляр Asset с другим значением для url, что может и не быть тем, что вы хотите.

Если это так, вам, вероятно, потребуется создать пользовательский формат json для вашего класса Asset, но, не зная, какую библиотеку сериализации вы используете, я не могу больше помочь в этом отношении.


UPDATE:

Оп, я полностью пропустил тот факт, что значение по умолчанию для url зависит от другого параметра (id) (благодаря @Kristian Домагало для замечать). Таким образом, мой вышеприведенный фрагмент не компилируется. Одно простое решение поставить url во втором списке параметров, как предложено @Kristian Домагала:

case class Asset(id:Option[Int],description:Option[String]=None)(val url:String = "images/" + id.toString+".png") 

Но это не может быть идеальным, как это изменило семантику равенства в Asset (url не учитывается больше при сравнении экземпляры), а также изменяет синтаксис построения: когда явно указывается значение url, вам нужно сделать что-то вроде Asset(Some(123))("gfx/myImage.png") вместо примера Asset(Some(123), url="gfx/myImage.png"). Если вы можете жить с этими минусами, это, безусловно, самое простое решение.

В противном случае, есть другая работа вокруг: мы можем переопределить Asset.apply ourselve (вручную):

case class AssetImpl(val id: Option[Int], val description: Option[String], val url: Option[String]) { 
    override def productPrefix = "Asset" 
} 
type Asset = AssetImpl 
object Asset { 
    def apply(id: Option[Int], description: Option[String] = None, url: Option[String] = None) = { 
    new Asset(id, description, url.orElse(id.map("images/" + _ + ".png"))) 
    } 
} 

Как вы можете видеть, что я превратил url в Option со значением по умолчанию None (избегая предыдущее ошибка компиляции, поскольку она больше не зависит от id) и в def apply... Я создаю экземпляр Asset со значением по умолчанию для url (здесь я фактически получаю значение id) id.map("images/" + _ + ".png").

Остальное в основном просто шум, чтобы иметь возможность переопределить Asset.apply: выясняется, что на самом деле вы не можете переопределить фабрику класса case (вы можете добавлять только отдельные перегрузки). Поэтому я переименовал класс как AssetImpl, добавил псевдоним типа, чтобы никто не заметил (;-)), и создал мой собственный объект Asset, где я определяю метод apply (который больше не конфликтует с автогенерированным apply, потому что это один находится в отдельном объекте AssetImpl. Я мог бы просто превратить Asset в стандартный класс (класс без case), но тогда мне нужно было бы переопределить equals и hashCode, который я нахожу более раздражающим, учитывая, что он должен поддерживаться при добавлении/удалении поля для класса.

+0

Это не компилируется. Чтобы ссылаться на 'id',' url' нужно было бы объявить во второй группе параметров. Сначала я отклонил ответ, считая, что вторая группа параметров не будет быть выбранным u p через библиотеки сериализации, но оказывается, что Джеркссон действительно сериализует его. Полное объявление должно быть «case class Asset (id: Option [Int]», описание: Option [String] = None) (val url: String = "images /" + id.toString + ".png") '. Наверное, я не думаю, что значение «url» будет тем, что ожидается, учитывая реализацию «Option.toString». –

+0

Спасибо, что указали это, я полностью пропустил зависимость 'url'->' id'. Я обновил свой ответ. –

+0

Спасибо, что ответили. На самом деле я переместил вычисление url вне класса Asset. Я не уверен, что это правильно, чтобы принять ответ, который я не проверил сам. – rvange