or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

attributes.mdbean-style.mdcode-generation.mdcollections.mdcore-immutable.mdindex.mdintegrations.mdjson-marshaling.mdruntime-marshaling.mdstyling.md

json-marshaling.mddocs/

0

# JSON Marshaling

1

2

Built-in JSON marshaling capabilities with customizable field names, subclass handling, and integration with streaming JSON APIs. The JSON marshaling feature generates efficient serialization code that works with the Immutables runtime marshaling framework.

3

4

## Capabilities

5

6

### JSON Marshaled Generation

7

8

Generate JSON marshaler for immutable types with streaming API support.

9

10

```java { .api }

11

/**

12

* Generate JSON marshaler for the annotated immutable type.

13

* Creates marshalers that integrate with the Immutables JSON framework

14

* for efficient streaming serialization and deserialization.

15

*/

16

@Target(ElementType.TYPE)

17

@Retention(RetentionPolicy.SOURCE)

18

@interface Json.Marshaled {}

19

```

20

21

**Usage Example:**

22

23

```java

24

import org.immutables.value.Value;

25

import org.immutables.value.Json;

26

import java.util.Optional;

27

import java.util.List;

28

29

@Value.Immutable

30

@Json.Marshaled

31

public interface Person {

32

String name();

33

int age();

34

Optional<String> email();

35

List<String> tags();

36

}

37

38

// JSON marshaling usage

39

Person person = ImmutablePerson.builder()

40

.name("Alice")

41

.age(30)

42

.email("alice@example.com")

43

.addTags("developer", "java")

44

.build();

45

46

// Serialize to JSON

47

String json = PersonMarshaler.instance().toString(person);

48

// {"name":"Alice","age":30,"email":"alice@example.com","tags":["developer","java"]}

49

50

// Deserialize from JSON

51

Person restored = PersonMarshaler.instance().fromString(json);

52

```

53

54

### Custom Field Names

55

56

Customize JSON field names for attributes.

57

58

```java { .api }

59

/**

60

* Specify custom JSON field name for an attribute.

61

* Overrides the default field name derived from the accessor method.

62

*/

63

@Target(ElementType.METHOD)

64

@Retention(RetentionPolicy.SOURCE)

65

@interface Json.Named {

66

/** Custom JSON field name */

67

String value();

68

}

69

```

70

71

**Usage Example:**

72

73

```java

74

import org.immutables.value.Value;

75

import org.immutables.value.Json;

76

77

@Value.Immutable

78

@Json.Marshaled

79

public interface ApiResponse {

80

@Json.Named("response_code")

81

int responseCode();

82

83

@Json.Named("data")

84

String responseData();

85

86

@Json.Named("timestamp_ms")

87

long timestampMillis();

88

}

89

90

// Generated JSON uses custom field names

91

ApiResponse response = ImmutableApiResponse.builder()

92

.responseCode(200)

93

.responseData("success")

94

.timestampMillis(System.currentTimeMillis())

95

.build();

96

97

String json = ApiResponseMarshaler.instance().toString(response);

98

// {"response_code":200,"data":"success","timestamp_ms":1640995200000}

99

```

100

101

### Field Exclusion

102

103

Exclude specific attributes from JSON serialization.

104

105

```java { .api }

106

/**

107

* Exclude an attribute from JSON marshaling.

108

* The attribute will not appear in serialized JSON output

109

* and will not be expected during deserialization.

110

*/

111

@Target(ElementType.METHOD)

112

@Retention(RetentionPolicy.SOURCE)

113

@interface Json.Ignore {}

114

```

115

116

**Usage Example:**

117

118

```java

119

import org.immutables.value.Value;

120

import org.immutables.value.Json;

121

import java.time.Instant;

122

123

@Value.Immutable

124

@Json.Marshaled

125

public interface UserAccount {

126

String username();

127

String email();

128

129

@Json.Ignore // Sensitive data not serialized

130

String passwordHash();

131

132

@Json.Ignore // Internal field not exposed via JSON

133

Instant lastModified();

134

135

boolean active();

136

}

137

138

// passwordHash and lastModified are excluded from JSON

139

UserAccount account = ImmutableUserAccount.builder()

140

.username("alice")

141

.email("alice@example.com")

142

.passwordHash("$2a$10$...")

143

.lastModified(Instant.now())

144

.active(true)

145

.build();

146

147

String json = UserAccountMarshaler.instance().toString(account);

148

// {"username":"alice","email":"alice@example.com","active":true}

149

```

150

151

### Force Empty Values

152

153

Force output of empty collections and null optional values.

154

155

```java { .api }

156

/**

157

* Force output of empty collections or null optional values in JSON.

158

* By default, empty collections and absent optionals are omitted

159

* from JSON output for compactness.

160

*/

161

@Target(ElementType.METHOD)

162

@Retention(RetentionPolicy.SOURCE)

163

@interface Json.ForceEmpty {}

164

```

165

166

**Usage Example:**

167

168

```java

169

import org.immutables.value.Value;

170

import org.immutables.value.Json;

171

import java.util.List;

172

import java.util.Optional;

173

import java.util.Map;

174

175

@Value.Immutable

176

@Json.Marshaled

177

public interface DataContainer {

178

String name();

179

180

@Json.ForceEmpty

181

List<String> items(); // Always include, even if empty

182

183

@Json.ForceEmpty

184

Optional<String> description(); // Always include, even if absent

185

186

Map<String, Object> metadata(); // Omitted if empty (default behavior)

187

}

188

189

// Empty collections and absent optionals are included when @Json.ForceEmpty

190

DataContainer container = ImmutableDataContainer.builder()

191

.name("test")

192

.build();

193

194

String json = DataContainerMarshaler.instance().toString(container);

195

// {"name":"test","items":[],"description":null}

196

// Note: metadata is omitted since it's empty and not marked @Json.ForceEmpty

197

```

198

199

### Import External Marshalers

200

201

Import static marshalers for use in generated marshaling code.

202

203

```java { .api }

204

/**

205

* Import static classes containing marshalers for use in generated code.

206

* Allows reuse of existing marshalers for complex nested types.

207

*/

208

@Target(ElementType.TYPE)

209

@Retention(RetentionPolicy.SOURCE)

210

@interface Json.Import {

211

/** Classes containing static marshalers to import */

212

Class<?>[] value();

213

}

214

```

215

216

**Usage Example:**

217

218

```java

219

import org.immutables.value.Value;

220

import org.immutables.value.Json;

221

import org.immutables.common.marshaling.Marshaler;

222

import org.immutables.common.marshaling.Marshaling;

223

import java.time.LocalDateTime;

224

225

// External marshaler class

226

public class CustomMarshalers {

227

public static final Marshaler<LocalDateTime> LOCAL_DATE_TIME =

228

Marshaling.fromString(LocalDateTime::toString, LocalDateTime::parse);

229

}

230

231

@Value.Immutable

232

@Json.Marshaled

233

@Json.Import(CustomMarshalers.class)

234

public interface Event {

235

String name();

236

LocalDateTime timestamp(); // Uses imported marshaler

237

String description();

238

}

239

240

// The generated marshaler uses CustomMarshalers.LOCAL_DATE_TIME

241

Event event = ImmutableEvent.builder()

242

.name("deployment")

243

.timestamp(LocalDateTime.now())

244

.description("Production deployment")

245

.build();

246

247

String json = EventMarshaler.instance().toString(event);

248

// {"name":"deployment","timestamp":"2023-01-01T10:30:00","description":"Production deployment"}

249

```

250

251

### Subclass Marshaling

252

253

Handle polymorphic types with expected subclasses.

254

255

```java { .api }

256

/**

257

* Specify expected subclasses for polymorphic marshaling.

258

* Generates marshaling code that can handle multiple implementations

259

* of an abstract type or interface.

260

*/

261

@Target(ElementType.TYPE)

262

@Retention(RetentionPolicy.SOURCE)

263

@interface Json.Subclasses {

264

/** Expected subclass types for polymorphic marshaling */

265

Class<?>[] value();

266

}

267

```

268

269

**Usage Example:**

270

271

```java

272

import org.immutables.value.Value;

273

import org.immutables.value.Json;

274

import java.util.List;

275

import java.util.Arrays;

276

import java.util.stream.Collectors;

277

278

// Base type

279

@Value.Immutable

280

@Json.Marshaled

281

@Json.Subclasses({Cat.class, Dog.class})

282

public interface Animal {

283

String name();

284

String type();

285

}

286

287

// Subclasses

288

@Value.Immutable

289

@Json.Marshaled

290

public interface Cat extends Animal {

291

@Value.Default

292

default String type() { return "cat"; }

293

boolean indoor();

294

}

295

296

@Value.Immutable

297

@Json.Marshaled

298

public interface Dog extends Animal {

299

@Value.Default

300

default String type() { return "dog"; }

301

String breed();

302

}

303

304

// Polymorphic marshaling

305

List<Animal> animals = Arrays.asList(

306

ImmutableCat.builder().name("Whiskers").indoor(true).build(),

307

ImmutableDog.builder().name("Rex").breed("Golden Retriever").build()

308

);

309

310

// AnimalMarshaler can handle both Cat and Dog instances

311

String json = animals.stream()

312

.map(animal -> AnimalMarshaler.instance().toString(animal))

313

.collect(Collectors.joining(",", "[", "]"));

314

```

315

316

## Generated Marshaler Classes

317

318

When `@Json.Marshaled` is applied, the annotation processor generates:

319

320

### Marshaler Class

321

322

- **Naming**: `{TypeName}Marshaler`

323

- **Singleton**: Static `instance()` method for singleton access

324

- **Thread-Safe**: Generated marshalers are thread-safe

325

326

### Serialization Methods

327

328

```java { .api }

329

// Generated marshaler methods

330

public final class PersonMarshaler extends Marshaler<Person> {

331

public static PersonMarshaler instance() { ... }

332

333

// String serialization

334

public String toString(Person instance) { ... }

335

336

// Writer serialization

337

public void toWriter(Person instance, Writer writer) throws IOException { ... }

338

339

// JsonGenerator serialization (Jackson integration)

340

public void toGenerator(Person instance, JsonGenerator generator) throws IOException { ... }

341

}

342

```

343

344

### Deserialization Methods

345

346

```java { .api }

347

// Generated unmarshaler methods

348

public final class PersonMarshaler extends Marshaler<Person> {

349

// String deserialization

350

public Person fromString(String json) throws IOException { ... }

351

352

// Reader deserialization

353

public Person fromReader(Reader reader) throws IOException { ... }

354

355

// JsonParser deserialization (Jackson integration)

356

public Person fromParser(JsonParser parser) throws IOException { ... }

357

}

358

```

359

360

## Integration with Marshaling Framework

361

362

The generated marshalers integrate with the `org.immutables.common.marshaling` framework:

363

364

```java

365

import org.immutables.common.marshaling.Marshaling;

366

367

// Create custom marshalers

368

Marshaler<LocalDate> dateMarshaler = Marshaling.fromString(

369

LocalDate::toString,

370

LocalDate::parse

371

);

372

373

// Combine with generated marshalers

374

Person person = PersonMarshaler.instance().fromString(jsonString);

375

```