Skip to content

Commit 429aa4e

Browse files
committed
Kotlin: Idioms
1 parent 47eee12 commit 429aa4e

11 files changed

Lines changed: 201 additions & 34 deletions

File tree

jooby/src/main/java/io/jooby/EnvironmentOptions.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ public List<String> getActiveNames() {
5757
return this;
5858
}
5959

60+
/**
61+
* Set active environment names.
62+
*
63+
* @param activeNames Active environment names.
64+
* @return This options.
65+
*/
66+
public @Nonnull EnvironmentOptions setActiveNames(@Nonnull List<String> activeNames) {
67+
this.activeNames = activeNames.toArray(new String[activeNames.size()]);
68+
return this;
69+
}
70+
6071
private static @Nonnull List<String> defaultEnvironmentNames() {
6172
return Arrays.asList(
6273
System.getProperty(ENV, System.getenv().getOrDefault(ENV, "dev")).split("\\s*,\\s*"));

jooby/src/main/java/io/jooby/RouterOptions.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public class RouterOptions {
3838
*
3939
* @return Whenever do case-sensitive matching.
4040
*/
41-
public boolean isIgnoreCase() {
41+
public boolean getIgnoreCase() {
4242
return ignoreCase;
4343
}
4444

@@ -58,7 +58,7 @@ public RouterOptions setIgnoreCase(boolean ignoreCase) {
5858
*
5959
* @return Whenever trailing slash on path pattern is ignored.
6060
*/
61-
public boolean isIgnoreTrailingSlash() {
61+
public boolean getIgnoreTrailingSlash() {
6262
return ignoreTrailingSlash;
6363
}
6464

jooby/src/main/java/io/jooby/ServerOptions.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ public int getWorkerThreads(int defaultWorkerThreads) {
262262
*
263263
* @return True if gzip is enabled.
264264
*/
265-
public boolean isGzip() {
265+
public boolean getGzip() {
266266
return gzip;
267267
}
268268

@@ -284,7 +284,7 @@ public boolean isGzip() {
284284
* @return True if default headers: <code>Date</code>, <code>Content-Type</code> and
285285
* <code>Server</code> are enabled.
286286
*/
287-
public boolean isDefaultHeaders() {
287+
public boolean getDefaultHeaders() {
288288
return defaultHeaders;
289289
}
290290

jooby/src/main/java/io/jooby/internal/RouterImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,8 @@ private Route defineRoute(@Nonnull String method, @Nonnull String pattern,
412412
route.setEncoder(renderer);
413413
}
414414
// router options
415-
if (options.isIgnoreCase() || options.isIgnoreTrailingSlash()) {
416-
chi = chi.options(options.isIgnoreCase(), options.isIgnoreTrailingSlash());
415+
if (options.getIgnoreCase() || options.getIgnoreTrailingSlash()) {
416+
chi = chi.options(options.getIgnoreCase(), options.getIgnoreTrailingSlash());
417417
}
418418
// unwrap executor
419419
worker = ((ForwardingExecutor) worker).executor;

jooby/src/main/kotlin/io/jooby/Kooby.kt

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@ package io.jooby
77

88
import kotlinx.coroutines.CoroutineStart
99
import kotlin.reflect.KClass
10+
import kotlin.reflect.KProperty
1011

1112
@DslMarker
1213
@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPEALIAS, AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
1314
annotation class RouterDsl
1415

16+
@DslMarker
17+
@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPEALIAS, AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
18+
annotation class OptionsDsl
19+
1520
/** Registry: */
1621
inline fun <reified T> Registry.require(): T {
1722
return this.require(T::class.java)
@@ -33,6 +38,10 @@ fun <T : Any> ServiceRegistry.get(klass: KClass<T>): T {
3338
return this.get(klass.java)
3439
}
3540

41+
fun <T : Any> ServiceRegistry.getOrNull(klass: KClass<T>): T? {
42+
return this.getOrNull(klass.java)
43+
}
44+
3645
fun <T : Any> ServiceRegistry.put(klass: KClass<T>, service: T): T? {
3746
return this.put(klass.java, service)
3847
}
@@ -42,6 +51,11 @@ fun <T : Any> ServiceRegistry.putIfAbsent(klass: KClass<T>, service: T): T? {
4251
}
4352

4453
/** Value: */
54+
55+
inline operator fun <reified T> Value.getValue(thisRef: Any?, property: KProperty<*>): T {
56+
return this.get(property.name).to(object : Reified<T>() {})
57+
}
58+
4559
operator fun Value.get(name: String): Value {
4660
return this.get(name)
4761
}
@@ -50,41 +64,57 @@ operator fun Value.get(index: Int): Value {
5064
return this.get(index)
5165
}
5266

53-
inline fun <reified T> Value.to(): T {
67+
inline fun <reified T> Value.to(): T? {
5468
return this.to(object : Reified<T>() {})
5569
}
5670

71+
infix fun <T : Any> Value.to(type: KClass<T>): T? {
72+
return this.to(type.java)
73+
}
74+
5775
/** Context: */
76+
val Context.query: QueryString
77+
get() = this.query()
78+
5879
inline fun <reified T> Context.query(): T {
59-
val reified = object : Reified<T>() {}
60-
return this.query(reified)
80+
return this.query(object : Reified<T>() {})
6181
}
6282

83+
val Context.form: Formdata
84+
get() = this.form()
85+
6386
inline fun <reified T> Context.form(): T {
6487
return this.form(object : Reified<T>() {})
6588
}
6689

90+
val Context.multipart: Multipart
91+
get() = this.multipart()
92+
6793
inline fun <reified T> Context.multipart(): T {
6894
return this.multipart(object : Reified<T>() {})
6995
}
7096

97+
val Context.body: Body
98+
get() = this.body()
99+
71100
inline fun <reified T> Context.body(): T {
72101
return this.body(object : Reified<T>() {})
73102
}
74103

75104
/** Kooby: */
76-
77105
open class Kooby constructor() : Jooby() {
78106

79107
constructor(init: Kooby.() -> Unit) : this() {
80108
this.init()
81109
}
82110

111+
@RouterDsl
83112
fun <T : Any> mvc(router: KClass<T>): Kooby {
84113
super.mvc(router.java)
85114
return this
86115
}
87116

117+
@RouterDsl
88118
fun <T : Any> mvc(router: KClass<T>, provider: () -> T): Kooby {
89119
super.mvc(router.java, provider)
90120
return this
@@ -205,56 +235,55 @@ open class Kooby constructor() : Jooby() {
205235
return super.route(method, pattern) { ctx -> handler(HandlerContext(ctx)) }.setHandle(handler)
206236
}
207237

238+
@OptionsDsl
208239
fun serverOptions(configurer: ServerOptions.() -> Unit): Kooby {
209240
val options = ServerOptions()
210241
configurer(options)
211242
setServerOptions(options)
212243
return this
213244
}
214245

246+
@OptionsDsl
215247
fun routerOptions(configurer: RouterOptions.() -> Unit): Kooby {
216248
val options = RouterOptions()
217249
configurer(options)
218-
setRouterOptions(options)
250+
this.routerOptions = options
219251
return this
220252
}
221253

254+
@OptionsDsl
222255
fun environmentOptions(configurer: EnvironmentOptions.() -> Unit): Environment {
223256
val options = EnvironmentOptions()
224257
configurer(options)
225258
val env = Environment.loadEnvironment(options)
226-
setEnvironment(env)
259+
this.environment = env
227260
return env
228261
}
229262
}
230263

231264
/** cors: */
232-
@RouterDsl
265+
@OptionsDsl
233266
fun cors(init: Cors.() -> Unit): Cors {
234267
val cors = Cors()
235268
cors.init()
236269
return cors
237270
}
238271

239272
/** runApp: */
240-
@RouterDsl
241273
fun runApp(args: Array<String>, mode: ExecutionMode, init: Kooby.() -> Unit) {
242274
configurePackage(init)
243275
Jooby.runApp(args, mode, fun() = Kooby(init))
244276
}
245277

246-
@RouterDsl
247278
fun runApp(args: Array<String>, init: Kooby.() -> Unit) {
248279
configurePackage(init)
249280
Jooby.runApp(args, ExecutionMode.DEFAULT, fun() = Kooby(init))
250281
}
251282

252-
@RouterDsl
253283
fun <T : Jooby> runApp(args: Array<String>, application: KClass<T>) {
254284
runApp(args, ExecutionMode.DEFAULT, application)
255285
}
256286

257-
@RouterDsl
258287
fun <T : Jooby> runApp(args: Array<String>, mode: ExecutionMode, application: KClass<T>) {
259288
Jooby.runApp(args, mode, application.java)
260289
}

jooby/src/test/kotlin/apps/Apps.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
package apps
22

3-
import io.jooby.CorsHandler
43
import io.jooby.ExecutionMode
54
import io.jooby.Kooby
6-
import io.jooby.cors
75
import io.jooby.runApp
86
import kotlinx.coroutines.delay
97

108
/** Class version: */
119
class App : Kooby({
1210

13-
decorator(CorsHandler(cors {
14-
methods = listOf("GET", "POST", "PUT")
15-
}))
16-
1711
coroutine {
1812
get { "Hi Kotlin!" }
1913

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package io.jooby
2+
3+
import kotlinx.coroutines.delay
4+
import java.nio.file.Paths
5+
import java.time.Duration
6+
7+
/**
8+
* Kotlin DLS in action, this class does nothing but we need it to make sure Kotlin version
9+
* compiles sucessfully.
10+
*/
11+
class Idioms : Kooby({
12+
13+
/** Services: */
14+
val s = require<Jooby>()
15+
println(s)
16+
17+
val named = require<Jooby>("name")
18+
println(named)
19+
20+
val sklass = require(Jooby::class)
21+
println(sklass)
22+
23+
val sklassname = require(Jooby::class, "name")
24+
println(sklassname)
25+
26+
val j1 = services.get(Jooby::class)
27+
println(j1)
28+
29+
val j2 = services.getOrNull(Jooby::class)
30+
println(j2)
31+
32+
/** Options: */
33+
serverOptions {
34+
bufferSize = 8194
35+
directBuffers = true
36+
ioThreads = 8
37+
gzip = true
38+
defaultHeaders = false
39+
maxRequestSize = 8000
40+
port = 8080
41+
server = "server"
42+
singleLoop = true
43+
workerThreads = 99
44+
}
45+
46+
routerOptions {
47+
this.ignoreCase = true
48+
this.ignoreTrailingSlash = true
49+
}
50+
51+
environmentOptions {
52+
this.activeNames = listOf("foo")
53+
this.basedir = Paths.get(".").toString()
54+
this.filename = "myfile"
55+
}
56+
57+
val cors = cors {
58+
this.exposedHeaders = listOf("f")
59+
this.headers = listOf("d")
60+
this.maxAge = Duration.ZERO
61+
this.methods = listOf("GET")
62+
this.origin = listOf("*")
63+
this.useCredentials = true
64+
}
65+
println(cors)
66+
67+
/** Value DSL: */
68+
get("/") {
69+
val query = ctx.query()
70+
val name: String by ctx.query
71+
val n1 = query["name"].value()
72+
val n2 = query[0].value()
73+
val n3 = query.to<Int>()
74+
val n4 = ctx.query["name"] to Int::class
75+
val n5 = ctx.form("name") to String::class
76+
val n6 = query.to(Int::class)
77+
78+
println(n1 + n2 + n3 + n4 + n5 + name + n6)
79+
ctx
80+
}
81+
82+
/** Router DSL: */
83+
before {
84+
ctx.path()
85+
}
86+
after {
87+
ctx.pathString()
88+
}
89+
decorator {
90+
next.apply(ctx)
91+
}
92+
get("/") {
93+
ctx.path()
94+
}
95+
post("/") {
96+
ctx.path()
97+
}
98+
put("/") {
99+
ctx.path()
100+
}
101+
patch("/") {
102+
ctx.path()
103+
}
104+
delete("/") {
105+
ctx.path()
106+
}
107+
options("/") {
108+
ctx.path()
109+
}
110+
trace("/") {
111+
ctx.path()
112+
}
113+
// mvc
114+
mvc(IdiomsController::class)
115+
116+
mvc(IdiomsController::class, ::IdiomsController)
117+
118+
/** Coroutine: */
119+
coroutine {
120+
get { "Hi Kotlin!" }
121+
122+
get("/suspend") {
123+
delay(100)
124+
"Hi Coroutine"
125+
}
126+
127+
get("/ctx-access") {
128+
ctx.pathString()
129+
}
130+
}
131+
})
132+
133+
class IdiomsController {}

0 commit comments

Comments
 (0)