Skip to content

Commit

Permalink
Register Scala EnumModule on default ObjectMapper
Browse files Browse the repository at this point in the history
  • Loading branch information
carlosedp committed Feb 2, 2024
1 parent 6caa943 commit 846ed2a
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 37 deletions.
58 changes: 22 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
- [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

Expand Down Expand Up @@ -248,54 +249,36 @@ 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:
If using Jackson for serialization, you probably want JSON support for case class and Enum.
There are two libraries you need to add to your project to enable this:

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

To set this up:

- Add the following to your dependencies

```xml
<!-- JSON Serialization Dependencies -->
<dependency>
<groupId>com.github.pjfanning</groupId>
<artifactId>jackson-module-scala3-enum_3</artifactId>
<version>2.12.3</version>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_3</artifactId>
<version>2.16.1</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_2.13</artifactId>
<version>2.12.3</version>
<groupId>com.github.pjfanning</groupId>
<artifactId>jackson-module-scala3-enum_3</artifactId>
<version>2.16.0</version>
</dependency>
```

- 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:

Expand All @@ -308,13 +291,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:
Expand Down Expand Up @@ -459,4 +445,4 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ class Scala3Processor {

private static final String FEATURE = "scala3";
private static final String SCALA_JACKSON_MODULE = "com.fasterxml.jackson.module.scala.DefaultScalaModule";
private static final String SCALA_JACKSON_ENUM_MODULE = "com.github.pjfanning.enum.EnumModule";

@BuildStep
FeatureBuildItem feature() {
return new FeatureBuildItem(FEATURE);
}

/*
* Register the Scala Jackson module if that has been added to the classpath
* Register the Scala Jackson module and Scala Enum module if that has been
* added to the classpath
* Producing the BuildItem is entirely safe since if quarkus-jackson is not on
* the classpath the BuildItem will just be ignored
*/
Expand All @@ -25,6 +27,8 @@ void registerScalaJacksonModule(BuildProducer<ClassPathJacksonModuleBuildItem> c
try {
Class.forName(SCALA_JACKSON_MODULE, false, Thread.currentThread().getContextClassLoader());
classPathJacksonModules.produce(new ClassPathJacksonModuleBuildItem(SCALA_JACKSON_MODULE));
Class.forName(SCALA_JACKSON_ENUM_MODULE, false, Thread.currentThread().getContextClassLoader());
classPathJacksonModules.produce(new ClassPathJacksonModuleBuildItem(SCALA_JACKSON_ENUM_MODULE));
} catch (Exception ignored) {
}
}
Expand Down

0 comments on commit 846ed2a

Please sign in to comment.