or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdformatting.mdinclusion-exclusion.mdindex.mdobject-creation.mdobject-identity.mdobject-structure.mdpolymorphic-types.mdproperty-control.md

object-creation.mddocs/

0

# Object Creation and Injection

1

2

Control how objects are created during deserialization, including constructor/factory method selection and dependency injection.

3

4

## Capabilities

5

6

### JsonCreator

7

8

Mark constructor or factory method for object creation during deserialization.

9

10

```java { .api }

11

/**

12

* Mark constructor or factory method for deserialization

13

* @param mode Creator binding mode controlling how parameters are bound

14

*/

15

@JsonCreator(JsonCreator.Mode mode = JsonCreator.Mode.DEFAULT)

16

public @interface JsonCreator {

17

18

enum Mode {

19

/** Default mode - auto-detect binding based on parameter annotations */

20

DEFAULT,

21

22

/** Delegating mode - single unnanotated parameter receives full JSON */

23

DELEGATING,

24

25

/** Properties mode - parameters bound to JSON properties by name */

26

PROPERTIES,

27

28

/** Disabled - do not use this creator */

29

DISABLED

30

}

31

}

32

```

33

34

**Usage Examples:**

35

36

```java

37

public class Person {

38

private final String name;

39

private final int age;

40

private final String email;

41

42

// Properties-based creator (default mode)

43

@JsonCreator

44

public Person(@JsonProperty("name") String name,

45

@JsonProperty("age") int age,

46

@JsonProperty("email") String email) {

47

this.name = name;

48

this.age = age;

49

this.email = email;

50

}

51

}

52

53

// Delegating creator example

54

public class Wrapper {

55

private final Map<String, Object> data;

56

57

@JsonCreator(mode = JsonCreator.Mode.DELEGATING)

58

public Wrapper(Map<String, Object> data) {

59

this.data = new HashMap<>(data);

60

}

61

}

62

63

// Factory method creator

64

public class Product {

65

private final String name;

66

private final BigDecimal price;

67

68

private Product(String name, BigDecimal price) {

69

this.name = name;

70

this.price = price;

71

}

72

73

@JsonCreator

74

public static Product create(@JsonProperty("productName") String name,

75

@JsonProperty("price") String priceStr) {

76

return new Product(name, new BigDecimal(priceStr));

77

}

78

}

79

```

80

81

### JacksonInject

82

83

Inject values from ObjectReader/ObjectMapper context during deserialization.

84

85

```java { .api }

86

/**

87

* Inject values from deserialization context

88

* @param value Injection identifier (default: use property/parameter name)

89

* @param useInput Whether to use input value if available in JSON

90

*/

91

@JacksonInject(String value = "",

92

OptBoolean useInput = OptBoolean.DEFAULT)

93

public @interface JacksonInject;

94

```

95

96

**Usage Examples:**

97

98

```java

99

public class AuditableEntity {

100

private String data;

101

102

@JacksonInject

103

private String createdBy; // Injected from context

104

105

@JacksonInject("timestamp")

106

private LocalDateTime createdAt; // Injected with specific key

107

108

@JacksonInject(useInput = OptBoolean.FALSE)

109

private String tenantId; // Always injected, never from JSON

110

111

@JsonCreator

112

public AuditableEntity(@JsonProperty("data") String data,

113

@JacksonInject("userId") String userId) {

114

this.data = data;

115

this.createdBy = userId;

116

}

117

}

118

119

// Usage with ObjectMapper:

120

ObjectMapper mapper = new ObjectMapper();

121

InjectableValues inject = new InjectableValues.Std()

122

.addValue("userId", "john.doe")

123

.addValue("timestamp", LocalDateTime.now())

124

.addValue("tenantId", "tenant-123");

125

126

AuditableEntity entity = mapper.reader(inject)

127

.readValue(json, AuditableEntity.class);

128

```

129

130

### JsonMerge

131

132

Enable merging of property values during deserialization instead of replacement.

133

134

```java { .api }

135

/**

136

* Enable property value merging during deserialization

137

* @param value Whether to enable merging (default: true)

138

*/

139

@JsonMerge(OptBoolean value = OptBoolean.TRUE)

140

public @interface JsonMerge;

141

```

142

143

**Usage Examples:**

144

145

```java

146

public class Configuration {

147

@JsonMerge

148

private Map<String, String> settings = new HashMap<>();

149

150

@JsonMerge

151

private List<String> features = new ArrayList<>();

152

153

@JsonMerge

154

private DatabaseConfig database = new DatabaseConfig();

155

156

// Getters and setters

157

}

158

159

public class DatabaseConfig {

160

private String host = "localhost";

161

private int port = 5432;

162

private String database = "myapp";

163

164

// Getters and setters

165

}

166

167

// Original object: {"settings": {"theme": "dark"}, "features": ["auth"], "database": {"host": "localhost", "port": 5432}}

168

// JSON update: {"settings": {"language": "en"}, "features": ["logging"], "database": {"port": 3306}}

169

// Result: {"settings": {"theme": "dark", "language": "en"}, "features": ["auth", "logging"], "database": {"host": "localhost", "port": 3306}}

170

```

171

172

## Advanced Creation Patterns

173

174

### Multiple Constructors

175

176

```java

177

public class User {

178

private String username;

179

private String email;

180

private String fullName;

181

182

// Primary creator for full JSON objects

183

@JsonCreator

184

public User(@JsonProperty("username") String username,

185

@JsonProperty("email") String email,

186

@JsonProperty("fullName") String fullName) {

187

this.username = username;

188

this.email = email;

189

this.fullName = fullName;

190

}

191

192

// Alternative creator for minimal objects

193

@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)

194

public static User minimal(@JsonProperty("username") String username) {

195

return new User(username, null, null);

196

}

197

}

198

```

199

200

### Builder Pattern Integration

201

202

```java

203

public class ComplexObject {

204

private final String name;

205

private final List<String> tags;

206

private final Map<String, Object> metadata;

207

208

private ComplexObject(Builder builder) {

209

this.name = builder.name;

210

this.tags = builder.tags;

211

this.metadata = builder.metadata;

212

}

213

214

@JsonCreator

215

public static ComplexObject create(@JsonProperty("name") String name,

216

@JsonProperty("tags") List<String> tags,

217

@JsonProperty("metadata") Map<String, Object> metadata) {

218

return new Builder()

219

.name(name)

220

.tags(tags)

221

.metadata(metadata)

222

.build();

223

}

224

225

public static class Builder {

226

private String name;

227

private List<String> tags = new ArrayList<>();

228

private Map<String, Object> metadata = new HashMap<>();

229

230

public Builder name(String name) {

231

this.name = name;

232

return this;

233

}

234

235

public Builder tags(List<String> tags) {

236

this.tags = tags != null ? new ArrayList<>(tags) : new ArrayList<>();

237

return this;

238

}

239

240

public Builder metadata(Map<String, Object> metadata) {

241

this.metadata = metadata != null ? new HashMap<>(metadata) : new HashMap<>();

242

return this;

243

}

244

245

public ComplexObject build() {

246

return new ComplexObject(this);

247

}

248

}

249

}

250

```

251

252

### Context-aware Creation

253

254

```java

255

public class SecureDocument {

256

private String content;

257

private String owner;

258

private LocalDateTime createdAt;

259

private String ipAddress;

260

261

@JsonCreator

262

public SecureDocument(@JsonProperty("content") String content,

263

@JacksonInject("currentUser") String owner,

264

@JacksonInject("requestTime") LocalDateTime createdAt,

265

@JacksonInject("clientIp") String ipAddress) {

266

this.content = content;

267

this.owner = owner;

268

this.createdAt = createdAt;

269

this.ipAddress = ipAddress;

270

}

271

}

272

273

// Context setup:

274

InjectableValues context = new InjectableValues.Std()

275

.addValue("currentUser", getCurrentUser())

276

.addValue("requestTime", LocalDateTime.now())

277

.addValue("clientIp", getClientIpAddress());

278

```

279

280

### Validation during Creation

281

282

```java

283

public class ValidatedUser {

284

private final String email;

285

private final int age;

286

287

@JsonCreator

288

public ValidatedUser(@JsonProperty("email") String email,

289

@JsonProperty("age") int age) {

290

if (email == null || !email.contains("@")) {

291

throw new IllegalArgumentException("Invalid email format");

292

}

293

if (age < 0 || age > 150) {

294

throw new IllegalArgumentException("Invalid age: " + age);

295

}

296

297

this.email = email;

298

this.age = age;

299

}

300

}

301

```

302

303

### JacksonInject.Value

304

305

Configuration class for programmatic injection control.

306

307

```java { .api }

308

/**

309

* Value class for JacksonInject configuration

310

*/

311

public static class JacksonInject.Value implements JacksonAnnotationValue<JacksonInject> {

312

public static final JacksonInject.Value EMPTY;

313

314

public static JacksonInject.Value construct(Object id, Boolean useInput);

315

public static JacksonInject.Value forId(Object id);

316

317

public Object getId();

318

public Boolean getUseInput();

319

320

public JacksonInject.Value withId(Object id);

321

public JacksonInject.Value withUseInput(Boolean useInput);

322

}

323

```