Scala külső könyvtárak

Kategória: Scala.

Számos külső könyvtár áll a Scala programozók rendelkezésére. Ne feledjük, hogy a Scala is JVM-re fordít, így lényegében használható a teljes Java könyvtárrendszer. A övetkező oldalak áttekintést nyújtanak a lehetőségekről.

Mindet megnézni képtelenség lenne; lássunk azért párat!

A külső könyvtárak használata

Akár parancssorban használjuk a Scala-t, akár fordítjuk, ahhoz, hogy használni tudjuk a külős könyvtárakat, a legegyszerűbb létrehozni egy build.sbt fájlt.

libraryDependencies += "[groupId]" %% "[artifactId]" % "[version]"

Parancssorból indítva most ne a scala-t indítsuk, hanem ezt:

sbt console

Ha mindent jól csináltunk, akkor automatikusan letölti a könyvtárakat, és azonnal használhatjuk. Fordításkor a már ismertetett build.sbt-be írjuk bele a függőségeket.

JSON

A JSON kezeléséhez a json4s-jackson könyvtárat használjuk. Hozzuk létre az alábbi build.sbt fájlt:

libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.6.0"

Indítsuk el a Scala parancssori értelmezőt: sbt console. Lássuk, hogyan tudjuk visszafejteni a JSON struktúrát Scala osztályokká:

import org.json4s._
import org.json4s.jackson.JsonMethods._

case class Person(name: String, age: Int)

implicit val formats = DefaultFormats
val jsValue = parse("""{"name":"John", "age": 28}""")
jsValue.extract[Person]

Ugyanezt ha fordítani szeretnénk, a következőképpen néz ki:

build.sbt:

name := "jsonexample"
version := "1.0"
scalaVersion := "2.12.7"
libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.6.0"

src/main/scala/JsonExample.scala:

import org.json4s._
import org.json4s.jackson.JsonMethods._

case class Person(name: String, age: Int)

object JsonExample {
  def main(args: Array[String]) = {
    implicit val formats = DefaultFormats
    val jsValue = parse("""{"name":"John", "age": 28}""")
    println(jsValue.extract[Person])
  }
}

Ez csak egy egyszerű példa a számos lehetőségből; ha használnunk kell, akkor részletesebben el kell benne mélyednünk, célszerűen ezen az oldalon: https://github.com/json4s/json4s.

Egységtesztelés

Ahogy a Java-nak sem része az egységtesztelés, a Scala esetén is külső könyvtárat kell ehhez használnunk. Adjuk a következő sort a build.sbt fájlhoz:

libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.8" % "test"

A forrást, amit tesztelni szeretnénk (src/main/scala/MyAdder.scala):

class MyAdder {
  def add(a: Int, b: Int) = a + b
}

Erre készítünk egységtesztet (src/test/scala/MyAdderTest.scala):

import org.scalatest.FlatSpec

class MyAdderTest extends FlatSpec {

  "My adder" should "return 5 when adding 2 and 3" in {
    val myAdder = new MyAdder
    val result = myAdder.add(2, 3)
    assert(result == 5)
  }

  it should "return 0 when adding -2 and 2" in {
    val myAdder = new MyAdder
    val result = myAdder.add(-2, 2)
    assert(result == 0)
  }

}

Futtatás:

sbt test

A futtatás lényeges eredménye:

[info] MyAdderTest:
[info] My adder
[info] - should return 5 when adding 2 and 3
[info] - should return 0 when adding -2 and 2
...
[info] All tests passed.

Némi magyarázat a fenti példához: a Scalatest egy rendkívül szerteágazó teszt keretrendszer. Első körben el kell döntenünk, hogy milyen stílust használunk. Ez lehet a Java-ban megszokott Junit4 is (org.scalatest.junit.AssertionsForJUnit), de a Scalaban inkább javasolt más megközelítés. Kezdetnek a Scalatest maga a FlatSpec-et javasolja, amelyben a fenti módon, szinte "emberi nyelven" tudjuk megadni az egységteszteket. Bővebb információt ezen az oldalon olvashatunk: http://www.scalatest.org/user_guide.

Adatbázis kapcsolat

A Scala-nak nincs saját adatbázis kapcsolat kezelője, a Java-s JDBC-t tudjuk használni erre a célra. Példaként a MySQL-t fogjuk használni, ehhez hozzuk létre a teszt adatbázist az adatbázisok oldalon leírtak alapján. Lássuk, hogyan tudunk ebből kiolvasni Scala-ban! Mindenekelőtt adjuk hozzá a megfelelő függőséget a build.sbt fájlhoz (ügyeljünk a megfelelő verzióra):

libraryDependencies += "mysql" % "mysql-connector-java" % "8.0.15"

Ügyeljünk a megfelelő verzióra; én belefutottam abba, hogy rossz verziót használtam, és furcsa hibaüzenettel állt le a program. Pl. itt tudjuk megnézni a pontos legfrissebb verziókat: https://mvnrepository.com/artifact/mysql/mysql-connector-java. Majd hozzuk létre meg a következő programot:

object JdbcExample {

  def main(args: Array[String]) = {
    Class.forName("com.mysql.cj.jdbc.Driver")
    val connection = java.sql.DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb", "csaba", "farago")
    val statement = connection.createStatement
    val rs = statement.executeQuery("SELECT name, age FROM person")
    while (rs.next()) {
      val name = rs.getString("name")
      val age = rs.getInt("age")
      println(name + " (" + age + ")")
    }
    connection.close()
  }

}

Ez egy rendkívül leegyszerűsített program, hibakezelés sincs benne. Ha mindent jól csináltunk lés lefuttatjuk a programot, akkor az eredmények az alábbinak kell lennie:

Sanyi (34)
Kata (32)
Pista (46)

Web kliens

Láthattunk hogy egyszerű HTTP GET lekérést standard Scala eszközzel is el tudjuk érni (scala.io.Source.fromURL()). A tapasztalatom szerint viszont már a legegyszerűbb esetben is hibába futhatunk, ill. ennél bonyolultabb esetekre (pl. HTTP POST) már nem igazán alkalmas. Célszerű a HTTP-hez külső könyvtárat használni.

Számos HTTP könyvtár létezik Scala-hoz, mi most a scalaj könyvtárat nézzük meg. Adjuk a build.sbt-hez az alábbi függőséget:

libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2"

Ekkor a legegyszerűbb HTTP GET kérés a következőképpen néz ki:

scalaj.http.Http("http://faragocsaba.hu").asString

Számos egyéb HTTP műveletet végre lehet hajtani. A részletekért javaslom a dokumentáció átolvasását (https://github.com/scalaj/scalaj-http) és a példaprogramokat (pl. https://github.com/scalaj/scalaj-http/blob/master/src/test/scala/scalaj/http/HttpBinTest.scala).

Web szerver

Web szerverként az Akka keretrendszert használhatjuk. Lássunk egy példát! A build.sbt fájlhoz adjuk hozzá a következő függőségeket:

libraryDependencies += "com.typesafe.akka" %% "akka-http" % "10.1.10"
libraryDependencies += "com.typesafe.akka" %% "akka-stream" % "2.5.23"

Majd készítsük el a következő kódot:

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import scala.io.StdIn

object WebServer {

  def main(args: Array[String]) {
    implicit val system = ActorSystem("my-system")
    implicit val materializer = ActorMaterializer()
    implicit val executionContext = system.dispatcher
    val route = path("greetings") {
        get {
          parameter("name") {name => complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "Hello, " + name + "!"))}
        }
      }
    val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
    println("Server online. Open a page like http://localhost:8080/greetings?name=Csaba for testing.\nPress RETURN to stop...")
    StdIn.readLine()
    bindingFuture
      .flatMap(_.unbind())
      .onComplete(_ => system.terminate())
  }

}

Indítsuk el. Ahogy a kódban is látható, nyissuk meg a http://localhost:8080/greetings?name=Csaba oldalt (a saját nevünket írjuk az URL-be). Ha mindent jól csináltunk, akkor megjelenik a Hello, Csaba! szöveg.

Ezzel is épp hogy csak a felszínt karcoltuk. A további részletekért használjuk a dokumentációt.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License