Skip to content

Commit 9ae84c9

Browse files
authored
Added Scala 3 support (#1904)
Added Macro support for Scala 3 Split Scala code to Scala 2 and Scala 3 specific code Updated evergreen to test Scala 3 Updated spotless Scala configuration to default to Scala 2 Added custom spotless Scala configuration for Scala 3 in bson-scala Updated test code work both with Scala 2 and Scala 3 JAVA-5261
1 parent 7a271ca commit 9ae84c9

87 files changed

Lines changed: 3347 additions & 229 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.evergreen/.evg.yml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1894,6 +1894,10 @@ axes:
18941894
display_name: "Scala 2.13"
18951895
variables:
18961896
SCALA: "2.13"
1897+
- id: "3"
1898+
display_name: "Scala 3"
1899+
variables:
1900+
SCALA: "3"
18971901

18981902
- id: "api-version"
18991903
display_name: "API Version"
@@ -2503,14 +2507,23 @@ buildvariants:
25032507
tasks:
25042508
- name: ".ocsp"
25052509

2506-
- matrix_name: "scala-tests"
2510+
- matrix_name: "scala-tests-2"
25072511
matrix_spec: { auth: "noauth", ssl: "nossl", jdk: [ "jdk8", "jdk17", "jdk21" ], version: [ "7.0" ], topology: "replicaset",
2508-
scala: "*", os: "ubuntu" }
2512+
scala: ["2.11", "2.12", "2.13"] , os: "ubuntu" }
25092513
display_name: "${scala} ${jdk} ${version} ${topology} ${os}"
25102514
tags: [ "test-scala-variant" ]
25112515
tasks:
25122516
- name: "scala-test-task"
25132517

2518+
- matrix_name: "scala-tests-3"
2519+
matrix_spec: { auth: "noauth", ssl: "nossl", jdk: [ "jdk17", "jdk21" ], version: [ "8.0" ], topology: "replicaset",
2520+
scala: "3", os: "ubuntu" }
2521+
display_name: "${scala} ${jdk} ${version} ${topology} ${os}"
2522+
tags: [ "test-scala-variant" ]
2523+
tasks:
2524+
- name: "scala-test-task"
2525+
2526+
25142527
- matrix_name: "kotlin-tests"
25152528
matrix_spec: { auth: "noauth", ssl: "nossl", jdk: [ "jdk8", "jdk17", "jdk21" ], version: [ "7.0" ], topology: "replicaset", os: "ubuntu" }
25162529
display_name: "Kotlin: ${jdk} ${version} ${topology} ${os}"

bom/build.gradle.kts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,12 @@ require(!scalaVersions.isNullOrEmpty()) {
5858
}
5959

6060
scalaVersions?.forEach { version ->
61-
require(version.matches(Regex("\\d\\.\\d{2}"))) { "Scala version '$version' must be in the format X.YY" }
61+
require(version.matches(Regex("^[23].*"))) { "Scala version '$version' not supported." }
62+
if (version.startsWith("3")) {
63+
require(version.matches(Regex("^3$"))) { "Scala version '$version' must be in the format X" }
64+
} else {
65+
require(version.matches(Regex("\\d\\.\\d{2}"))) { "Scala version '$version' must be in the format X.YY" }
66+
}
6267
}
6368
/*
6469
* Apply the Java Platform plugin to create the BOM

bson-scala/README.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Scala Bson library
2+
3+
The `bson-scala` project provides Scala-idiomatic wrappers for the Java Bson library.
4+
It currently supports: **Scala 2.11**, **Scala 2.12**, **Scala 2.13**, and **Scala 3**.
5+
6+
## Scala Versions
7+
8+
Supported Scala versions and their exact version numbers are defined in [`gradle.properties`](../gradle.properties):
9+
10+
- `supportedScalaVersions` — the list of supported Scala versions
11+
- `defaultScalaVersion` — the version used when no `-PscalaVersion` flag is provided (currently `2.13`)
12+
13+
## Build Configuration
14+
15+
The Scala source set configuration, compiler options, and dependency wiring are all handled in [`buildSrc/src/main/kotlin/project/scala.gradle.kts`](../buildSrc/src/main/kotlin/project/scala.gradle.kts).
16+
17+
## Library Dependencies
18+
19+
Scala library and test dependencies for each version are defined in [`gradle/libs.versions.toml`](../gradle/libs.versions.toml). Look for entries prefixed with `scala-` in the `[versions]`, `[libraries]`, and `[bundles]` sections.
20+
21+
## Directory Layout
22+
23+
Source code is organized into version-specific directories.
24+
Shared code goes in the common `scala` directory, while version-specific code goes in the appropriate directory:
25+
26+
```
27+
src/main/
28+
├── scala/ # Shared code (all Scala versions)
29+
├── scala-2/ # Scala 2 only (2.11, 2.12 and 2.13)
30+
├── scala-2.13/ # Scala 2.13 only
31+
├── scala-2.13-/ # Scala 2.12 & 2.11
32+
├── scala-3/ # Scala 3 only
33+
```
34+
35+
Test code also supports the same directory structure.
36+
The source sets for each Scala version are configured in [`buildSrc/src/main/kotlin/project/scala.gradle.kts`](../buildSrc/src/main/kotlin/project/scala.gradle.kts).
37+
When adding new code, place it in the most general directory that applies. Only use a version-specific directory when the code requires syntax or APIs unique to that version.
38+
39+
## Code Formatting (Spotless)
40+
41+
Spotless defaults to **Scala 2.13** formatting rules. This means code in shared directories (`scala/`, `scala-2/`) is formatted with the 2.13 scalafmt configuration.
42+
43+
For **Scala 3 specific code**, the `bson-scala/build.gradle.kts` shows how to configure Spotless to use a Scala 3 scalafmt config. It targets only files in `**/scala-3/**` and uses a separate `config/scala/scalafmt-3.conf`:
44+
45+
```kotlin
46+
if (scalaVersion.equals("3")) {
47+
spotless {
48+
scala {
49+
clearSteps()
50+
target("**/scala-3/**")
51+
scalafmt("3.10.7").configFile(rootProject.file("config/scala/scalafmt-3.conf"))
52+
}
53+
}
54+
}
55+
```
56+
57+
Use this pattern in other `build.gradle.kts` files if they also contain Scala 3 specific code.
58+
59+
## Testing
60+
61+
By default, tests run against Scala 2.13. To test against a specific Scala version, pass the `-PscalaVersion` flag:
62+
63+
```bash
64+
# Test bson-scala with Scala 3
65+
./gradlew :bson-scala:scalaCheck -PscalaVersion=3
66+
67+
# Test bson-scala with Scala 2.12
68+
./gradlew :bson-scala:scalaCheck -PscalaVersion=2.12
69+
70+
# Test bson-scala with the default (2.13)
71+
./gradlew :bson-scala:scalaCheck
72+
```

bson-scala/build.gradle.kts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
*/
1616
import ProjectExtensions.configureJarManifest
1717
import ProjectExtensions.configureMavenPublication
18+
import ProjectExtensions.scalaVersion
1819

1920
plugins { id("project.scala") }
2021

22+
val scalaVersion: String = project.scalaVersion()
23+
2124
base.archivesName.set("mongo-scala-bson")
2225

2326
dependencies { api(project(path = ":bson", configuration = "default")) }
@@ -35,3 +38,13 @@ configureJarManifest {
3538
attributes["Bundle-SymbolicName"] = "org.mongodb.scala.mongo-scala-bson"
3639
attributes["Import-Package"] = "!scala.*,*"
3740
}
41+
42+
if (scalaVersion.equals("3")) {
43+
spotless {
44+
scala {
45+
clearSteps()
46+
target("**/scala-3/**")
47+
scalafmt("3.10.7").configFile(rootProject.file("config/scala/scalafmt-3.conf"))
48+
}
49+
}
50+
}

bson-scala/src/main/scala-2.13+/org/mongodb/scala/bson/collection/immutable/Document.scala renamed to bson-scala/src/main/scala-2.13/org/mongodb/scala/bson/collection/immutable/Document.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ object Document extends SpecificIterableFactory[(String, BsonValue), Document] {
4444
/**
4545
* Parses a string in MongoDB Extended JSON format to a `Document`
4646
*
47-
* @param json the JSON stringN
47+
* @param json the JSON string
4848
* @return a corresponding `Document` object
4949
* @see org.bson.json.JsonReader
5050
* @see [[https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/ MongoDB Extended JSON]]

bson-scala/src/main/scala-2.13+/org/mongodb/scala/bson/collection/mutable/Document.scala renamed to bson-scala/src/main/scala-2.13/org/mongodb/scala/bson/collection/mutable/Document.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ case class Document(protected[scala] val underlying: BsonDocument)
108108
import BsonMagnets._
109109

110110
/**
111-
* Creates a new immutable document
111+
* Creates a new mutable document
112112
* @param underlying the underlying BsonDocument
113113
* @return a new document
114114
*/

bson-scala/src/main/scala/org/mongodb/scala/bson/codecs/Macros.scala renamed to bson-scala/src/main/scala-2/org/mongodb/scala/bson/codecs/Macros.scala

File renamed without changes.

bson-scala/src/main/scala/org/mongodb/scala/bson/codecs/macrocodecs/CaseClassCodec.scala renamed to bson-scala/src/main/scala-2/org/mongodb/scala/bson/codecs/macrocodecs/CaseClassCodec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ private[codecs] object CaseClassCodec {
345345
val cases: Seq[Tree] = {
346346
fields.map {
347347
case (classType, _) if isCaseObject(classType) => cq""" ${keyName(classType)} =>"""
348-
case (classType, fields) =>
348+
case (classType, fields) =>
349349
cq""" ${keyName(classType)} =>
350350
val instanceValue = value.asInstanceOf[${classType}]
351351
..${writeClassValues(fields, ignoredFields(classType))}"""

bson-scala/src/main/scala/org/mongodb/scala/bson/codecs/macrocodecs/CaseClassProvider.scala renamed to bson-scala/src/main/scala-2/org/mongodb/scala/bson/codecs/macrocodecs/CaseClassProvider.scala

File renamed without changes.

bson-scala/src/main/scala/org/mongodb/scala/bson/codecs/macrocodecs/MacroCodec.scala renamed to bson-scala/src/main/scala-2/org/mongodb/scala/bson/codecs/macrocodecs/MacroCodec.scala

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ trait MacroCodec[T] extends Codec[T] {
187187
currentType match {
188188
case BsonType.DOCUMENT => readDocument(reader, decoderContext, clazz, typeArgs)
189189
case BsonType.ARRAY => readArray(reader, decoderContext, clazz, typeArgs)
190-
case BsonType.NULL =>
190+
case BsonType.NULL =>
191191
reader.readNull()
192192
null.asInstanceOf[V] // scalastyle:ignore
193193
case _ => registry.get(clazz).decode(reader, decoderContext)
@@ -239,12 +239,13 @@ trait MacroCodec[T] extends Codec[T] {
239239
if (typeArgs.isEmpty) {
240240
reader.skipValue()
241241
} else {
242-
map += (name -> readValue(
243-
reader,
244-
decoderContext,
245-
typeArgs.head,
246-
typeArgs.tail
247-
))
242+
map +=
243+
(name -> readValue(
244+
reader,
245+
decoderContext,
246+
typeArgs.head,
247+
typeArgs.tail
248+
))
248249
}
249250
}
250251
reader.readEndDocument()

0 commit comments

Comments
 (0)