forked from spring-projects/spring-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
/
validation.xml
1931 lines (1559 loc) · 86.9 KB
/
validation.xml
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
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?>
<chapter xml:id="validation"
xmlns="http://docbook.org/ns/docbook" version="5.0"
xmlns:xl="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
<title>Validation, Data Binding, and Type Conversion</title>
<section xml:id="validation-introduction">
<title>Introduction</title>
<sidebar xml:id="validation-beanvalidation-vs-spring-validation">
<title>JSR-303 Bean Validation</title>
<para>The Spring Framework supports JSR-303 Bean Validation adapting
it to Spring's <interfacename>Validator</interfacename> interface.</para>
<para>An application can choose to enable JSR-303 Bean Validation once globally,
as described in <xref linkend="validation-beanvalidation" />, and use it
exclusively for all validation needs.</para>
<para>An application can also register
additional Spring <interfacename>Validator</interfacename> instances
per <classname>DataBinder</classname> instance, as described in
<xref linkend="validation-binder" />. This may be useful for
plugging in validation logic without the use of annotations.</para>
</sidebar>
<para>There are pros and cons for considering validation as business logic,
and Spring offers a design for validation (and data binding) that does not
exclude either one of them. Specifically validation should not be tied to
the web tier, should be easy to localize and it should be possible to plug
in any validator available. Considering the above, Spring has come up with
a <interfacename>Validator</interfacename> interface that is both basic
ands eminently usable in every layer of an application. </para>
<para>Data binding is useful for allowing user input to be dynamically bound
to the domain model of an application (or whatever objects you use to
process user input). Spring provides the so-called
<interfacename>DataBinder</interfacename> to do exactly that. The
<interfacename>Validator</interfacename> and the
<interfacename>DataBinder</interfacename> make up the
<literal>validation</literal> package, which is primarily used in but not
limited to the MVC framework. </para>
<para>The <interfacename>BeanWrapper</interfacename> is a fundamental
concept in the Spring Framework and is used in a lot of places. However,
you probably will not have the need to use the
<interfacename>BeanWrapper</interfacename> directly. Because this is
reference documentation however, we felt that some explanation might be in
order. We will explain the <interfacename>BeanWrapper</interfacename> in
this chapter since, if you were going to use it at all, you would most
likely do so when trying to bind data to objects.</para>
<para>Spring's DataBinder and the lower-level BeanWrapper both use
PropertyEditors to parse and format property values. The
<interfacename>PropertyEditor</interfacename> concept is part of the
JavaBeans specification, and is also explained in this chapter. Spring 3
introduces a "core.convert" package that provides a general type
conversion facility, as well as a higher-level "format" package for
formatting UI field values. These new packages may be used as simpler
alternatives to PropertyEditors, and will also be discussed in this
chapter.</para>
</section>
<section xml:id="validator">
<title>Validation using Spring's <interfacename>Validator</interfacename>
interface</title>
<para>Spring features a <interfacename>Validator</interfacename> interface
that you can use to validate objects. The
<interfacename>Validator</interfacename> interface works using an
<interfacename>Errors</interfacename> object so that while validating,
validators can report validation failures to the
<interfacename>Errors</interfacename> object.</para>
<para>Let's consider a small data object:</para>
<programlisting language="java"><![CDATA[public class Person {
private String name;
private int age;
]]><lineannotation>// the usual getters and setters...</lineannotation><![CDATA[
}]]></programlisting>
<para>We're going to provide validation behavior for the
<classname>Person</classname> class by implementing the following two
methods of the
<interfacename>org.springframework.validation.Validator</interfacename>
interface: <itemizedlist spacing="compact">
<listitem>
<para><methodname>supports(Class)</methodname> - Can this
<interfacename>Validator</interfacename> validate instances of the
supplied <classname>Class</classname>?</para>
</listitem>
<listitem>
<para><methodname>validate(Object,
org.springframework.validation.Errors)</methodname> - validates the
given object and in case of validation errors, registers those with
the given <interfacename>Errors</interfacename> object</para>
</listitem>
</itemizedlist> </para>
<para> Implementing a <interfacename>Validator</interfacename> is fairly
straightforward, especially when you know of the
<classname>ValidationUtils</classname> helper class that the Spring
Framework also provides.</para>
<programlisting language="java"><![CDATA[public class PersonValidator implements Validator {
]]><lineannotation>/**
* This Validator validates *just* Person instances
*/</lineannotation><![CDATA[
public boolean supports(Class clazz) {
return Person.class.equals(clazz);
}
public void validate(Object obj, Errors e) {
ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
Person p = (Person) obj;
if (p.getAge() < 0) {
e.rejectValue("age", "negativevalue");
} else if (p.getAge() > 110) {
e.rejectValue("age", "too.darn.old");
}
}
}]]></programlisting>
<para>As you can see, the <literal>static</literal>
<methodname>rejectIfEmpty(..)</methodname> method on the
<classname>ValidationUtils</classname> class is used to reject the
<literal>'name'</literal> property if it is <literal>null</literal> or the
empty string. Have a look at the Javadoc for the
<classname>ValidationUtils</classname> class to see what functionality it
provides besides the example shown previously.</para>
<para>While it is certainly possible to implement a single
<interfacename>Validator</interfacename> class to validate each of the
nested objects in a rich object, it may be better to encapsulate the
validation logic for each nested class of object in its own
<interfacename>Validator</interfacename> implementation. A simple example
of a <emphasis>'rich'</emphasis> object would be a
<classname>Customer</classname> that is composed of two
<classname>String</classname> properties (a first and second name) and a
complex <classname>Address</classname> object.
<classname>Address</classname> objects may be used independently of
<classname>Customer</classname> objects, and so a distinct
<classname>AddressValidator</classname> has been implemented. If you want
your <classname>CustomerValidator</classname> to reuse the logic contained
within the <classname>AddressValidator</classname> class without resorting
to copy-and-paste, you can dependency-inject or instantiate an
<classname>AddressValidator</classname> within your
<classname>CustomerValidator</classname>, and use it like so:</para>
<programlisting language="java"><![CDATA[public class CustomerValidator implements Validator {
private final Validator addressValidator;
public CustomerValidator(Validator addressValidator) {
if (addressValidator == null) {
throw new IllegalArgumentException(
"The supplied [Validator] is required and must not be null.");
}
if (!addressValidator.supports(Address.class)) {
throw new IllegalArgumentException(
"The supplied [Validator] must support the validation of [Address] instances.");
}
this.addressValidator = addressValidator;
}
]]><lineannotation>/**
* This Validator validates Customer instances, and any subclasses of Customer too
*/</lineannotation><![CDATA[
public boolean supports(Class clazz) {
return Customer.class.isAssignableFrom(clazz);
}
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required");
Customer customer = (Customer) target;
try {
errors.pushNestedPath("address");
ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors);
} finally {
errors.popNestedPath();
}
}
}]]></programlisting>
<para>Validation errors are reported to the
<interfacename>Errors</interfacename> object passed to the validator. In
case of Spring Web MVC you can use <literal><spring:bind/></literal>
tag to inspect the error messages, but of course you can also inspect the
errors object yourself. More information about the methods it offers can
be found from the Javadoc.</para>
</section>
<section xml:id="validation-conversion">
<title>Resolving codes to error messages</title>
<para>We've talked about databinding and validation. Outputting messages
corresponding to validation errors is the last thing we need to discuss.
In the example we've shown above, we rejected the <literal>name</literal>
and the <literal>age</literal> field. If we're going to output the error
messages by using a <interfacename>MessageSource</interfacename>, we will
do so using the error code we've given when rejecting the field ('name'
and 'age' in this case). When you call (either directly, or indirectly,
using for example the <classname>ValidationUtils</classname> class)
<literal>rejectValue</literal> or one of the other
<literal>reject</literal> methods from the
<interfacename>Errors</interfacename> interface, the underlying
implementation will not only register the code you've passed in, but also
a number of additional error codes. What error codes it registers is
determined by the <interfacename>MessageCodesResolver</interfacename> that
is used. By default, the
<classname>DefaultMessageCodesResolver</classname> is used, which for
example not only registers a message with the code you gave, but also
messages that include the field name you passed to the reject method. So
in case you reject a field using <literal>rejectValue("age",
"too.darn.old")</literal>, apart from the <literal>too.darn.old</literal>
code, Spring will also register <literal>too.darn.old.age</literal> and
<literal>too.darn.old.age.int</literal> (so the first will include the
field name and the second will include the type of the field); this is
done as a convenience to aid developers in targeting error messages and
suchlike.</para>
<para>More information on the
<interfacename>MessageCodesResolver</interfacename> and the default
strategy can be found online with the Javadocs for <link
xl:href="http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/validation/MessageCodesResolver.html"
>MessageCodesResolver</link> and <link
xl:href="http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/validation/DefaultMessageCodesResolver.html"
>DefaultMessageCodesResolver</link> respectively.</para>
</section>
<section xml:id="beans-beans">
<title>Bean manipulation and the
<interfacename>BeanWrapper</interfacename></title>
<para>The <literal>org.springframework.beans</literal> package adheres to
the JavaBeans standard provided by Sun. A JavaBean is simply a class with
a default no-argument constructor, which follows a naming convention where
(by way of an example) a property named <literal>bingoMadness</literal>
would have a setter method <methodname>setBingoMadness(..)</methodname>
and a getter method <methodname>getBingoMadness()</methodname>. For more
information about JavaBeans and the specification, please refer to Sun's
website ( <link xl:href="http://java.sun.com/products/javabeans/"
>java.sun.com/products/javabeans</link>).</para>
<para>One quite important class in the beans package is the
<interfacename>BeanWrapper</interfacename> interface and its corresponding
implementation (<classname>BeanWrapperImpl</classname>). As quoted from
the Javadoc, the <interfacename>BeanWrapper</interfacename> offers
functionality to set and get property values (individually or in bulk),
get property descriptors, and to query properties to determine if they are
readable or writable. Also, the <interfacename>BeanWrapper</interfacename>
offers support for nested properties, enabling the setting of properties
on sub-properties to an unlimited depth. Then, the
<interfacename>BeanWrapper</interfacename> supports the ability to add
standard JavaBeans <interfacename>PropertyChangeListeners</interfacename>
and <interfacename>VetoableChangeListeners</interfacename>, without the
need for supporting code in the target class. Last but not least, the
<interfacename>BeanWrapper</interfacename> provides support for the
setting of indexed properties. The
<interfacename>BeanWrapper</interfacename> usually isn't used by
application code directly, but by the
<interfacename>DataBinder</interfacename> and the
<interfacename>BeanFactory</interfacename>.</para>
<para>The way the <interfacename>BeanWrapper</interfacename> works is partly
indicated by its name: <emphasis>it wraps a bean</emphasis> to perform
actions on that bean, like setting and retrieving properties.</para>
<section xml:id="beans-beans-conventions">
<title>Setting and getting basic and nested properties</title>
<para>Setting and getting properties is done using the
<literal>setPropertyValue(s)</literal> and
<literal>getPropertyValue(s)</literal> methods that both come with a
couple of overloaded variants. They're all described in more detail in
the Javadoc Spring comes with. What's important to know is that there
are a couple of conventions for indicating properties of an object. A
couple of examples:</para>
<table xml:id="beans-beans-conventions-properties-tbl">
<title>Examples of properties</title>
<tgroup cols="2">
<colspec colname="c1" colwidth="1*"/>
<colspec colname="c2" colwidth="3*"/>
<thead>
<row>
<entry>Expression</entry>
<entry>Explanation</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>name</literal></entry>
<entry>Indicates the property <literal>name</literal>
corresponding to the methods <methodname>getName()</methodname>
or <methodname>isName()</methodname> and
<methodname>setName(..)</methodname></entry>
</row>
<row>
<entry><literal>account.name</literal></entry>
<entry>Indicates the nested property <literal>name</literal> of
the property <literal>account</literal> corresponding e.g. to
the methods <literal>getAccount().setName()</literal> or
<literal>getAccount().getName()</literal></entry>
</row>
<row>
<entry><literal>account[2]</literal></entry>
<entry>Indicates the <emphasis>third</emphasis> element of the
indexed property <literal>account</literal>. Indexed properties
can be of type <literal>array</literal>, <literal>list</literal>
or other <emphasis>naturally ordered</emphasis>
collection</entry>
</row>
<row>
<entry><literal>account[COMPANYNAME]</literal></entry>
<entry>Indicates the value of the map entry indexed by the key
<emphasis>COMPANYNAME</emphasis> of the Map property
<literal>account</literal></entry>
</row>
</tbody>
</tgroup>
</table>
<para>Below you'll find some examples of working with the
<interfacename>BeanWrapper</interfacename> to get and set
properties.</para>
<para><emphasis>(This next section is not vitally important to you if
you're not planning to work with the
<interfacename>BeanWrapper</interfacename> directly. If you're just
using the <interfacename>DataBinder</interfacename> and the
<interfacename>BeanFactory</interfacename> and their out-of-the-box
implementation, you should skip ahead to the section about
<interfacename>PropertyEditors</interfacename>.)</emphasis></para>
<para>Consider the following two classes:</para>
<programlisting language="java"><![CDATA[public class Company {
private String name;
private Employee managingDirector;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Employee getManagingDirector() {
return this.managingDirector;
}
public void setManagingDirector(Employee managingDirector) {
this.managingDirector = managingDirector;
}
}]]></programlisting>
<programlisting language="java"><![CDATA[public class Employee {
private String name;
private float salary;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public float getSalary() {
return salary;
}
public void setSalary(float salary) {
this.salary = salary;
}
}]]></programlisting>
<para>The following code snippets show some examples of how to retrieve
and manipulate some of the properties of instantiated
<literal>Companies</literal> and <literal>Employees</literal>:</para>
<programlisting language="java"><![CDATA[BeanWrapper company = BeanWrapperImpl(new Company());
]]><lineannotation>// setting the company name..</lineannotation><![CDATA[
company.setPropertyValue("name", "Some Company Inc.");
]]><lineannotation>// ... can also be done like this:</lineannotation><![CDATA[
PropertyValue value = new PropertyValue("name", "Some Company Inc.");
company.setPropertyValue(value);
]]><lineannotation>// ok, let's create the director and tie it to the company:</lineannotation><![CDATA[
BeanWrapper jim = BeanWrapperImpl(new Employee());
jim.setPropertyValue("name", "Jim Stravinsky");
company.setPropertyValue("managingDirector", jim.getWrappedInstance());
]]><lineannotation>// retrieving the salary of the managingDirector through the company</lineannotation><![CDATA[
Float salary = (Float) company.getPropertyValue("managingDirector.salary");]]></programlisting>
</section>
<section xml:id="beans-beans-conversion">
<title>Built-in <interfacename>PropertyEditor</interfacename>
implementations</title>
<para>Spring uses the concept of <literal>PropertyEditors</literal> to
effect the conversion between an <classname>Object</classname> and a
<classname>String</classname>. If you think about it, it sometimes might
be handy to be able to represent properties in a different way than the
object itself. For example, a <classname>Date</classname> can be
represented in a human readable way (as the
<classname>String</classname> '<literal>2007-14-09</literal>'), while
we're still able to convert the human readable form back to the original
date (or even better: convert any date entered in a human readable form,
back to <classname>Date</classname> objects). This behavior can be
achieved by <emphasis>registering custom editors</emphasis>, of type
<interfacename>java.beans.PropertyEditor</interfacename>. Registering
custom editors on a <interfacename>BeanWrapper</interfacename> or
alternately in a specific IoC container as mentioned in the previous
chapter, gives it the knowledge of how to convert properties to the
desired type. Read more about
<interfacename>PropertyEditors</interfacename> in the Javadoc of the
<literal>java.beans</literal> package provided by Sun.</para>
<para>A couple of examples where property editing is used in Spring:
<itemizedlist spacing="compact">
<listitem>
<para><emphasis>setting properties on beans</emphasis> is done using
<literal>PropertyEditors</literal>. When mentioning
<literal>java.lang.String</literal> as the value of a property of
some bean you're declaring in XML file, Spring will (if the setter
of the corresponding property has a
<classname>Class</classname>-parameter) use the
<classname>ClassEditor</classname> to try to resolve the parameter
to a <classname>Class</classname> object.</para>
</listitem>
<listitem>
<para><emphasis>parsing HTTP request parameters</emphasis> in Spring's
MVC framework is done using all kinds of
<literal>PropertyEditors</literal> that you can manually bind in all
subclasses of the <classname>CommandController</classname>.</para>
</listitem>
</itemizedlist> </para>
<para>Spring has a number of built-in <literal>PropertyEditors</literal>
to make life easy. Each of those is listed below and they are all
located in the
<literal>org.springframework.beans.propertyeditors</literal> package.
Most, but not all (as indicated below), are registered by default by
<classname>BeanWrapperImpl</classname>. Where the property editor is
configurable in some fashion, you can of course still register your own
variant to override the default one:</para>
<table xml:id="beans-beans-property-editors-tbl">
<title>Built-in <literal>PropertyEditors</literal></title>
<tgroup cols="2">
<colspec colname="c1" colwidth="3*"/>
<colspec colname="c2" colwidth="5*"/>
<thead>
<row>
<entry>Class</entry>
<entry>Explanation</entry>
</row>
</thead>
<tbody>
<row>
<entry><classname>ByteArrayPropertyEditor</classname></entry>
<entry>Editor for byte arrays. Strings will simply be converted to
their corresponding byte representations. Registered by default
by <classname>BeanWrapperImpl</classname>.</entry>
</row>
<row>
<entry><classname>ClassEditor</classname></entry>
<entry>Parses Strings representing classes to actual classes and
the other way around. When a class is not found, an
<classname>IllegalArgumentException</classname> is thrown.
Registered by default by
<classname>BeanWrapperImpl</classname>.</entry>
</row>
<row>
<entry><classname>CustomBooleanEditor</classname></entry>
<entry>Customizable property editor for
<classname>Boolean</classname> properties. Registered by default
by <classname>BeanWrapperImpl</classname>, but, can be
overridden by registering custom instance of it as custom
editor.</entry>
</row>
<row>
<entry><classname>CustomCollectionEditor</classname></entry>
<entry>Property editor for Collections, converting any source
<interfacename>Collection</interfacename> to a given target
<interfacename>Collection</interfacename> type.</entry>
</row>
<row>
<entry><classname>CustomDateEditor</classname></entry>
<entry>Customizable property editor for java.util.Date, supporting
a custom DateFormat. NOT registered by default. Must be user
registered as needed with appropriate format.</entry>
</row>
<row>
<entry><classname>CustomNumberEditor</classname></entry>
<entry>Customizable property editor for any Number subclass like
<classname>Integer</classname>, <classname>Long</classname>,
<classname>Float</classname>, <classname>Double</classname>.
Registered by default by <classname>BeanWrapperImpl</classname>,
but can be overridden by registering custom instance of it as a
custom editor.</entry>
</row>
<row>
<entry><classname>FileEditor</classname></entry>
<entry>Capable of resolving Strings to
<classname>java.io.File</classname> objects. Registered by
default by <classname>BeanWrapperImpl</classname>. </entry>
</row>
<row>
<entry><classname>InputStreamEditor</classname></entry>
<entry>One-way property editor, capable of taking a text string
and producing (via an intermediate
<classname>ResourceEditor</classname> and
<interfacename>Resource</interfacename>) an
<interfacename>InputStream</interfacename>, so
<interfacename>InputStream</interfacename> properties may be
directly set as Strings. Note that the default usage will not
close the <interfacename>InputStream</interfacename> for you!
Registered by default by
<classname>BeanWrapperImpl</classname>.</entry>
</row>
<row>
<entry><classname>LocaleEditor</classname></entry>
<entry>Capable of resolving Strings to
<classname>Locale</classname> objects and vice versa (the String
format is [language]_[country]_[variant], which is the same
thing the toString() method of Locale provides). Registered by
default by <classname>BeanWrapperImpl</classname>.</entry>
</row>
<row>
<entry><classname>PatternEditor</classname></entry>
<entry>Capable of resolving Strings to JDK 1.5
<classname>Pattern</classname> objects and vice versa.</entry>
</row>
<row>
<entry><classname>PropertiesEditor</classname></entry>
<entry>Capable of converting Strings (formatted using the format
as defined in the Javadoc for the java.lang.Properties class) to
<classname>Properties</classname> objects. Registered by default
by <classname>BeanWrapperImpl</classname>.</entry>
</row>
<row>
<entry><classname>StringTrimmerEditor</classname></entry>
<entry>Property editor that trims Strings. Optionally allows
transforming an empty string into a <literal>null</literal>
value. NOT registered by default; must be user registered as
needed.</entry>
</row>
<row>
<entry><classname>URLEditor</classname></entry>
<entry>Capable of resolving a String representation of a URL to an
actual <classname>URL</classname> object. Registered by default
by <classname>BeanWrapperImpl</classname>.</entry>
</row>
</tbody>
</tgroup>
</table>
<para> Spring uses the
<interfacename>java.beans.PropertyEditorManager</interfacename> to set
the search path for property editors that might be needed. The search
path also includes <literal>sun.bean.editors</literal>, which includes
<interfacename>PropertyEditor</interfacename> implementations for types
such as <classname>Font</classname>, <classname>Color</classname>, and
most of the primitive types. Note also that the standard JavaBeans
infrastructure will automatically discover
<interfacename>PropertyEditor</interfacename> classes (without you
having to register them explicitly) if they are in the same package as
the class they handle, and have the same name as that class, with
<literal>'Editor'</literal> appended; for example, one could have the
following class and package structure, which would be sufficient for the
<classname>FooEditor</classname> class to be recognized and used as the
<interfacename>PropertyEditor</interfacename> for
<classname>Foo</classname>-typed properties. </para>
<programlisting><![CDATA[com
chank
pop
Foo
FooEditor ]]><lineannotation>// the PropertyEditor for the Foo class</lineannotation></programlisting>
<para>Note that you can also use the standard
<interfacename>BeanInfo</interfacename> JavaBeans mechanism here as well
(described <link
xl:href="http://docs.oracle.com/javase/tutorial/javabeans/advanced/customization.html"
>in not-amazing-detail here</link>). Find below an example of using the
<interfacename>BeanInfo</interfacename> mechanism for explicitly
registering one or more <interfacename>PropertyEditor</interfacename>
instances with the properties of an associated class.</para>
<programlisting><![CDATA[com
chank
pop
Foo
FooBeanInfo ]]><lineannotation>// the BeanInfo for the Foo class</lineannotation></programlisting>
<para> Here is the Java source code for the referenced
<classname>FooBeanInfo</classname> class. This would associate a
<classname>CustomNumberEditor</classname> with the
<literal>age</literal> property of the <classname>Foo</classname> class. </para>
<programlisting language="java"><![CDATA[public class FooBeanInfo extends SimpleBeanInfo {
public PropertyDescriptor[] getPropertyDescriptors() {
try {
final PropertyEditor numberPE = new CustomNumberEditor(Integer.class, true);
PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Foo.class) {
public PropertyEditor createPropertyEditor(Object bean) {
return numberPE;
};
};
return new PropertyDescriptor[] { ageDescriptor };
}
catch (IntrospectionException ex) {
throw new Error(ex.toString());
}
}
}]]></programlisting>
<section xml:id="beans-beans-conversion-customeditor-registration">
<title>Registering additional custom
<interfacename>PropertyEditors</interfacename></title>
<para>When setting bean properties as a string value, a Spring IoC
container ultimately uses standard JavaBeans
<literal>PropertyEditors</literal> to convert these Strings to the
complex type of the property. Spring pre-registers a number of custom
<literal>PropertyEditors</literal> (for example, to convert a
classname expressed as a string into a real
<classname>Class</classname> object). Additionally, Java's standard
JavaBeans <interfacename>PropertyEditor</interfacename> lookup
mechanism allows a <classname>PropertyEditor</classname> for a class
simply to be named appropriately and placed in the same package as the
class it provides support for, to be found automatically.</para>
<para>If there is a need to register other custom
<literal>PropertyEditors</literal>, there are several mechanisms
available. The most manual approach, which is not normally convenient
or recommended, is to simply use the
<methodname>registerCustomEditor()</methodname> method of the
<interfacename>ConfigurableBeanFactory</interfacename> interface,
assuming you have a <interfacename>BeanFactory</interfacename>
reference. Another, slightly more convenient, mechanism is to use a
special bean factory post-processor called
<classname>CustomEditorConfigurer</classname>. Although bean factory
post-processors can be used with
<interfacename>BeanFactory</interfacename> implementations, the
<classname>CustomEditorConfigurer</classname> has a nested property
setup, so it is strongly recommended that it is used with the
<interfacename>ApplicationContext</interfacename>, where it may be
deployed in similar fashion to any other bean, and automatically
detected and applied.</para>
<para>Note that all bean factories and application contexts
automatically use a number of built-in property editors, through their
use of something called a <interfacename>BeanWrapper</interfacename>
to handle property conversions. The standard property editors that the
<interfacename>BeanWrapper</interfacename> registers are listed in
<link linkend="beans-beans-conversion">the previous section</link>.
Additionally, <literal>ApplicationContexts</literal> also override or
add an additional number of editors to handle resource lookups in a
manner appropriate to the specific application context type.</para>
<para>Standard JavaBeans <interfacename>PropertyEditor</interfacename>
instances are used to convert property values expressed as strings to
the actual complex type of the property.
<classname>CustomEditorConfigurer</classname>, a bean factory
post-processor, may be used to conveniently add support for additional
<interfacename>PropertyEditor</interfacename> instances to an
<interfacename>ApplicationContext</interfacename>.</para>
<para>Consider a user class <classname>ExoticType</classname>, and
another class <classname>DependsOnExoticType</classname> which needs
<classname>ExoticType</classname> set as a property:</para>
<programlisting language="java"><![CDATA[package example;
public class ExoticType {
private String name;
public ExoticType(String name) {
this.name = name;
}
}
public class DependsOnExoticType {
private ExoticType type;
public void setType(ExoticType type) {
this.type = type;
}
}]]></programlisting>
<para>When things are properly set up, we want to be able to assign the
type property as a string, which a
<interfacename>PropertyEditor</interfacename> will behind the scenes
convert into an actual <classname>ExoticType</classname>
instance:</para>
<programlisting language="xml"><![CDATA[<bean id="sample" class="example.DependsOnExoticType">
<property name="type" value="aNameForExoticType"/>
</bean>]]></programlisting>
<para>The <interfacename>PropertyEditor</interfacename> implementation
could look similar to this:</para>
<programlisting language="java"><lineannotation>// converts string representation to ExoticType object</lineannotation><![CDATA[
package example;
public class ExoticTypeEditor extends PropertyEditorSupport {
public void setAsText(String text) {
setValue(new ExoticType(text.toUpperCase()));
}
}]]></programlisting>
<para>Finally, we use <classname>CustomEditorConfigurer</classname> to
register the new <interfacename>PropertyEditor</interfacename> with
the <interfacename>ApplicationContext</interfacename>, which will then
be able to use it as needed:</para>
<programlisting language="xml"><![CDATA[<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="example.ExoticType" value="example.ExoticTypeEditor"/>
</map>
</property>
</bean>]]></programlisting>
<section xml:id="beans-beans-conversion-customeditor-registration-per">
<title>Using
<interfacename>PropertyEditorRegistrars</interfacename></title>
<para>Another mechanism for registering property editors with the
Spring container is to create and use a
<interfacename>PropertyEditorRegistrar</interfacename>. This
interface is particularly useful when you need to use the same set
of property editors in several different situations: write a
corresponding registrar and reuse that in each case.
<literal>PropertyEditorRegistrars</literal> work in conjunction with
an interface called
<interfacename>PropertyEditorRegistry</interfacename>, an interface
that is implemented by the Spring
<interfacename>BeanWrapper</interfacename> (and
<interfacename>DataBinder</interfacename>).
<literal>PropertyEditorRegistrars</literal> are particularly
convenient when used in conjunction with the
<classname>CustomEditorConfigurer</classname> (introduced <link
linkend="beans-beans-conversion-customeditor-registration"
>here</link>), which exposes a property called
<methodname>setPropertyEditorRegistrars(..)</methodname>:
<literal>PropertyEditorRegistrars</literal> added to a
<classname>CustomEditorConfigurer</classname> in this fashion can
easily be shared with <interfacename>DataBinder</interfacename> and
Spring MVC <interfacename>Controllers</interfacename>. Furthermore,
it avoids the need for synchronization on custom editors: a
<interfacename>PropertyEditorRegistrar</interfacename> is expected
to create fresh <interfacename>PropertyEditor</interfacename>
instances for each bean creation attempt.</para>
<para>Using a <interfacename>PropertyEditorRegistrar</interfacename>
is perhaps best illustrated with an example. First off, you need to
create your own
<interfacename>PropertyEditorRegistrar</interfacename>
implementation:</para>
<programlisting language="java"><![CDATA[package com.foo.editors.spring;
public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry registry) {
]]><lineannotation>// it is expected that new PropertyEditor instances are created</lineannotation><![CDATA[
registry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor());
]]><lineannotation>// you could register as many custom property editors as are required here...</lineannotation><![CDATA[
}
}]]></programlisting>
<para>See also the
<classname>org.springframework.beans.support.ResourceEditorRegistrar</classname>
for an example
<interfacename>PropertyEditorRegistrar</interfacename>
implementation. Notice how in its implementation of the
<methodname>registerCustomEditors(..)</methodname> method it creates
new instances of each property editor.</para>
<para>Next we configure a
<classname>CustomEditorConfigurer</classname> and inject an instance
of our <classname>CustomPropertyEditorRegistrar</classname> into
it:</para>
<programlisting language="xml"><![CDATA[<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<ref bean="customPropertyEditorRegistrar"/>
</list>
</property>
</bean>
<bean id="customPropertyEditorRegistrar"
class="com.foo.editors.spring.CustomPropertyEditorRegistrar"/>]]></programlisting>
<para>Finally, and in a bit of a departure from the focus of this
chapter, for those of you using <link linkend="mvc">Spring's MVC web
framework</link>, using
<interfacename>PropertyEditorRegistrars</interfacename> in
conjunction with data-binding
<interfacename>Controllers</interfacename> (such as
<classname>SimpleFormController</classname>) can be very convenient.
Find below an example of using a
<interfacename>PropertyEditorRegistrar</interfacename> in the
implementation of an <methodname>initBinder(..)</methodname>
method:</para>
<programlisting language="java"><![CDATA[public final class RegisterUserController extends SimpleFormController {
private final PropertyEditorRegistrar customPropertyEditorRegistrar;
public RegisterUserController(PropertyEditorRegistrar propertyEditorRegistrar) {
this.customPropertyEditorRegistrar = propertyEditorRegistrar;
}
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder)
throws Exception {
]]><emphasis role="bold">this.customPropertyEditorRegistrar.registerCustomEditors(binder);</emphasis><![CDATA[
}
]]><lineannotation>// other methods to do with registering a User</lineannotation><![CDATA[
}]]></programlisting>
<para>This style of <interfacename>PropertyEditor</interfacename>
registration can lead to concise code (the implementation of
<methodname>initBinder(..)</methodname> is just one line long!), and
allows common <interfacename>PropertyEditor</interfacename>
registration code to be encapsulated in a class and then shared
amongst as many <interfacename>Controllers</interfacename> as
needed.</para>
</section>
</section>
</section>
</section>
<section xml:id="core-convert">
<title>Spring 3 Type Conversion</title>
<para> Spring 3 introduces a <filename>core.convert</filename> package that
provides a general type conversion system. The system defines an SPI to
implement type conversion logic, as well as an API to execute type
conversions at runtime. Within a Spring container, this system can be used
as an alternative to PropertyEditors to convert externalized bean property
value strings to required property types. The public API may also be used
anywhere in your application where type conversion is needed. </para>
<section xml:id="core-convert-Converter-API">
<title>Converter SPI</title>
<para> The SPI to implement type conversion logic is simple and strongly
typed: </para>
<programlisting language="java"><![CDATA[package org.springframework.core.convert.converter;
public interface Converter<S, T> {
T convert(S source);
}]]></programlisting>
<para> To create your own Converter, simply implement the interface above.
Parameterize S as the type you are converting from, and T as the type
you are converting to. For each call to convert(S), the source argument
is guaranteed to be NOT null. Your Converter may throw any Exception if
conversion fails. An IllegalArgumentException should be thrown to report
an invalid source value. Take care to ensure your Converter
implementation is thread-safe. </para>
<para> Several converter implementations are provided in the
<filename>core.convert.support</filename> package as a convenience.
These include converters from Strings to Numbers and other common types.
Consider <classname>StringToInteger</classname> as an example Converter
implementation: </para>
<programlisting language="java"><![CDATA[package org.springframework.core.convert.support;
final class StringToInteger implements Converter<String, Integer> {
public Integer convert(String source) {
return Integer.valueOf(source);
}
}]]></programlisting>
</section>
<section xml:id="core-convert-ConverterFactory-SPI">
<title>ConverterFactory</title>
<para> When you need to centralize the conversion logic for an entire
class hierarchy, for example, when converting from String to
java.lang.Enum objects, implement
<interfacename>ConverterFactory</interfacename>: </para>
<programlisting language="java"><![CDATA[package org.springframework.core.convert.converter;
public interface ConverterFactory<S, R> {
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}]]></programlisting>
<para> Parameterize S to be the type you are converting from and R to be
the base type defining the <emphasis>range</emphasis> of classes you can
convert to. Then implement getConverter(Class<T>), where T is a
subclass of R. </para>
<para> Consider the <classname>StringToEnum</classname> ConverterFactory
as an example: </para>
<programlisting language="java"><![CDATA[package org.springframework.core.convert.support;
final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {
public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToEnumConverter(targetType);
}
private final class StringToEnumConverter<T extends Enum> implements Converter<String, T> {
private Class<T> enumType;
public StringToEnumConverter(Class<T> enumType) {
this.enumType = enumType;
}
public T convert(String source) {
return (T) Enum.valueOf(this.enumType, source.trim());
}
}
}]]></programlisting>
</section>
<section xml:id="core-convert-GenericConverter-SPI">
<title>GenericConverter</title>
<para> When you require a sophisticated Converter implementation, consider
the GenericConverter interface. With a more flexible but less strongly
typed signature, a GenericConverter supports converting between multiple
source and target types. In addition, a GenericConverter makes available
source and target field context you can use when implementing your
conversion logic. Such context allows a type conversion to be driven by
a field annotation, or generic information declared on a field
signature. </para>
<programlisting language="java"><![CDATA[package org.springframework.core.convert.converter;
public interface GenericConverter {
public Set<ConvertiblePair> getConvertibleTypes();