or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

gson-serializer.mdindex.mdjackson-serializer.mdjson-plugin.mdjson-serializer.mdkotlinx-serializer.md

jackson-serializer.mddocs/

0

# Jackson Serialization

1

2

Jackson-based JSON serialization implementation for Ktor HTTP clients. Provides high-performance JSON processing with extensive configuration options, custom serializers, and advanced data binding features through the Jackson ObjectMapper.

3

4

## Capabilities

5

6

### JacksonSerializer Class

7

8

JsonSerializer implementation using Jackson's ObjectMapper for JSON processing.

9

10

```kotlin { .api }

11

/**

12

* JsonSerializer using Jackson as backend.

13

*/

14

@Deprecated("Please use ContentNegotiation plugin and its converters")

15

class JacksonSerializer(

16

jackson: ObjectMapper = jacksonObjectMapper(),

17

block: ObjectMapper.() -> Unit = {}

18

) : JsonSerializer {

19

/**

20

* Convert data object to OutgoingContent using Jackson serialization.

21

*/

22

override fun write(data: Any, contentType: ContentType): OutgoingContent

23

24

/**

25

* Read content from response using Jackson deserialization.

26

*/

27

override fun read(type: TypeInfo, body: Input): Any

28

}

29

```

30

31

## Service Registration

32

33

The JacksonSerializer is automatically discoverable on JVM through the ServiceLoader mechanism:

34

35

**META-INF/services/io.ktor.client.plugins.json.JsonSerializer**

36

```

37

io.ktor.client.plugins.jackson.JacksonSerializer

38

```

39

40

## Dependencies

41

42

To use JacksonSerializer, add the Jackson dependency to your project:

43

44

**Gradle**

45

```kotlin

46

implementation("io.ktor:ktor-client-jackson:2.3.13")

47

```

48

49

**Maven**

50

```xml

51

<dependency>

52

<groupId>io.ktor</groupId>

53

<artifactId>ktor-client-jackson-jvm</artifactId>

54

<version>2.3.13</version>

55

</dependency>

56

```

57

58

## Usage Examples

59

60

### Basic Usage

61

62

```kotlin

63

import io.ktor.client.*

64

import io.ktor.client.plugins.json.*

65

import io.ktor.client.plugins.jackson.*

66

67

val client = HttpClient {

68

install(JsonPlugin) {

69

serializer = JacksonSerializer()

70

}

71

}

72

```

73

74

### Custom ObjectMapper Configuration

75

76

```kotlin

77

val client = HttpClient {

78

install(JsonPlugin) {

79

serializer = JacksonSerializer {

80

// Configure ObjectMapper

81

configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

82

configure(SerializationFeature.INDENT_OUTPUT, true)

83

configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)

84

85

// Property naming strategy

86

propertyNamingStrategy = PropertyNamingStrategies.SNAKE_CASE

87

88

// Date format

89

setDateFormat(SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))

90

91

// Null value handling

92

setSerializationInclusion(JsonInclude.Include.NON_NULL)

93

94

// Custom modules

95

registerModule(JavaTimeModule())

96

registerModule(KotlinModule.Builder().build())

97

}

98

}

99

}

100

```

101

102

### Data Classes with Jackson

103

104

```kotlin

105

import com.fasterxml.jackson.annotation.*

106

import java.time.LocalDateTime

107

108

data class User(

109

val id: Long,

110

val name: String,

111

val email: String,

112

@JsonProperty("created_at")

113

val createdAt: LocalDateTime,

114

@JsonIgnore

115

val password: String? = null

116

)

117

118

// POST request - automatic serialization

119

val response = client.post("https://api.example.com/users") {

120

contentType(ContentType.Application.Json)

121

setBody(User(0, "Alice", "alice@example.com", LocalDateTime.now()))

122

}

123

124

// GET request - automatic deserialization

125

val user: User = client.get("https://api.example.com/users/1").body()

126

```

127

128

### Custom Serializers and Deserializers

129

130

```kotlin

131

import com.fasterxml.jackson.core.*

132

import com.fasterxml.jackson.databind.*

133

import java.time.LocalDateTime

134

import java.time.format.DateTimeFormatter

135

136

class LocalDateTimeSerializer : JsonSerializer<LocalDateTime>() {

137

private val formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME

138

139

override fun serialize(

140

value: LocalDateTime,

141

gen: JsonGenerator,

142

serializers: SerializerProvider

143

) {

144

gen.writeString(value.format(formatter))

145

}

146

}

147

148

class LocalDateTimeDeserializer : JsonDeserializer<LocalDateTime>() {

149

private val formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME

150

151

override fun deserialize(

152

parser: JsonParser,

153

context: DeserializationContext

154

): LocalDateTime {

155

return LocalDateTime.parse(parser.valueAsString, formatter)

156

}

157

}

158

159

// Usage with custom serializers

160

val client = HttpClient {

161

install(JsonPlugin) {

162

serializer = JacksonSerializer {

163

val module = SimpleModule()

164

module.addSerializer(LocalDateTime::class.java, LocalDateTimeSerializer())

165

module.addDeserializer(LocalDateTime::class.java, LocalDateTimeDeserializer())

166

registerModule(module)

167

}

168

}

169

}

170

```

171

172

### Polymorphic Serialization

173

174

```kotlin

175

import com.fasterxml.jackson.annotation.*

176

177

@JsonTypeInfo(

178

use = JsonTypeInfo.Id.NAME,

179

include = JsonTypeInfo.As.PROPERTY,

180

property = "type"

181

)

182

@JsonSubTypes(

183

JsonSubTypes.Type(value = Dog::class, name = "dog"),

184

JsonSubTypes.Type(value = Cat::class, name = "cat")

185

)

186

abstract class Animal(

187

open val name: String

188

)

189

190

@JsonTypeName("dog")

191

data class Dog(

192

override val name: String,

193

val breed: String

194

) : Animal(name)

195

196

@JsonTypeName("cat")

197

data class Cat(

198

override val name: String,

199

val color: String

200

) : Animal(name)

201

202

// Usage

203

val animals = listOf(

204

Dog("Buddy", "Golden Retriever"),

205

Cat("Whiskers", "Orange")

206

)

207

208

val response = client.post("https://api.example.com/animals") {

209

contentType(ContentType.Application.Json)

210

setBody(animals)

211

}

212

```

213

214

### Collection and Map Handling

215

216

```kotlin

217

// Generic type handling with TypeReference

218

import com.fasterxml.jackson.core.type.TypeReference

219

220

// List deserialization

221

val userListType = object : TypeReference<List<User>>() {}

222

val users: List<User> = client.get("https://api.example.com/users").body()

223

224

// Map deserialization

225

val userMapType = object : TypeReference<Map<String, User>>() {}

226

val userMap: Map<String, User> = client.get("https://api.example.com/users/map").body()

227

228

// Complex nested structures

229

data class ApiResponse<T>(

230

val data: T,

231

val status: String,

232

val message: String?

233

)

234

235

val responseType = object : TypeReference<ApiResponse<List<User>>>() {}

236

val response: ApiResponse<List<User>> = client.get("https://api.example.com/users").body()

237

```

238

239

### Error Handling

240

241

```kotlin

242

import com.fasterxml.jackson.core.*

243

import com.fasterxml.jackson.databind.*

244

245

try {

246

val user: User = client.get("https://api.example.com/users/1").body()

247

} catch (e: JsonParseException) {

248

// Malformed JSON

249

logger.error("Invalid JSON response", e)

250

} catch (e: JsonMappingException) {

251

// Mapping error (type mismatch, missing properties)

252

logger.error("JSON mapping error", e)

253

} catch (e: JsonProcessingException) {

254

// General processing error

255

logger.error("JSON processing error", e)

256

}

257

```

258

259

### Advanced ObjectMapper Configuration

260

261

```kotlin

262

val client = HttpClient {

263

install(JsonPlugin) {

264

serializer = JacksonSerializer {

265

// Deserialization features

266

configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

267

configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false)

268

configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true)

269

configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true)

270

271

// Serialization features

272

configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)

273

configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)

274

configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false)

275

configure(SerializationFeature.INDENT_OUTPUT, true)

276

277

// Property inclusion

278

setSerializationInclusion(JsonInclude.Include.NON_NULL)

279

setSerializationInclusion(JsonInclude.Include.NON_EMPTY)

280

281

// Visibility settings

282

setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)

283

setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)

284

285

// Property naming strategy

286

propertyNamingStrategy = PropertyNamingStrategies.SNAKE_CASE

287

288

// Date and time handling

289

registerModule(JavaTimeModule())

290

setDateFormat(SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"))

291

292

// Kotlin support

293

registerModule(KotlinModule.Builder()

294

.withReflectionCacheSize(512)

295

.configure(KotlinFeature.NullToEmptyCollection, false)

296

.configure(KotlinFeature.NullToEmptyMap, false)

297

.configure(KotlinFeature.SingletonSupport, true)

298

.build())

299

}

300

}

301

}

302

```

303

304

### MixIn Annotations

305

306

```kotlin

307

// Using MixIn to add annotations to third-party classes

308

interface UserMixIn {

309

@JsonProperty("user_id")

310

fun getId(): Long

311

312

@JsonIgnore

313

fun getPassword(): String?

314

}

315

316

val client = HttpClient {

317

install(JsonPlugin) {

318

serializer = JacksonSerializer {

319

addMixIn(User::class.java, UserMixIn::class.java)

320

}

321

}

322

}

323

```

324

325

## Jackson Configuration Options

326

327

The JacksonSerializer supports extensive ObjectMapper configuration:

328

329

### Deserialization Features

330

- `FAIL_ON_UNKNOWN_PROPERTIES`: Control unknown property handling

331

- `FAIL_ON_NULL_FOR_PRIMITIVES`: Handle null values for primitives

332

- `ACCEPT_EMPTY_STRING_AS_NULL_OBJECT`: Empty string handling

333

- `READ_UNKNOWN_ENUM_VALUES_AS_NULL`: Enum value handling

334

335

### Serialization Features

336

- `FAIL_ON_EMPTY_BEANS`: Empty object handling

337

- `WRITE_DATES_AS_TIMESTAMPS`: Date format control

338

- `INDENT_OUTPUT`: Pretty printing

339

- `WRITE_NULL_MAP_VALUES`: Null value inclusion

340

341

### Property Inclusion

342

- `JsonInclude.Include.NON_NULL`: Exclude null values

343

- `JsonInclude.Include.NON_EMPTY`: Exclude empty collections

344

- `JsonInclude.Include.NON_DEFAULT`: Exclude default values

345

346

### Advanced Features

347

- **Custom Modules**: JavaTimeModule, KotlinModule, etc.

348

- **Property Naming**: Snake case, camel case strategies

349

- **Type Information**: Polymorphic type handling

350

- **MixIn Annotations**: Add annotations to third-party classes

351

- **Custom Serializers**: Fine-grained serialization control

352

353

## Performance Considerations

354

355

- ObjectMapper instances are thread-safe and should be reused

356

- Module registration is expensive - do it during configuration, not per request

357

- Consider using `@JsonIgnoreProperties(ignoreUnknown = true)` for resilient deserialization

358

- Custom serializers should be stateless and lightweight

359

- Use TypeReference for complex generic types to avoid type erasure issues