Using JAX-RS (Jersey) to build a JPA/JAXB-backed JSON REST API
was published on December 25th, 2008 and is listed in Java , Technology
Building applications for deployment to the web has evolved over the last several years to be focused on dynamic behavior, separation of model/view/controller, and simplified but scalable configuration and deployment. From a performance, tools and library perspective I’m still highly biased to development in Java over more up-and-coming languages. However, much has been learned in the Java community from the better frameworks like Rails and those lessons should not be ignored.
I’ve been looking for a while though to find that perfect combination of frameworks and libraries that would give me the expressive power that I want for building web applications. There have been many contenders from JRuby on Rails , to Grails , to Seam and even just writing everything myself. Ultimately, I believe in the DRY principle (like Rails), though I don’t think many frameworks go far enough when dealing with the database. When you are building a web application it is rare that you are going to change what database you are using. In fact, the majority of your scaling architecture is likely highly dependent on how you store your data. This is why I prefer an application framework that allows me to start with the database and construct my application’s data object model from it.
So what are my acceptance criteria for this über-framework?
- Great object-relational mapping tool that works well with MySQL + PostgreSQL
- Excellent support for consuming and producing XML and JSON that integrates with the well with the data objects that the ORM tool uses
- Supports writing MVC applications naturally
- Support for building REST APIs with arbitrary URL mapping to service parameters
- High straight-line performance with the ability to scale up servers
- Great defaults that make configuration mostly unnecessary with simple deployment
- State-of-the-art IDE support . I don’t like to type anymore nor memorize APIs.
- Suitable for quick prototyping and production applications
- Support for templating views of any output type (HTML, XML, etc)
- Easy to unit and integration test
- Open source
Certainly a high barrier but I think I have finally found one that is a very strong contender. Amazingly, it is even coming out of the JSR standards process with a nice layer of open source on top of it. JSR-311 was stated to develop an API for providing support for RESTful Web Services in the Java Platform. Not only does it do that nicely but it also has the right hooks for simple dependency injection, orthogonal to JPA (my favorite ORM), support for both XML and JSON natively, and except in unusual circumstances very DRY.
Because it is in Java and works well with JPA it satisfies a large number of my requirements before we even look at what it offers. Another aspect of it that didn’t make the above list is that the production quality reference implementation is available as a couple of dependencies in Maven making it very easy to work with. It also works well deployed within lightweight containers like Grizzly , heavier ones like Tomcat and Glassfish , and the REST APIs it creates can even be directly tested without any container at all. There are some things that Jersey supports that are non-standard that I think are excellent additions to the framework and should likely make it into future versions including support for templating (like JSP and Freemarker) that help it satisfy my requirements.
To give you an example of how terse the API can be, here is the simplest example that includes deployment as an operating web service:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175public class Main {
@Path ( "/helloworld" )
public static class HelloWorldResource {
@GET
@Produces ( "text/plain" )
public String getClichedMessage() {
return "Hello World" ;
}
}
public static void main(String[] args) throws IOException {
Map<String, String> initParams = new HashMap<String, String>();
initParams.put( "com.sun.jersey.config.property.packages" , "com.sun.jersey.samples.helloworld" );
System. out .println( "Starting grizzly..." );
URI uri = UriBuilder. fromUri ( "http://localhost/" ).port( 9998 ).build();
SelectorThread threadSelector = GrizzlyWebContainerFactory. create (uri, initParams);
System. out .println(String. format ( "Try out %shelloworld /n Hit enter to stop it..." , uri));
System. in . read ();
threadSelector.stopEndpoint();
}
}
The @Path annotation lets you use URI path templates to specify the matching paths and path parameters to your REST service. You can produce any set of content-types and content negotiation will be done for you based on the incoming request. Exceptions can be mapped directly to error responses. Query, Matrix, Path, Header and Cookie parameters are all supported and automatically injected based on annotations. Here is a more sophisticated example from an application I am writing:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101@GET
@Produces ( "application/json" )
@Path ( "/network/{id: [0-9]+}/{nid}" )
public User getUserByNetworkId( @PathParam ( "id" ) int id, @PathParam ( "nid" ) String networkId) {
Query q = em .createQuery( " SELECT u FROM User u WHERE u.networkId = :id AND u.networkUserId = :nid " );
q.setParameter( "id" , id);
q.setParameter( "nid" , networkId);
return (User) q.getSingleResult();
}
In this example we are implementing a GET request with two path parameters, id and uid. They are automatically passed into the method on execution and then I use them in a JPA statement. EntityNotFoundException is actually mapped to a 404 but I don’t need to deal with that in the method itself. PUTs and POSTs are similarly straight-forward. This method creates a new user:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73@PUT
@Consumes ( "application/json" )
@Produces ( "application/json" )
@Path ( "/create" )
public User createUser(User user) {
user.setNetwork( em .getReference(Network. class , user.getNetworkId()));
em .persist(user);
em .refresh(user);
return user;
}
All very declarative and readable. And works great with JPA objects that also happen to be JAXB objects. Notice that in those examples I am returning JSON but I don’t need to explicitly convert my objects. All that is handled by built in message readers and writers (which can be extended if need be).
One thing that I will note is that after struggling with both OpenJPA (less than ideal support for the standard) and Hibernate (some very odd runtime class munging) I settled with Toplink-Essentials (the open-source version of Oracle Toplink). It is much more robust than OpenJPA and is much cleaner at runtime than Hibernate. Finally here is what a typical Maven dependencies look like for creating a Jersey-based web application:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573< repositories >
< repository >
< id > maven2-repository.dev.java.net </ id >
< name > Java.net Repository for Maven </ name >
< url > http://download.java.net/maven/2 </ url >
</ repository >
< repository >
< id > java.net </ id >
< url > http://download.java.net/maven/1 </ url >
< layout > legacy </ layout >
</ repository >
</ repositories >
< dependencies >
< dependency >
< groupId > com.sun.jersey </ groupId >
< artifactId > jersey-server </ artifactId >
< version > 1.0.1 </ version >
</ dependency >
< dependency >
< groupId > com.sun.jersey </ groupId >
< artifactId > jersey-json </ artifactId >
< version > 1.0.1 </ version >
</ dependency >
< dependency >
< groupId > com.sun.jersey </ groupId >
< artifactId > jersey-atom </ artifactId >
< version > 1.0.1 </ version >
</ dependency >
< dependency >
< groupId > mysql </ groupId >
< artifactId > mysql-connector-java </ artifactId >
< version > 5.1.6 </ version >
</ dependency >
< dependency >
< groupId > toplink.essentials </ groupId >
< artifactId > toplink-essentials </ artifactId >
< version > 2.1-60 </ version >
</ dependency >
</ dependencies >
I was very impressed with how little it took to get going, especially with IntelliJ 8.0 ’s awesome support for reading pom.xml files. So now I’m a few days into building the application I set out to build and things are going great. I haven’t hit any roadblocks so far and I’ve planned pretty far out already so I don’t expect to. Though, with Jersey’s extensibility API, I think that if I do run into anything I have a great escape valve for augmenting the framework. I’m not associated with Jersey or the JSR-311 specification but I might have to join in the fun. This framework looks like it will have long legs in the Java community.
最后
以上就是如意画笔最近收集整理的关于Using JAX-RS (Jersey) to build a JPA/JAXB-backed JSON REST API Using JAX-RS (Jersey) to build a JPA/JAXB-backed JSON REST API的全部内容,更多相关Using内容请搜索靠谱客的其他文章。
发表评论 取消回复