REST services
Rest server module
To start, we'll create a simple REST server module in our movies project. Normally this would not go in your Android project, but for convenience we'll add it here.
Use File > New Module > Java or Kotlin Library to create a module called restserver. Use
RunServer as the class name.
We'll use the Apache Jersey server for our simple REST server, so we'll add its libraries to the
version catalog. To make things a bit more convenient, we'll use the version catalog [bundles]
support, allowing us to define a single name to represent a set of libraries we're using together.
show in full file gradle/libs.versions.toml
[versions]
// ...
glance="1.1.1"
jetbrainsKotlinJvm = "2.0.21"
jersey="3.1.9"
activation="2.1.3"
[libraries]
jersey-grizzly2 = { group = "org.glassfish.jersey.containers", name = "jersey-container-grizzly2-http", version.ref = "jersey" }
jersey-jetty = { group = "org.glassfish.jersey.containers", name = "jersey-container-jetty-http", version.ref = "jersey" }
jersey-servlet = { group = "org.glassfish.jersey.containers", name = "jersey-container-servlet-core", version.ref = "jersey" }
jersey-jackson = { group = "org.glassfish.jersey.media", name = "jersey-media-json-jackson", version.ref = "jersey" }
jersey-server = { group = "org.glassfish.jersey.core", name = "jersey-server", version.ref = "jersey" }
jersey-hk2 = { group = "org.glassfish.jersey.inject", name = "jersey-hk2", version.ref = "jersey" }
activation = { group = "jakarta.activation", name = "jakarta.activation-api", version.ref = "activation" }
glance-appwidget = { group = "androidx.glance", name = "glance-appwidget", version.ref = "glance" }
glance-material3 = { group = "androidx.glance", name = "glance-material3", version.ref = "glance" }
// ...
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
[bundles]
server = [
"jersey-grizzly2",
"jersey-jetty",
"jersey-servlet",
"jersey-jackson",
"jersey-server",
"jersey-hk2",
"activation"
]
[plugins]
// ...
We add these to the new module's build.gradle.kts using the version catalog bundle.
To run the server, we need to add the application plugin. We don't need to add this plugin
to the version catalog as it's a standard part of the Gradle distribution. We specify the application
to run using mainClass
show in full file restserver/build.gradle.kts
plugins {
id("java-library")
alias(libs.plugins.jetbrains.kotlin.jvm)
application
}
// ...
}
dependencies {
implementation(libs.bundles.server)
}
kotlin {
// ...
}
application {
mainClass = "com.androidbyexample.compose.movies.restserver.RunServer"
}
To test that everything is set up ok to run, we'll add a simple main to our RunServer class
show in full file restserver/src/main/java/com/androidbyexample/compose/movies/restserver/RunServer.kt
// ...
class RunServer {
companion object {
@JvmStatic
fun main(args: Array<String>) {
println("It runs!")
}
}
}
and then we can run it via
./gradlew run
Note
Because we're running this on a Java Virtual Machine (JVM), the main class is expected to have
a public static void main(String[] args) method. TO accomplish this, we:
- Add a
companion objecttoRunServer. Any function defined inside it belongs to theRunServerclass, and you won't need an instance ofRunServerto execute it. - Add a
fun main(args: Array<String>)function inside thecompanion object - Mark the
mainfunction with the@JvmStaticannotation to define the function as a static method when run on the JVM.
All code changes
CHANGED: build.gradle.kts
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false
alias(libs.plugins.android.library) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.jetbrains.kotlin.jvm) apply false
}
CHANGED: gradle/libs.versions.toml
[versions]
agp = "8.7.3"
kotlin = "2.0.21"
coreKtx = "1.15.0"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
lifecycleRuntimeKtx = "2.8.7"
activityCompose = "1.9.3"
composeBom = "2024.12.01"
appcompat = "1.7.0"
material = "1.12.0"
room = "2.6.1"
ksp = "2.0.21-1.0.28"
compileSdk = "35"
targetSdk = "35"
minSdk = "24"
jvmTarget = "11"
javaVersion = "VERSION_11"
lifecycle-compose = "2.8.7"
icons-extended = "1.7.6"
glance="1.1.1"
jetbrainsKotlinJvm = "2.0.21"
jersey="3.1.9"
activation="2.1.3"
[libraries]
jersey-grizzly2 = { group = "org.glassfish.jersey.containers", name = "jersey-container-grizzly2-http", version.ref = "jersey" }
jersey-jetty = { group = "org.glassfish.jersey.containers", name = "jersey-container-jetty-http", version.ref = "jersey" }
jersey-servlet = { group = "org.glassfish.jersey.containers", name = "jersey-container-servlet-core", version.ref = "jersey" }
jersey-jackson = { group = "org.glassfish.jersey.media", name = "jersey-media-json-jackson", version.ref = "jersey" }
jersey-server = { group = "org.glassfish.jersey.core", name = "jersey-server", version.ref = "jersey" }
jersey-hk2 = { group = "org.glassfish.jersey.inject", name = "jersey-hk2", version.ref = "jersey" }
activation = { group = "jakarta.activation", name = "jakarta.activation-api", version.ref = "activation" }
glance-appwidget = { group = "androidx.glance", name = "glance-appwidget", version.ref = "glance" }
glance-material3 = { group = "androidx.glance", name = "glance-material3", version.ref = "glance" }
icons-extended = { group = "androidx.compose.material", name = "material-icons-extended-android", version.ref = "icons-extended"}
lifecycle-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle-compose" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
[bundles]
server = [
"jersey-grizzly2",
"jersey-jetty",
"jersey-servlet",
"jersey-jackson",
"jersey-server",
"jersey-hk2",
"activation"
]
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
android-library = { id = "com.android.library", version.ref = "agp" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
jetbrains-kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "jetbrainsKotlinJvm" }
ADDED: restserver/.gitignore
/build
ADDED: restserver/build.gradle.kts
plugins {
id("java-library")
alias(libs.plugins.jetbrains.kotlin.jvm)
application
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
dependencies {
implementation(libs.bundles.server)
}
kotlin {
compilerOptions {
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11
}
}
application {
mainClass = "com.androidbyexample.compose.movies.restserver.RunServer"
}
ADDED: restserver/src/main/java/com/androidbyexample/compose/movies/restserver/RunServer.kt
package com.androidbyexample.compose.movies.restserver
class RunServer {
companion object {
@JvmStatic
fun main(args: Array<String>) {
println("It runs!")
}
}
}
CHANGED: settings.gradle.kts
pluginManagement {
repositories {
google {
content {
includeGroupByRegex("com\\.android.*")
includeGroupByRegex("com\\.google.*")
includeGroupByRegex("androidx.*")
}
}
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "Movies"
include(":app")
include(":data")
include(":repository")
include(":restserver")