Статьи

Spring Data и Scala — могут ли они смешаться?


Некоторое время назад я приступил к задаче создания своего первого полноценного сервера Scala.
У меня было несколько решений, чтобы сделать:
  1. Магазин постоянства
  2. Постоянство Рамки
  3. Сервер приложений
Я долго смотрел на Монго, так что это был легкий выбор.

Использование NoSql в основном удалило все связанные с JPO фреймворки из таблицы (что я считаю хорошей вещью). Любовь к Spring, как и я, привела меня к выбору Spring-data в качестве основы постоянства. Казалось, что приличная поддержка Монго.

Для сервера приложений я решил положиться на прошлые успехи и использовал Jetty 9.

Настроить монго было довольно легко. Поскольку я использовал Scala, я хотел использовать case-классы в качестве моей модели. Цель состояла в том, чтобы использовать одни и те же объекты для моего слоя REST, используя модуль Jackson Scala, с одной стороны, и иметь возможность записать один и тот же тип объекта в моем хранилище постоянства. 

Spring-данные поначалу выглядели многообещающе. Я смог отправить Json, конвертировать в мою объектную модель прозрачно, используя следующий фрагмент XML:


    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper" ref="mapper"/>
            </bean>

        </mvc:message-converters>
    </mvc:annotation-driven>

Картограф был экземпляром  Джексона-модуля-Скала . Все идет нормально.

Я заметил одну странную вещь. Spring не знал, как сериализовать мои классы case из коробки (очевидно), поэтому он использовал универсальный сериализатор классов при записи моих объектов в Mongo. это работало достаточно хорошо, читая состояние обратно в объект, пока я не попал в showtopper.

Очевидно, классы case, которые содержали Scala ‘Option’, не были десериализованы должным образом. Например, рассмотрим следующий код:


myOptionField match {
      case Some(value) => do something
      case None => do something else
}

Оказывается, он никогда не доходил до сегмента «дела нет». Чтение моего состояния из Монго, хотя сериализовано как None, привело к нарушению вышесказанного Единственным обходным решением было сделать что-то вроде этого:

myOptionField match {
      case Some(value) => do something
      case _=> do something else
}

Это, конечно, было не оптимально.

Если этого было недостаточно, в некоторых случаях, когда нам приходилось использовать последовательные поля опций Scala, мы получали странные ошибки сериализации Json:

com.fasterxml.jackson.databind.JsonMappingException: (None,None) (of class scala.Tuple2)


Хммм. Я не чувствую себя комфортно с текущим состоянием …

Поскольку мой проект был молодым, мне повезло, что я смог изменить его. К счастью, у меня был изолированный db-слой, который позволил мне довольно легко вернуться к моему решению Persistence Framework.

Читая еще немного, я обнаружил, что у  Mongo есть официальный драйвер Scala  (как же я пропустил это?) Ницца. Но ждать. Начав реализовывать переход от Spring-Data к Casbah-драйверу Scala, быстро  выяснилось, что  я не могу передать свои кейс-классы в Scala-драйвер. Он использует только объекты MongoDB. О чувак. Действительно ли мне нужно создавать читателей и писателей для всех моих 20+ тематических классов? 

Ну нет.

Салат  на помощь. Наконец, аккуратное решение. Я могу легко конвертировать мои классы дел в монго и обратно, используя лаконичный и легко читаемый код:

  val mongodbConnetion = MongoConnection(host,port)
  val mydb = mongodbConnetion("mydb")
  mydb.writeConcern = WriteConcern.FsyncSafe
  val my-coll-db = mydb("my-coll-db")

//insert new document
my-coll-db.insert(grater[MyCaseClassObject].asDBObject(myObj))

Вот и все. Легко использовать. Легко читать. Учись писать.


Подводя итог, можно сказать, что данные Spring (как ни крути) не подходят для работы с Scala. К счастью, у нас есть хорошие альтернативы.