Exploring the Scala Macro System for Compile Time Model-Based Generation of Statically Type-Safe REST Services
Filipe R. R. Oliveira
ei10038@fe.up.pt July 20, 2015
Supervisor Hugo Sereno Ferreira Co-supervisor Tiago Boldt Sousa
Exploring the Scala Macro System for Compile Time Model-Based - - PowerPoint PPT Presentation
Exploring the Scala Macro System for Compile Time Model-Based Generation of Statically Type-Safe REST Services Filipe R. R. Oliveira ei10038@fe.up.pt July 20, 2015 Supervisor Hugo Sereno Ferreira Co-supervisor Tiago Boldt Sousa Context
ei10038@fe.up.pt July 20, 2015
Supervisor Hugo Sereno Ferreira Co-supervisor Tiago Boldt Sousa
2
3
4
Resource A GET POST ... Resource B GET POST ...
5
Resource A GET POST ... Resource B GET POST ...
6
7
8
9
10
11
printf("Hello, %s!", "World") print("Hello, World!")
12
printf("Hello, %s!", "World") print("Hello, World!")
@json case class Category(name: String, description: String) case class Category(name: String, description: String) { def toJson: String = "{" + "name:" + name + "," + "description:" + description + "}" }
13
14
15
16
metamorphic { host = "111.111.111.111" // default "localhost" port = 9000 // default 8080 databases.default.name = "file.db" }
17
18
@entity class Category { def name = StringField() def description = StringField() }
19
@entity class Category { def name = StringField() def description = StringField() }
20
@entity class Category { def name = StringField() def description = StringField() } Entity("Category", List( Property("name", String, …), Property("description", String, …) )
21
@entity class Category { def name = StringField() def description = StringField() } Entity("Category", List( Property("name", String, …), Property("description", String, …) )
22
@entity class Category { def name = StringField() def description = StringField() } Entity("Category", List( Property("name", String, …), Property("description", String, …) )
23
Entity("Category", List( Property("name", String, …), Property("description", String, …) )
24
Entity("Category", List( Property("name", String, …), Property("description", String, …) ) Application( Service("CategoryService", List( Operation(Get, Path("categories", …), …), Operation(Post, Path("categories", …), …), … ) )
25
Entity("Category", List( Property("name", String, …), Property("description", String, …) ) Application( Service("CategoryService", List( Operation(Get, Path("categories", …), …), Operation(Post, Path("categories", …), …), … ) )
26
Entity("Category", List( Property("name", String, …), Property("description", String, …) ) Application( Service("CategoryService", List( Operation(Get, Path("categories", …), …), Operation(Post, Path("categories", …), …), … ) )
27
Application( Service("CategoryService", List( Operation(Get, Path("categories", …), …), Operation(Post, Path("categories", …), …), … ) )
28
Application( Service("CategoryService", List( Operation(Get, Path("categories", …), …), Operation(Post, Path("categories", …), …), … ) )
case class Category( id: Option[Int], name: String, description: String ) // Repository[Category] // CategoryService }
29
case class Category( id: Option[Int], name: String, description: String ) // Repository[Category] // CategoryService }
30
case class Category( id: Option[Int], name: String, description: String ) // Repository[Category] // CategoryService } POST http://localhost:8080/categories/ GET http://localhost:8080/categories/ PUT http://localhost:8080/categories/1/ DELETE http://localhost:8080/categories/1/ GET http://localhost:8080/categories/1/ { "id": 1, "name": "Cameras", "description": "High quality cameras." }
31
import metamorphic.dsl._ @app object RESTApp { @entity class Category { def name = StringField() def description = StringField() } class CategoryService extends EntityService[Category] { def create(category: Category) = { if (category.name.length < 5) Response("Name is too short.", BadRequest) else super.create(category) } } }
32
33
34
35
36
37
38
Framework Create GetAll Get Replace Delete Sum LoopBack 1 | 1 | 1 3 | 2 | 1 1 | 1 | 1 2 | 2 | 2 1 | 1 | 1 21 Metamorphic Async 2 | 2 | 2 1 | 1 | 2 3 | 2 | 2 . 1 | 1 | 1 . 2 | 2 | 2 26 Sails 3 | 3 | 6 2 | 6 | 4 2 | 3 | 3 3 | 3 | 6 3 | 3 | 5 55 Django REST 3.4 5 | 5 | 4 5 | 4 | 5 6 | 5 | 5 5 | 4 | 3 4 | 4 | 4 68 Django REST 4 | 4 | 3 6 | 5 | 6 5 | 6 | 6 4 | 5 | 4 5 | 5 | 3 71 Metamorphic 6 | 6 | 5 4 | 3 | 3 4 | 4 | 4 6 | 6 | 5 6 | 6 | 6 74 Eve* 1 | 1 | 1 4 | 3 | 2 4 | 3 | 3 1 | 1 | 2 3 | 3 | 3 35
39
40
sync
41
42
43
Functionality
Modeling 0.043 0.200 Creation of services 0.014 0.014 Customization 0.014 0.100
44
45
Measurement Round
Task 1: Modeling 1 11.44 03.11 20.13 09.18 08.69 43.2% 2 07.94 01.48 08.81 03.06 00.87 09.9% Task 2: Services 1 08.31 06.46 22.94 13.73 14.63 63.8% 2 10.69 05.76 17.25 01.49 06.56 38.0% Task 3: Customization 1 05.06 02.12 03.92 02.67
2 05.31 01.91 03.44 00.97
Total 1 45.81 08.19 70.56 12.14 24.75 35.1% 2 31.50 01.86 51.38 08.29 19.88 38.7%
46
Measurement Round
# Compile-time errors 1 02.8 2.06 01.5 1.29 2 04.3 1.71 00.3 0.50 # Runtime errors 1 00.0 . 0.00 05.8 4.99 2 00.3 . 0.50 05.5 1.73
47
48
EPFL, Team Member of Scala Macros
16 upvotes (100%) reddit.com/user/frroliveira/ 31 stars github.com/frroliveira/metamorphic
github.com/pathikrit
github.com/Daxten
def printf(format: String, params: Any*): Unit = macro impl def impl(c: Context)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] = { //... c.Expr[Unit](q"print($result)") }
printf("Hello, %s!", "World")
50
class serializable extends StaticAnnotation { def macroTransform(annottees: Any*): Any = macro Implementation.json } class Implementation(val context: Context) { def json(annottees: c.Expr[Any]*): c.Expr[Any] = ??? }
@json case class Category(name: String, description: String)
51
52
53
54