Programação, Scala

Compilando o plugin play-slick 0.5.1 com Scala 2.11.1 e SBT 0.13.5

Dando seguimento ao nosso post sobre a compilação do Slick 1.0.0 com Scala 2.11.1, é chegada a hora de integrar Slick novamente ao Play Framework 2.3.4.

Se tem curiosidade sobre por que estamos usando versões legadas de Slick nas versões atuais do Play, a resposta é apenas : custo e tempo para atualizar.

Temos muito código legado que utiliza Scalaquery e Slick 1.0 e, por ora, não podemos perder tempo com essa migração visto que a camada de interface com o BD está funcionando bem.

É o preço a pagar por versões que rompem radicalmente com versões anteriores. Houveram mudanças significativas do Play 2.2 para 2.3, bem como do Slick 1.0 para Slick 2.0. Conforme mencionado no primeiro post, tememos que essa tendência repita o desastre do Python 3.0 que, ao romper completamente com as versões anteriores da linguagem, gerou basicamente duas comunidades: uma do Python 2 e outra do Python 3. (Divisão essa que, já dura mais de 6 anos e não mostra fortes sinais de estar se fechando. Cursos universitários e cursos de treinamentos continuam a usar Python 2.7, para citar um exemplo, formando ainda mais profissionais na versão antiga da linguagem.)

O Slick 2 rompe com Slick 1, e o Play 2.3 trouxe mudanças significativas do Play 2.2, de forma que é preciso testar regressões e ter cuidado extra na hora de colocar o app em produção. Em um aplicativo no qual trabalhamos o plugin mailer do Play sofreu uma regressão sorrateira: o envio de emails falhava com um problema que não era detectado na compilação e nos testes. Esse problema foi ao ar, em ambiente de produção, pois testávamos o envio de emails porém não o recebimento dos mesmos. Resulta que centenas de mensagens deixaram de ser enviadas para clientes – os gerentes não ficam nada felizes com isso. Felizmente descobrimos em curto espaço de tempo e atualizamos o plugin para a versão compatível com Play 2.3.4(que utiliza o Typesafe Activator).

Compilando Play-Slick Plugin 0.5.1

O último plugin Play-Slick que suporta Slick 1.0 é a versão 0.5.1. Baixamos essa versão na página de releases do Github.

Editamos build.sbt e project/build.properties para atualizar as versões de Scala e SBT para 2.11.1 e 0.13.5 respectivamente.

Tentamos um primeiro sbt compile e obtemos o primeiro erro:

[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: UNRESOLVED DEPENDENCIES ::
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: com.typesafe.slick#slick_2.11;1.0.1: not found
[warn] ::::::::::::::::::::::::::::::::::::::::::::::

Obviamente os repositórios oficiais não terão nosso build personalizado. Pegamos então o JAR gerado no buld anterior, o colocamos em lib/(que precisa ser criado na raíz do projeto) e retiramos a linha do build.sbt que contém a dependência no Slick 1.0.1: "com.typesafe.slick" %% "slick" % "1.0.1". Agora que temos o arquivo slick_2.11.1-1.0.0.jar no diretório lib/, vamos tentar novamente o sbt compile.

Obtemos então 4 erros:

1)
[error] /root/scala/play-slick-0.5.1/src/main/scala/play/api/db/slick/DBAction.scala:42: in object DBAction, multiple overloaded alternatives of method transaction define default arguments.
[error] The members with defaults are defined in trait CurrentDBAction in package slick and trait PredicatedDBAction in package slick and trait PredicatedDBAction in package slick.
[error] object DBAction extends CurrentDBAction
[error]
^

2)

[error] /root/scala/play-slick-0.5.1/src/main/scala/play/api/db/slick/DBAction.scala:48: in trait CurrentDBAction, multiple overloaded alternatives of method transaction define default arguments.
[error] The members with defaults are defined in trait CurrentDBAction in package slick and trait PredicatedDBAction in package slick and trait PredicatedDBAction in package slick.
[error] trait CurrentDBAction extends PredicatedDBAction {
[error] ^

3)
[error] /root/scala/play-slick-0.5.1/src/main/scala/play/api/db/slick/DBAction.scala:107: in class DBAction, multiple overloaded alternatives of method transaction define default arguments.
[error] The members with defaults are defined in trait PredicatedDBAction in package slick and trait PredicatedDBAction in package slick.
[error] class DBAction(database: Database, minConnections: Int = 5, maxConnections: Int = 5, partitionCount: Int = 2, maxQueriesPerRequest: Int = 20) extends PredicatedDBAction {
[error] ^

4)

[error] /root/scala/play-slick-0.5.1/src/main/scala/play/api/db/slick/DBAction.scala:123: in trait PredicatedDBAction, multiple overloaded alternatives of method transaction define default arguments.
[error] trait PredicatedDBAction {
[error] ^

Vamos à batalha!

Erro 1)
[error] /root/scala/play-slick-0.5.1/src/main/scala/play/api/db/slick/DBAction.scala:42: in object DBAction, multiple overloaded alternatives of method transaction define default arguments.

Esse erro ocorre quando mais de uma versão de uma função usa parâmetros default. No caso:
def transaction[A](dbName: String, bodyParser: BodyParser[A] = anyContent)(requestHandler: DBSessionRequest[A] => SimpleResult)(implicit app: Application = null) = { ....

Vemos que bodyParser tem um valor padrão e app idem. O problema é o valor de app : ele precisa ser opcional ou no trait ou no objeto, mas não em ambos. Deve ser fruto da atualização da linguagem Scala que quebrou muita coisa do 2.10 para 2.11. A versão no trait é :

def transaction(requestHandler: DBSessionRequest[AnyContent] => SimpleResult)(implicit app: Application = null) = {

Por que deveríamos ter um valor concreto para o parâmetro de tipo Application em um trait? Primeiro: utilizar valores null em Scala não é recomendado. Segundo: traits não tem qualquer utilidade para valores concretos! Essa asserção deveria encontrar-se posteriormente, no código que implementa o trait. Vamos retirar essa salvaguarda de todos os métodos do trait (e rodar testes posteriormente). A assinatura de todos os métodos onde há …Application = null deve tornar-se apenas Application.

Por exemplo:
def transaction(requestHandler: DBSessionRequest[AnyContent] => SimpleResult)(implicit app: Application) = { ...

E voilà! [success] Total time: 18 s, completed Sep 4, 2014 11:34:56 AM. Resolvendo o problema nr 1, removemos também os entraves para a compilação do resto do código. Com um simples sbt package temos nosso JAR nos aguardando!

Conclusão

Compilamos o plugin Play-Slick 0.5.1 e Slick 1.0.0 para funcionar com Scala 2.11.1, obedecendo a lógica de Scala e todas as recomendações dos “Scala Issues” e documento “changes” que especificam o que mudou entre as versões 2.10 e 2.11 da linguagem.

Veja também: Compilando Slick 1.0.0

Standard