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