0
# Type Handling and Mapping
1
2
Type-safe operations and object mapping capabilities for converting JSON data to specific Java types. JsonPath provides several mechanisms for handling generic types and custom object mapping.
3
4
## Capabilities
5
6
### Generic Type References
7
8
TypeRef class for handling generic types safely, preserving parameterized type information at runtime.
9
10
```java { .api }
11
/**
12
* Abstract class for specifying generic type information in JsonPath operations
13
* Used to preserve generic type parameters that would otherwise be lost due to type erasure
14
* @param <T> The target type with full generic information
15
*/
16
public abstract class TypeRef<T> implements Comparable<TypeRef<T>> {
17
/**
18
* Returns the parameterized type information
19
* @return Type representing the full generic type
20
*/
21
public Type getType();
22
23
/**
24
* Required by Comparable interface (prevents construction without type info)
25
* @param o Other TypeRef to compare with
26
* @return Comparison result (typically 0)
27
*/
28
public int compareTo(TypeRef<T> o);
29
}
30
```
31
32
**Usage Examples:**
33
34
```java
35
import com.jayway.jsonpath.TypeRef;
36
import com.jayway.jsonpath.JsonPath;
37
import java.util.List;
38
import java.util.Map;
39
40
String json = "{ \"users\": [{ \"name\": \"Alice\", \"age\": 30 }, { \"name\": \"Bob\", \"age\": 25 }] }";
41
42
// Create TypeRef for List<Map<String, Object>>
43
TypeRef<List<Map<String, Object>>> listTypeRef = new TypeRef<List<Map<String, Object>>>() {};
44
45
// Use with JsonPath reading
46
List<Map<String, Object>> users = JsonPath.read(json, "$.users", listTypeRef);
47
48
// Create TypeRef for nested generic types
49
TypeRef<Map<String, List<String>>> mapTypeRef = new TypeRef<Map<String, List<String>>>() {};
50
51
// TypeRef for custom classes with generics
52
TypeRef<List<User>> userListTypeRef = new TypeRef<List<User>>() {};
53
54
// Using with DocumentContext
55
DocumentContext context = JsonPath.parse(json);
56
List<Map<String, Object>> typedUsers = context.read("$.users", listTypeRef);
57
```
58
59
### Type-Safe Reading Operations
60
61
Methods for reading JSON data with automatic type conversion to specified Java types.
62
63
```java { .api }
64
// ReadContext interface methods for type-safe reading
65
public interface ReadContext {
66
/**
67
* Reads path with automatic mapping to specified class
68
* @param path JsonPath expression
69
* @param type Target class for mapping
70
* @param filters Optional predicates for filtering
71
* @return Result mapped to specified type
72
*/
73
<T> T read(String path, Class<T> type, Predicate... filters);
74
75
/**
76
* Reads compiled path with automatic mapping to specified class
77
* @param path Compiled JsonPath instance
78
* @param type Target class for mapping
79
* @return Result mapped to specified type
80
*/
81
<T> T read(JsonPath path, Class<T> type);
82
83
/**
84
* Reads compiled path with generic type reference
85
* @param path Compiled JsonPath instance
86
* @param typeRef Type reference for generic types
87
* @return Result mapped to specified generic type
88
*/
89
<T> T read(JsonPath path, TypeRef<T> typeRef);
90
91
/**
92
* Reads path with generic type reference
93
* @param path JsonPath expression
94
* @param typeRef Type reference for generic types
95
* @return Result mapped to specified generic type
96
*/
97
<T> T read(String path, TypeRef<T> typeRef);
98
}
99
100
// Static methods on JsonPath class
101
public class JsonPath {
102
/**
103
* Static read with type mapping (various overloads for different input sources)
104
*/
105
public static <T> T read(String json, String jsonPath, Class<T> type);
106
public static <T> T read(Object json, String jsonPath, Class<T> type);
107
public static <T> T read(File jsonFile, String jsonPath, Class<T> type) throws IOException;
108
public static <T> T read(InputStream stream, String jsonPath, Class<T> type) throws IOException;
109
}
110
```
111
112
**Usage Examples:**
113
114
```java
115
import com.jayway.jsonpath.JsonPath;
116
import com.jayway.jsonpath.DocumentContext;
117
import com.jayway.jsonpath.TypeRef;
118
import java.util.List;
119
import java.util.Map;
120
121
String json = "{ \"count\": 42, \"names\": [\"Alice\", \"Bob\"], \"user\": { \"name\": \"Charlie\", \"age\": 30 } }";
122
123
// Basic type-safe reading
124
Integer count = JsonPath.read(json, "$.count", Integer.class);
125
List<String> names = JsonPath.read(json, "$.names", List.class); // Note: loses generic info
126
127
// Using TypeRef for full type safety
128
TypeRef<List<String>> stringListType = new TypeRef<List<String>>() {};
129
List<String> typedNames = JsonPath.read(json, "$.names", stringListType);
130
131
// Reading complex objects
132
TypeRef<Map<String, Object>> mapType = new TypeRef<Map<String, Object>>() {};
133
Map<String, Object> user = JsonPath.read(json, "$.user", mapType);
134
135
// With DocumentContext
136
DocumentContext context = JsonPath.parse(json);
137
Integer contextCount = context.read("$.count", Integer.class);
138
List<String> contextNames = context.read("$.names", stringListType);
139
140
// Custom class mapping (requires appropriate MappingProvider)
141
public class User {
142
private String name;
143
private int age;
144
// constructors, getters, setters...
145
}
146
147
User userObject = context.read("$.user", User.class);
148
TypeRef<List<User>> userListType = new TypeRef<List<User>>() {};
149
```
150
151
### Value Transformation
152
153
MapFunction interface for transforming values during path operations.
154
155
```java { .api }
156
/**
157
* Interface for transforming values during JsonPath operations
158
* Used with map operations to convert values in-place
159
*/
160
public interface MapFunction {
161
/**
162
* Transforms the current value
163
* @param currentValue The value found at the path location
164
* @param configuration Configuration being used for the operation
165
* @return New value to replace the current value
166
*/
167
Object map(Object currentValue, Configuration configuration);
168
}
169
```
170
171
**Usage Examples:**
172
173
```java
174
import com.jayway.jsonpath.MapFunction;
175
import com.jayway.jsonpath.Configuration;
176
import com.jayway.jsonpath.JsonPath;
177
import com.jayway.jsonpath.DocumentContext;
178
179
String json = "{ \"prices\": [10.50, 15.75, 8.25], \"users\": [{ \"name\": \"alice\" }, { \"name\": \"bob\" }] }";
180
DocumentContext context = JsonPath.parse(json);
181
182
// Transform numeric values
183
MapFunction addTax = new MapFunction() {
184
public Object map(Object currentValue, Configuration configuration) {
185
if (currentValue instanceof Number) {
186
double price = ((Number) currentValue).doubleValue();
187
return price * 1.1; // Add 10% tax
188
}
189
return currentValue;
190
}
191
};
192
193
// Apply transformation to all prices
194
context.map("$.prices[*]", addTax);
195
196
// Transform string values
197
MapFunction capitalizeNames = new MapFunction() {
198
public Object map(Object currentValue, Configuration configuration) {
199
if (currentValue instanceof String) {
200
String name = (String) currentValue;
201
return name.substring(0, 1).toUpperCase() + name.substring(1);
202
}
203
return currentValue;
204
}
205
};
206
207
// Apply to user names
208
context.map("$.users[*].name", capitalizeNames);
209
210
// Lambda expressions (Java 8+)
211
context.map("$.prices[*]", (current, config) -> {
212
if (current instanceof Number) {
213
return ((Number) current).doubleValue() * 0.9; // 10% discount
214
}
215
return current;
216
});
217
218
// Get transformed JSON
219
String transformedJson = context.jsonString();
220
```
221
222
### Mapping Provider Interface
223
224
SPI interface for implementing custom object mapping strategies.
225
226
```java { .api }
227
/**
228
* Service Provider Interface for object type mapping
229
* Implementations handle conversion between JSON structures and Java objects
230
*/
231
public interface MappingProvider {
232
/**
233
* Maps source object to target class
234
* @param source Source object to map from
235
* @param targetType Target class to map to
236
* @param configuration Current configuration
237
* @return Mapped object of target type
238
* @throws MappingException If mapping fails
239
*/
240
<T> T map(Object source, Class<T> targetType, Configuration configuration);
241
242
/**
243
* Maps source object to target type using TypeRef
244
* @param source Source object to map from
245
* @param targetType Target type reference with generic information
246
* @param configuration Current configuration
247
* @return Mapped object of target type
248
* @throws MappingException If mapping fails
249
*/
250
<T> T map(Object source, TypeRef<T> targetType, Configuration configuration);
251
}
252
253
/**
254
* Exception thrown when mapping operations fail
255
*/
256
public class MappingException extends RuntimeException {
257
public MappingException(String message);
258
public MappingException(String message, Throwable cause);
259
}
260
```
261
262
**Usage Examples:**
263
264
```java
265
import com.jayway.jsonpath.spi.mapper.MappingProvider;
266
import com.jayway.jsonpath.spi.mapper.MappingException;
267
import com.jayway.jsonpath.Configuration;
268
import com.jayway.jsonpath.TypeRef;
269
270
// Custom mapping provider implementation
271
public class CustomMappingProvider implements MappingProvider {
272
@Override
273
public <T> T map(Object source, Class<T> targetType, Configuration configuration) {
274
if (targetType == String.class && source instanceof Number) {
275
return targetType.cast(source.toString());
276
}
277
if (targetType == Integer.class && source instanceof String) {
278
try {
279
return targetType.cast(Integer.parseInt((String) source));
280
} catch (NumberFormatException e) {
281
throw new MappingException("Cannot convert string to integer: " + source, e);
282
}
283
}
284
// Add more custom mapping logic...
285
throw new MappingException("Cannot map " + source.getClass() + " to " + targetType);
286
}
287
288
@Override
289
public <T> T map(Object source, TypeRef<T> targetType, Configuration configuration) {
290
// Handle generic type mapping
291
Type type = targetType.getType();
292
// Implementation depends on the specific generic type...
293
throw new MappingException("Generic type mapping not implemented");
294
}
295
}
296
297
// Use custom mapping provider
298
Configuration config = Configuration.builder()
299
.mappingProvider(new CustomMappingProvider())
300
.build();
301
302
// Now reads will use the custom mapping logic
303
DocumentContext context = JsonPath.using(config).parse(json);
304
```
305
306
### Built-in Mapping Providers
307
308
JsonPath includes several built-in mapping providers for popular JSON libraries.
309
310
```java { .api }
311
// Available mapping providers (require corresponding JSON library dependencies)
312
313
// Gson-based mapping
314
com.jayway.jsonpath.spi.mapper.GsonMappingProvider
315
316
// Jackson-based mapping (implicit in JacksonJsonProvider)
317
// Uses Jackson's ObjectMapper for type conversion
318
319
// JSON Smart mapping
320
com.jayway.jsonpath.spi.mapper.JsonSmartMappingProvider
321
322
// Tapestry JSON mapping
323
com.jayway.jsonpath.spi.mapper.TapestryMappingProvider
324
```
325
326
**Usage Examples:**
327
328
```java
329
import com.jayway.jsonpath.Configuration;
330
import com.jayway.jsonpath.spi.json.GsonJsonProvider;
331
import com.jayway.jsonpath.spi.mapper.GsonMappingProvider;
332
import com.jayway.jsonpath.JsonPath;
333
334
// Using Gson for both parsing and mapping
335
Configuration gsonConfig = Configuration.builder()
336
.jsonProvider(new GsonJsonProvider())
337
.mappingProvider(new GsonMappingProvider())
338
.build();
339
340
// Custom objects will be mapped using Gson's capabilities
341
DocumentContext context = JsonPath.using(gsonConfig).parse(json);
342
343
// This will use Gson's type adapter system
344
User user = context.read("$.user", User.class);
345
List<User> users = context.read("$.users", new TypeRef<List<User>>() {});
346
```
347
348
### Type Conversion Examples
349
350
Common patterns for working with different data types in JsonPath operations.
351
352
**Working with Collections:**
353
354
```java
355
import com.jayway.jsonpath.JsonPath;
356
import com.jayway.jsonpath.TypeRef;
357
import java.util.*;
358
359
String json = "{ \"data\": [1, 2, 3, 4, 5] }";
360
361
// Read as generic List (loses type information)
362
List list = JsonPath.read(json, "$.data");
363
364
// Read as typed List
365
TypeRef<List<Integer>> intListType = new TypeRef<List<Integer>>() {};
366
List<Integer> integers = JsonPath.read(json, "$.data", intListType);
367
368
// Read as Set
369
TypeRef<Set<Integer>> intSetType = new TypeRef<Set<Integer>>() {};
370
Set<Integer> integerSet = JsonPath.read(json, "$.data", intSetType);
371
```
372
373
**Working with Maps:**
374
375
```java
376
String json = "{ \"metadata\": { \"version\": \"1.0\", \"author\": \"System\" } }";
377
378
// Read as generic Map
379
Map map = JsonPath.read(json, "$.metadata");
380
381
// Read as typed Map
382
TypeRef<Map<String, String>> stringMapType = new TypeRef<Map<String, String>>() {};
383
Map<String, String> metadata = JsonPath.read(json, "$.metadata", stringMapType);
384
```
385
386
**Working with Custom Objects:**
387
388
```java
389
public class Product {
390
private String name;
391
private double price;
392
private List<String> tags;
393
// constructors, getters, setters...
394
}
395
396
String json = "{ \"product\": { \"name\": \"Laptop\", \"price\": 999.99, \"tags\": [\"electronics\", \"computers\"] } }";
397
398
// Direct object mapping (requires appropriate MappingProvider)
399
Product product = JsonPath.read(json, "$.product", Product.class);
400
401
// List of custom objects
402
String listJson = "{ \"products\": [{ \"name\": \"Laptop\", \"price\": 999.99 }] }";
403
TypeRef<List<Product>> productListType = new TypeRef<List<Product>>() {};
404
List<Product> products = JsonPath.read(listJson, "$.products", productListType);
405
```