diff --git a/README.md b/README.md index 726098d..bade6c3 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,12 @@ - [Passing Scala compiler args in Quarkus Dev Mode](#passing-scala-compiler-args-in-quarkus-dev-mode) - [Useful tips and tricks for building Quarkus apps with Scala, common patterns](#useful-tips-and-tricks-for-building-quarkus-apps-with-scala-common-patterns) - ["No tests were found"?! How can that be?](#no-tests-were-found-how-can-that-be) - - [Configuring Scala Jackson and the addon-on "Enum" module for JSON support](#configuring-scala-jackson-and-the-addon-on-enum-module-for-json-support) + - [Scala and Jackson serialization for JSON with Scala Enum support](#scala-and-jackson-serialization-for-json-with-scala-enum-support) - [Scala DSL for rest-assured (similar to Kotlin DSL)](#scala-dsl-for-rest-assured-similar-to-kotlin-dsl) - [Functional HTTP routes (Vert.x handlers)](#functional-http-routes-vertx-handlers) + - [Contributors ✨](#contributors-) -## Introduction +## Introduction This extension provides support for Scala 3 in Quarkus. @@ -50,43 +51,23 @@ repositories { } VERSIONS = [ - QUARKUS_SCALA3: "0.0.1", - SCALA3 : "3.1.0", - SCALA_LIBRARY : "2.13.6", - // Scala Jackson at time of writing doesn't support Scala 3 Enum's natively. It requires another library. - // That library doesn't support same version of Jackson that Quarkus BOM uses (2.12.5), so this is the best compromise - // https://search.maven.org/artifact/com.github.pjfanning/jackson-module-scala3-enum_3/2.12.3/jar - JACKSON : "2.12.3" + QUARKUS: "3.10.0", + QUARKUS_SCALA3: "1.0.0", + SCALA3 : "3.3.3", ] dependencies { + implementation enforcedPlatform("io.quarkus.platform:quarkus-bom:${VERSIONS.QUARKUS}") implementation "io.quarkiverse.scala:quarkus-scala3:${VERSIONS.QUARKUS_SCALA3}" - implementation("org.scala-lang:scala3-compiler_3") { - version { - strictly VERSIONS.SCALA3 - } - } - implementation("org.scala-lang:scala3-library_3") { - version { - strictly VERSIONS.SCALA3 - } - } - implementation("org.scala-lang:scala-library") { - version { - strictly VERSIONS.SCALA_LIBRARY - } - } + implementation "org.scala-lang:scala3-library_3:${VERSIONS.SCALA3}" + implementation "org.scala-lang:scala3-compiler_3:${VERSIONS.SCALA3}" - // Quarkus comes with Scala 2 distributed in it's Bill-of-Materials unfortunately - // It's Scala 2.12.13, which is not ABI compatible -- With Scala 3, we need to exclude this entirely - implementation(enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")) { - exclude group: 'org.scala-lang', module: 'scala-library' - } implementation "io.quarkus:quarkus-arc" implementation "io.quarkus:quarkus-resteasy-reactive" - implementation "com.fasterxml.jackson.module:jackson-module-scala_3:${VERSIONS.JACKSON}" - implementation "com.github.pjfanning:jackson-module-scala3-enum_3:${VERSIONS.JACKSON}" + implementation "io.quarkus:quarkus-jackson" + implementation "io.quarkus:quarkus-rest-jackson" + implementation "com.fasterxml.jackson.module:jackson-module-scala_3" testImplementation "io.quarkus:quarkus-junit5" testImplementation "io.rest-assured:rest-assured" @@ -96,31 +77,24 @@ group = "org.acme" version = "1.0.0-SNAPSHOT" java { - // Set to 17 for performance reasons, feel free to change to 11 or 8 - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } tasks.withType(ScalaCompile) { scalaCompileOptions.additionalParameters = [ - "-feature", // Emit warnings and locations for features that should be imported explicitly - "-explain", // Explain (type) errors in more detail - "-Ysafe-init", // Ensure safe initialization of objects (prevent null object init) - "-Yrequire-targetName", // Warn if an operator is defined without a @targetName annotation - // "-Yexplicit-nulls", // Make reference types non-nullable. Nullable types can be expressed with unions: e.g. String|Null. - - // I am unsure if this is required for proper tooling to work. Metals/IntelliJ may already cover this. - "-Xsemanticdb", // Store information in SemanticDB + "-feature", + "-Wunused:all", ] } compileJava { - options.encoding = 'UTF-8' - options.compilerArgs << '-parameters' + options.encoding = "UTF-8" + options.compilerArgs << "-parameters" } compileTestJava { - options.encoding = 'UTF-8' + options.encoding = "UTF-8" } ``` @@ -130,43 +104,40 @@ If you want to use this extension, you need to add the `io.quarkiverse.scala:qua In your `pom.xml` file, add: ```xml - - io.quarkiverse.scala - quarkus-scala3 - 0.0.1 - + +... + + io.quarkiverse.scala + quarkus-scala3 + 0.0.1 + +... ``` -Then, you will need to install the Scala 3 compiler, the Scala Maven plugin, and to fix an odd bug with the way that the Scala 3 compiler Maven dependencies are resolved. - -Due to Scala 2 version in upstream `Quarkus BOM`, the wrong version of `scala-library` (a transitive dependency: `scala3-compiler_3` -> `scala3-library_3` -> `scala-library`) is resolved. - -This causes binary incompatibilities -- and Scala to break. In order to fix this, you just need to manually align the version of `scala-library` to the one listed as used by the version of `scala3-library_3` that's the same as the `scala3-compiler_3` version. - -So for `scala3-compiler_3` = `3.0.0`, then `scala3-library_3` = `3.0.0`, and we check the `scala-library` version it uses: -- https://mvnrepository.com/artifact/org.scala-lang/scala3-library_3/3.0.0 - -Here, we can see that it was compiled with `2.13.5` in it's dependencies. So that's what we set in ours: +Then, you will need to add the Scala 3 compiler and library and the Scala Maven plugin: ```xml - 4.5.3 - 3.1.0 - 2.13.6 + 4.9.1 + 3.3.3 - org.scala-lang - scala3-compiler_3 - ${scala.version} + io.quarkiverse.scala + quarkus-scala3 + 1.0.0 + + + org.scala-lang + scala3-library_3 + ${scala.version} - - org.scala-lang - scala-library - ${scala-library.version} + org.scala-lang + scala3-compiler_3 + ${scala.version} @@ -202,10 +173,10 @@ Here, we can see that it was compiled with `2.13.5` in it's dependencies. So tha ${scala.version} - -deprecated - -explain + -Wunused:all -feature - -Ysafe-init + -deprecation + -Ysemanticdb @@ -250,54 +221,25 @@ class MyTest: assert(2 == 2) ``` -### Configuring Scala Jackson and the addon-on "Enum" module for JSON support +### Scala and Jackson serialization for JSON with Scala Enum support -You probably want JSON support for case class and enum serialization. -There are two things you need to enable this, as of the time of writing: - -1. The standard Jackson Scala module -2. An addon module from one of the Jackson Scala maintainers for Scala 3 enums that hasn't made its way into the official module yet +If using Jackson for serialization, you probably want JSON support for case class and Enum. Scala Jackson module already supports Scala 3 Enums built-in. To set this up: -- Add the following to your dependencies - +- Add the following to your dependencies (in addition to existing `quarkus-jackson` and `quarkus-rest-jackson` extensions). + ```xml - com.github.pjfanning - jackson-module-scala3-enum_3 - 2.12.3 - - - - com.fasterxml.jackson.module - jackson-module-scala_2.13 - 2.12.3 + com.fasterxml.jackson.module + jackson-module-scala_3 ``` -- Set up something like the below in your codebase: - -```scala -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.module.scala.DefaultScalaModule -import com.github.pjfanning.`enum`.EnumModule -import io.quarkus.jackson.ObjectMapperCustomizer - -import javax.inject.Singleton - -// https://quarkus.io/guides/rest-json#jackson -@Singleton -class Scala3ObjectMapperCustomizer extends ObjectMapperCustomizer: - def customize(mapper: ObjectMapper): Unit = - // General Scala support - // https://github.com/FasterXML/jackson-module-scala - mapper.registerModule(DefaultScalaModule) - // Suport for Scala 3 Enums - // https://github.com/pjfanning/jackson-module-scala3-enum - mapper.registerModule(EnumModule) -``` +If these dependencies are added to the project, they will be automatically registered to the default `ObjectMapper` bean. + +To ensure full-compatibility with native-image, it is recommended to apply the Jackson @field:JsonProperty("fieldName") annotation, and set a nullable default, as shown below. The API is usable like this: @@ -310,13 +252,16 @@ import org.junit.jupiter.api.{DisplayName, Test} import javax.inject.Inject import scala.collection.JavaConverters.* - enum AnEnum: case A extends AnEnum case B extends AnEnum -case class Other(foo: String) -case class Something(name: String, someEnum: AnEnum, other: Other) +case class Other(@JsonProperty("foo") foo: String) +case class Something( + @JsonProperty("name") name: String, + @JsonProperty("someEnum") someEnum: AnEnum, + @JsonValue other: Other, + ) @QuarkusTest class Scala3ObjectMapperCustomizerTest: @@ -452,6 +397,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Gavin Ray
Gavin Ray

💻 🚧 Guillaume Smet
Guillaume Smet

💻 + Carlos Eduardo de Paula
Carlos Eduardo de Paula

💻 diff --git a/deployment/pom.xml b/deployment/pom.xml index 34e2699..f0d944e 100644 --- a/deployment/pom.xml +++ b/deployment/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 io.quarkiverse.scala @@ -36,7 +37,7 @@ org.scala-lang scala3-interfaces - 3.3.1 + 3.3.3
@@ -55,4 +56,4 @@ - \ No newline at end of file + diff --git a/pom.xml b/pom.xml index b80da21..16c70e3 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 io.quarkiverse @@ -24,7 +25,7 @@ UTF-8 UTF-8 - 3.6.4 + 3.10.0