validation.xml 85.5 KB
Newer Older
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
T
Thomas Risberg 已提交
3 4
 "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">

5
<chapter id="validation">
6
  <title>Validation, Data Binding, and Type Conversion</title>
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

  <section id="validation-introduction">
    <title>Introduction</title>

    <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 and 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
29
    will not have the need to use the <interfacename>BeanWrapper</interfacename> directly. Because this
30
    is reference documentation however, we felt that some explanation might be
31 32 33 34 35 36 37 38
    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>
    
39 40 41 42 43 44 45 46 47
  </section>

    <section id="validator">
        <title>Validation using Spring's <interfacename>Validator</interfacename> interface</title>
        <para>Spring's 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>
48
        <programlisting language="java"><![CDATA[
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
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>
76
		<programlisting language="java"><![CDATA[public class PersonValidator implements Validator {
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
    
    ]]><lineannotation>/**
    * This <interfacename>Validator</interfacename> validates <emphasis role="bold">just</emphasis> <classname>Person</classname> 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 recourse to copy-n-paste you can
        dependency-inject or instantiate an <classname>AddressValidator</classname> within your
        <classname>CustomerValidator</classname>, and use it like so:</para>
114
        <programlisting language="java"><![CDATA[public class CustomerValidator implements Validator {
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

   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 <interfacename>Validator</interfacename> validates <classname>Customer</classname> instances, and any subclasses of <classname>Customer</classname> 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>&lt;spring:bind/&gt;</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 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
		<ulink url="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/validation/MessageCodesResolver.html">MessageCodesResolver</ulink>
		and
		<ulink url="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/validation/DefaultMessageCodesResolver.html">DefaultMessageCodesResolver</ulink>
		respectively.</para>
	</section>

  <section 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 ( <ulink url="http://java.sun.com/products/javabeans/">java.sun.com/products/javabeans</ulink>).</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 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 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>
290
	  <programlisting language="java"><![CDATA[public class Company {
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
    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>

308
	<programlisting language="java"><![CDATA[public class Employee {
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
    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>
329
      <programlisting language="java"><![CDATA[BeanWrapper company = BeanWrapperImpl(new Company());
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
]]><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 id="beans-beans-conversion">
      <title>Built-in <interface>PropertyEditor</interface> implementations</title>

348
		<para>Spring uses the concept of <literal>PropertyEditors</literal> to effect the conversion
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
		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 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 <interfacename>PropertyEditor</interfacename> for the <classname>Foo</classname> class</lineannotation></programlisting>
      <para>Note that you can also use the standard <interfacename>BeanInfo</interfacename> JavaBeans
		mechanism here as well (described
		<ulink url="http://java.sun.com/docs/books/tutorial/javabeans/customization/index.html">in not-amazing-detail here</ulink>).
		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 <interfacename>BeanInfo</interfacename> for the <classname>Foo</classname> 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>
552
	  <programlisting language="java"><![CDATA[public class FooBeanInfo extends SimpleBeanInfo {
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
      
    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 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>

607
			<programlisting language="java"><![CDATA[package example;
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
		
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>
629
			<programlisting language="xml"><![CDATA[<bean id="sample" class="example.DependsOnExoticType">
630 631 632
    <property name="type" value="aNameForExoticType"/>
</bean>]]></programlisting>
			<para>The <interfacename>PropertyEditor</interfacename> implementation could look similar to this:</para>
633
			<programlisting language="java"><lineannotation>// converts string representation to <classname>ExoticType</classname> object</lineannotation><![CDATA[
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
package example;

public class ExoticTypeEditor extends PropertyEditorSupport {

    private String format;

    public void setFormat(String format) {
        this.format = format;
    }
    
    public void setAsText(String text) {
        if (format != null && format.equals("upperCase")) {
            text = text.toUpperCase();
        }
        ExoticType type = new ExoticType(text);
        setValue(type);
    }
}]]></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>
655
			<programlisting language="xml"><![CDATA[<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
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
  <property name="customEditors">
    <map>
      <entry key="example.ExoticType">
        <bean class="example.ExoticTypeEditor">
          <property name="format" value="upperCase"/>
        </bean>
      </entry>
    </map>
  </property>
</bean>]]></programlisting>

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

689
			<programlisting language="java"><![CDATA[package com.foo.editors.spring;
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706

public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {

    public void registerCustomEditors(PropertyEditorRegistry registry) {

        ]]><lineannotation>// it is expected that new <interfacename>PropertyEditor</interfacename> 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>
707
			<programlisting language="xml"><![CDATA[<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723
    <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>

724
			<programlisting language="java"><![CDATA[public final class RegisterUserController extends SimpleFormController {
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

    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 <classname>User</classname></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>

751 752 753 754
	<section 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.
K
Keith Donald 已提交
755
			The system defines an API to implement type conversion logic, as well as an API to execute type conversions at runtime.
756
			Within a Spring container, if configured, this system can be used as an alternative to PropertyEditors to convert externalized bean property value strings to required property types.
K
polish  
Keith Donald 已提交
757
			The public API may also be used anywhere in your application where type conversion is needed.
758
		</para>
K
Keith Donald 已提交
759 760
		<section id="core-convert-Converter-API">
			<title>Converter API</title>
761
			<para>
K
Keith Donald 已提交
762
				The API to implement type conversion logic is simple and strongly typed:
763 764 765 766 767
			</para>
			<programlisting language="java"><![CDATA[
package org.springframework.core.converter;
    
public interface Converter<S, T> {
K
polish  
Keith Donald 已提交
768

K
Keith Donald 已提交
769
    T convert(S source);   
K
polish  
Keith Donald 已提交
770
        
S
Sam Brannen 已提交
771
}]]></programlisting>
772
			<para>
K
polish  
Keith Donald 已提交
773
				To create your own Converter, simply implement the interface above.
774 775 776
				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.
K
Keith Donald 已提交
777
				An IllegalArgumentException should be thrown to report an invalid source value.
S
Sam Brannen 已提交
778
				Take care to ensure your Converter implementation is thread-safe.
779 780 781
			</para>
			<para>
				Several converter implementations are provided in the <filename>core.convert.converters</filename> package as a convenience.
S
Sam Brannen 已提交
782 783
				These include converters from Strings to Numbers and other common types.
				Consider <classname>StringToInteger</classname> as an example Converter implementation:
784
			</para>
S
Sam Brannen 已提交
785
			<programlisting language="java">package org.springframework.core.convert.converters;
786
    
S
Sam Brannen 已提交
787
public class StringToInteger implements Converter&lt;String, Integer&gt; {
K
polish  
Keith Donald 已提交
788

789 790 791
    public Integer convert(String source) {
        return Integer.valueOf(source);
    }
K
polish  
Keith Donald 已提交
792
    
S
Sam Brannen 已提交
793
}</programlisting>
794
		</section>
K
polish  
Keith Donald 已提交
795 796 797
		<section id="core-convert-ConverterFactory-SPI">
			<title>ConverterFactory</title>
			<para>
K
polish  
Keith Donald 已提交
798
				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 a <interfacename>ConverterFactory</interfacename>:
K
polish  
Keith Donald 已提交
799 800 801
			</para>
			<programlisting language="java"><![CDATA[
package org.springframework.core.converter;
S
Sam Brannen 已提交
802

K
polish  
Keith Donald 已提交
803
public interface ConverterFactory<S, R> {
K
polish  
Keith Donald 已提交
804 805

    <T extends R> Converter<S, T> getConverter(Class<T> targetType);  
S
Sam Brannen 已提交
806 807
      
}]]></programlisting>
K
polish  
Keith Donald 已提交
808
			<para>
S
Sam Brannen 已提交
809
				Parameterize S to be type you are converting from and R to be base type defining the <emphasis>range</emphasis> of classes you can convert to.
K
polish  
Keith Donald 已提交
810
				Then implement getConverter(Class&lt;T&gt;), where T is a subclass of R.
K
polish  
Keith Donald 已提交
811 812
			</para>
			<para>
S
Sam Brannen 已提交
813
				Consider the <classname>StringToEnum</classname> ConverterFactory as an example:
K
polish  
Keith Donald 已提交
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829
			</para>
			<programlisting language="java"><![CDATA[
public class StringToEnumFactory implements ConverterFactory<String, Enum> {

    public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
        return new StringToEnum(targetType);
    }

    private final class StringToEnum<T extends Enum> implements Converter<String, T> {

        private Class<T> enumType;
		
        public StringToEnum(Class<T> enumType) {
            this.enumType = enumType;
        }
        
K
Keith Donald 已提交
830
        public T convert(String source) {
K
polish  
Keith Donald 已提交
831 832 833
            return (T) Enum.valueOf(this.enumType, source.trim());
        }
    }
S
Sam Brannen 已提交
834
}]]></programlisting>
K
polish  
Keith Donald 已提交
835
		</section>		
836 837 838 839
		<section id="core-convert-ConversionService-API">
			<title>ConversionService API</title>
			<para>
				The ConversionService defines a public API for executing type conversion logic at runtime.
K
Keith Donald 已提交
840
				Converters are often executed behind this facade interface:
841 842 843 844
			</para>
			<programlisting language="java"><![CDATA[
public interface ConversionService {

K
polish  
Keith Donald 已提交
845 846 847
    boolean canConvert(Class<?> sourceType, Class<?> targetType);
    
    <T> T convert(Object source, Class<T> targetType);
848
	
S
Sam Brannen 已提交
849
}]]></programlisting>
850
			<para>
S
Sam Brannen 已提交
851
				Most ConversionService implementations also implement <interface>ConverterRegistry</interface>, which provides an SPI for registering converters.
K
polish  
Keith Donald 已提交
852
				Internally, a ConversionService implementation delegates to its registered Converters and ConverterFactories to carry out type conversion logic.
853 854 855 856 857 858 859 860 861 862
			</para>
			<para>
				Two ConversionService implementations are provided with the system in the <filename>core.convert.support</filename> package.
				<classname>GenericConversionService</classname> is a generic implementation designed to be explicitly configured, either programatically or declaratively as a Spring bean.
				<classname>DefaultConversionService</classname> is a subclass that pre-registers the common Converters in the <filename>core.converter</filename> package as a convenience.
			</para>
		</section>
		<section id="core-convert-Spring-config">
			<title>Configuring a ConversionService</title>
			<para>
K
polish  
Keith Donald 已提交
863
				A ConversionService is a stateless object designed to be instantiated at application startup, then shared between multiple threads.
864 865 866 867
				In a Spring application, you typically configure a ConversionService instance per Spring container (or ApplicationContext).
				That ConversionService will be picked up by Spring and then used whenever a type conversion needs to be performed by the framework.
				You may also inject this ConversionService into any of your beans and invoke it directly.
			</para>
S
Sam Brannen 已提交
868 869 870 871 872
			<note>
				<para>
					If no ConversionService is registered with Spring, the original PropertyEditor-based system is used.
				</para>
			</note>
873 874 875 876 877 878 879
			<para>
				To register the DefaultConversionService with Spring, simply configure it as a bean with the id <code>conversionService</code>:
			</para>
			<programlisting language="xml"><![CDATA[
<bean id="conversionService" class="org.springframework.core.convert.support.DefaultConversionService" />]]>
			</programlisting>
			<para>
S
Sam Brannen 已提交
880
				To override the default set of converters with your own custom converter(s), set the <code>converters</code> property:
881 882 883 884 885
			</para>
			<programlisting language="xml"><![CDATA[
<bean id="conversionService" class="org.springframework.core.convert.support.DefaultConversionService">
    <property name="converters">
        <list>
K
polish  
Keith Donald 已提交
886
            <bean class="example.MyCustomConverter" />
887 888
        </list>
    </property>
S
Sam Brannen 已提交
889
</bean>]]></programlisting>
890 891 892 893
		</section>
		<section id="core-convert-programmatic-usage">
			<title>Using a ConversionService programatically</title>
			<para>
S
Sam Brannen 已提交
894
				To work with a ConversionService instance programatically, simply inject a reference to it like you would for any other bean:
895 896 897 898 899 900 901 902 903 904 905 906 907
			</para>
			<programlisting language="java"><![CDATA[
@Service
public class MyService {

    @Autowired
    public MyService(ConversionService conversionService) {
        this.conversionService = conversionService;
    }
    
    public void doIt() {
        this.conversionService.convert(...)
    }
S
Sam Brannen 已提交
908
}]]></programlisting>
909 910 911 912
		</section>
	</section>
	
	<section id="ui.format">
913
		<title>Spring 3 Field Formatting</title>
914
		<para>
K
Keith Donald 已提交
915 916 917 918
			As discussed in the previous section, <link linkend="core.convert"><filename>core.convert</filename></link> is a general-purpose type conversion system.
			It provides a unified ConversionService API as well as a strongly-typed Converter SPI for implementing conversion logic from one type to another.
			A Spring Container uses this system to bind bean property values.
			In addition, both the Spring Expression Language (SpEL) and DataBinder use this system to bind field values.
919
			For example, when SpEL needs to coerce a <classname>Short</classname> to a <classname>Long</classname> to complete an <function>expression.setValue(Object bean, Object value)</function> attempt, the core.convert system performs the coercion.
920 921
		</para>
		<para>
922
			Now consider the type conversion requirements of a typical client environment such as a web or desktop application.
K
polish  
Keith Donald 已提交
923
			In such environments, you typically convert <emphasis>from String</emphasis> to support the client postback process, as well as back <emphasis>to String</emphasis> to support the view rendering process.
K
Keith Donald 已提交
924 925 926
			In addition, you often need to localize String values.
			The more general <emphasis>core.convert</emphasis> Converter SPI does not address such <emphasis>formatting</emphasis> requirements directly.
			To directly address them, Spring 3 introduces a convenient Formatter SPI that provides a simple and robust alternative to PropertyEditors for client environments.
927 928
		</para>
		<para>
K
Keith Donald 已提交
929 930 931
			In general, use the Converter SPI when you need to implement general-purpose type conversion logic; for example, for converting between a java.util.Date and and java.lang.Long.
			Use the Formatter SPI when you're working in a client environment, such as a web application, and need to parse and print localized field values.
			The ConversionService provides a unified type conversion API for both SPIs.
932
		</para>
K
polish  
Keith Donald 已提交
933
		<section id="format-Formatter-SPI">
934 935
			<title>Formatter SPI</title>
			<para>
K
Keith Donald 已提交
936
				The Formatter SPI to implement field formatting logic is simple and strongly typed:
937 938
			</para>
			<programlisting language="java"><![CDATA[
K
Keith Donald 已提交
939 940 941 942 943 944 945 946 947
package org.springframework.format;

public interface Formatter<T> extends Printer<T>, Parser<T> {
}]]>
			</programlisting>
			<para>
				Where Formatter extends from the Printer and Parser building-block interfaces:
			</para>
			<programlisting language="java"><![CDATA[
948 949 950 951 952
public interface Printer<T> {
    String print(T fieldValue, Locale locale);
}]]>
			</programlisting>
			<programlisting language="java"><![CDATA[
953 954
import java.text.ParseException;

955 956 957 958
public interface Parser<T> {
    T parse(String clientValue, Locale locale) throws ParseException;
}]]>
			</programlisting>
959
			<para>
960
				To create your own Formatter, simply implement the Formatter interface above.
K
Keith Donald 已提交
961
				Parameterize T to be the type of object you wish to format, for example, <classname>java.util.Date</classname>.
962
				Implement the <methodname>print</methodname> operation to print an instance of T for display in the client locale.
963
				Implement the <methodname>parse</methodname> operation to parse an instance of T from the formatted representation returned from the client locale.
964
				Your Formatter should throw a ParseException or IllegalArgumentException if a parse attempt fails.
S
Sam Brannen 已提交
965
				Take care to ensure your Formatter implementation is thread-safe.
966 967
			</para>
			<para>
K
Keith Donald 已提交
968
				Several Formatter implementations are provided in <filename>format</filename> subpackages as a convenience.
K
polish  
Keith Donald 已提交
969
				The <filename>number</filename> package provides a NumberFormatter, CurrencyFormatter, and PercentFormatter to format java.lang.Number objects using a java.text.NumberFormat.
K
Keith Donald 已提交
970
				The <filename>datetime</filename> package provides a DateFormatter to format java.util.Date objects with a java.text.DateFormat.
971
				The <filename>datetime.joda</filename> package provides comprehensive datetime formatting support based on the <ulink url="http://joda-time.sourceforge.net">Joda Time library</ulink>.
K
polish  
Keith Donald 已提交
972 973
			</para>
			<para>
S
Sam Brannen 已提交
974
				Consider <classname>DateFormatter</classname> as an example <interfacename>Formatter</interfacename> implementation:				
975 976
			</para>
			<programlisting language="java"><![CDATA[
977
package org.springframework.format.datetime;
978 979 980

public final class DateFormatter implements Formatter<Date> {

K
polish  
Keith Donald 已提交
981 982 983 984 985 986
    private String pattern;
    
    public DateFormatter(String pattern) {
        this.pattern = pattern;
    }
    
987
    public String print(Date date, Locale locale) {
K
polish  
Keith Donald 已提交
988 989 990 991 992
        if (date == null) {
            return "";
        }
        return getDateFormat(locale).format(date);
    }
993

K
polish  
Keith Donald 已提交
994 995 996 997 998 999
    public Date parse(String formatted, Locale locale) throws ParseException {
        if (formatted.length() == 0) {
            return null;
        }
        return getDateFormat(locale).parse(formatted);
    }
1000

K
polish  
Keith Donald 已提交
1001 1002 1003 1004 1005
    protected DateFormat getDateFormat(Locale locale) {
        DateFormat dateFormat = new SimpleDateFormat(this.pattern, locale);
        dateFormat.setLenient(false);
        return dateFormat;
    }
1006

S
Sam Brannen 已提交
1007
}]]></programlisting>
K
polish  
Keith Donald 已提交
1008 1009 1010
			<para>
				The Spring team welcomes community-driven Formatter contributions; see <ulink url="http://jira.springframework.org">http://jira.springframework.org</ulink> to contribute.
			</para>
1011
		</section>
K
polish  
Keith Donald 已提交
1012
		<section id="format-CustomFormatAnnotations">
K
Keith Donald 已提交
1013
			<title>Annotation-driven Formatting</title>
1014
			<para>
K
Keith Donald 已提交
1015 1016
				As you will see, field formatting can be configured by field type or annotation.
				To bind an Annotation to a formatter, implement AnnotationFormatterFactory:
K
polish  
Keith Donald 已提交
1017
			</para>
K
polish  
Keith Donald 已提交
1018
			<programlisting language="java"><![CDATA[
1019
package org.springframework.format;
1020

1021
public interface AnnotationFormatterFactory<A extends Annotation> {
K
polish  
Keith Donald 已提交
1022

1023 1024 1025 1026 1027
    Set<Class<?>> getFieldTypes();    
  
    Printer<?> getPrinter(A annotation, Class<?> fieldType);
    
    Parser<?> getParser(A annotation, Class<?> fieldType);
K
polish  
Keith Donald 已提交
1028

K
polish  
Keith Donald 已提交
1029 1030 1031 1032
}]]>
			</programlisting>
			<para>
				Parameterize A to be the field annotationType you wish to associate formatting logic with, for example <code>org.springframework.format.annotation.DateTimeFormat</code>.
K
Keith Donald 已提交
1033 1034 1035
				Have <methodname>getFieldTypes</methodname> return the types of fields the annotation may be used on.
				Have <methodname>getPrinter</methodname> return a Printer to print the value of an annotated field.
				Have <methodname>getParser</methodname> return a Parser to parse a clientValue for an annotated field.
K
polish  
Keith Donald 已提交
1036 1037
			</para>
			<para>
K
Keith Donald 已提交
1038 1039
				The example AnnotationFormatterFactory implementation below binds the @NumberFormat Annotation to a formatter.
				This annotation allows either a number style or pattern to be specified:
K
polish  
Keith Donald 已提交
1040 1041 1042 1043
			</para>
			<programlisting language="java"><![CDATA[
public final class NumberFormatAnnotationFormatterFactory implements AnnotationFormatterFactory<NumberFormat> {

K
Keith Donald 已提交
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
    public Set<Class<?>> getFieldTypes() {
        return new HashSet<Class<?>>(asList(new Class<?>[] { 
            Short.class, Integer.class, Long.class, Float.class, Double.class, BigDecimal.class, BigInteger.class }));
    }
    
    public Printer<Number> getPrinter(NumberFormat annotation, Class<?> fieldType) {
        return configureFormatterFrom(annotation, fieldType);
    }
    
    public Parser<Number> getParser(NumberFormat annotation, Class<?> fieldType) {
        return configureFormatterFrom(annotation, fieldType);
    }

    private Formatter<Number> configureFormatterFrom(NumberFormat annotation, Class<?> fieldType) {
        if (!annotation.pattern().isEmpty()) {
            return new NumberFormatter(annotation.pattern());
        } else {
            Style style = annotation.style();
            if (style == Style.PERCENT) {
                return new PercentFormatter();
            } else if (style == Style.CURRENCY) {
                return new CurrencyFormatter();
            } else {
                return new NumberFormatter();
            }
        }
    }
K
polish  
Keith Donald 已提交
1071 1072 1073
}]]>
			</programlisting>
			<para>
K
Keith Donald 已提交
1074
				To trigger formatting, simply annotate fields with @NumberFormat:
K
polish  
Keith Donald 已提交
1075 1076
			</para>
			<programlisting language="java"><![CDATA[
1077 1078
public class MyModel {

K
polish  
Keith Donald 已提交
1079
    @NumberFormat(style=Style.CURRENCY)
K
polish  
Keith Donald 已提交
1080
    private BigDecimal decimal;
1081
	
K
polish  
Keith Donald 已提交
1082 1083
}]]>
			</programlisting>
K
Keith Donald 已提交
1084 1085 1086 1087
			<section id="format.annotations.api">
				<title>Format Annotation API</title>
				<para>
					A portable format annotation API exists in the <filename>org.springframework.format.annotation</filename> package.
K
Keith Donald 已提交
1088 1089
					Use @NumberFormat to format java.lang.Number fields.
					Use @DateTimeFormat to format java.util.Date, java.util.Calendar, java.util.Long, or Joda Time fields. 
K
Keith Donald 已提交
1090 1091
				</para>
				<para>
K
Keith Donald 已提交
1092
					The example below uses @DateTimeFormat to format a java.util.Date as a ISO Date (yyyy-MM-dd):
K
Keith Donald 已提交
1093 1094
				</para>
				<programlisting language="java"><![CDATA[
K
polish  
Keith Donald 已提交
1095 1096 1097 1098 1099 1100
public class MyModel {

    @DateTimeFormat(iso=ISO.DATE)
    private Date date;
	
}]]>
K
Keith Donald 已提交
1101 1102
				</programlisting>		
			</section>
1103
		</section>
K
polish  
Keith Donald 已提交
1104
		<section id="format-FormatterRegistry-SPI">
1105 1106
			<title>FormatterRegistry SPI</title>
			<para>
K
Keith Donald 已提交
1107
				At runtime, Formatters are registered in a FormatterRegistry.
K
Keith Donald 已提交
1108
				The FormatterRegistry SPI allows you to configure Formatting rules centrally, instead of duplicating such configuration across your Controllers.
1109
				For example, you might want to enforce that all Date fields are formatted a certain way, or fields with a specific annotation are formatted in a certain way.
K
polish  
Keith Donald 已提交
1110
				With a shared FormatterRegistry, you define these rules once and they are applied whenever formatting is needed.
1111 1112 1113 1114 1115
			</para>
			<para>
				Review the FormatterRegistry SPI below:
			</para>
			<programlisting language="java"><![CDATA[
1116
package org.springframework.format;
K
polish  
Keith Donald 已提交
1117

1118 1119
public interface FormatterRegistry {

K
polish  
Keith Donald 已提交
1120 1121 1122
    void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);

    void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);
1123

K
polish  
Keith Donald 已提交
1124
    void addFormatterForAnnotation(AnnotationFormatterFactory<?, ?> factory);
K
polish  
Keith Donald 已提交
1125
    
S
Sam Brannen 已提交
1126
}]]></programlisting>
1127
			<para>
K
polish  
Keith Donald 已提交
1128 1129
				As shown above, Formatters can be registered by fieldType or annotation.
				<classname>FormattingConversionService</classname> is the implementation of <classname>FormatterRegistry</classname> suitable for most environments.
K
Keith Donald 已提交
1130 1131
				This implementation may be configured programatically, or declaratively as a Spring bean using <classname>FormattingConversionServiceFactoryBean</classname>.
				Because this implemementation also implements <classname>ConversionService</classname>, it can be directly configured for use with Spring's DataBinder and the Spring Expression Language (SpEL).
1132 1133
			</para>
		</section>
K
polish  
Keith Donald 已提交
1134 1135
		<section id="format-configuring-FormatterRegistry">
			<title>Configuring Formatting in Spring MVC</title>
1136
			<para>
K
Keith Donald 已提交
1137 1138 1139
				In a Spring MVC application, you may configure a custom ConversionService instance explicity as an attribute of the <literal>annotation-driven</literal> element of the MVC namespace.
				This ConversionService will then be used anytime a type conversion is required during Controller model binding.
				If not configured explicitly, Spring MVC will automatically register default formatters and converters for common types such as numbers and dates.
1140 1141
			</para>
			<para>
K
Keith Donald 已提交
1142
				To rely on default formatting rules, no custom configuration is required in your Spring MVC config XML:
1143
			</para>
K
Keith Donald 已提交
1144
			<programlisting language="xml"><![CDATA[
K
polish  
Keith Donald 已提交
1145 1146 1147 1148
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
K
Keith Donald 已提交
1149 1150 1151 1152 1153
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
K
polish  
Keith Donald 已提交
1154 1155 1156 1157 1158 1159 1160 1161

    <mvc:annotation-driven/>
	
</beans>
]]>
			</programlisting>
			<para>
				With this one-line of configuation, default formatters for Numbers and Date types will be installed, including support for the @NumberFormat and @DateTimeFormat annotations.
K
Keith Donald 已提交
1162
				Full support for the Joda Time formatting library is also installed if Joda Time is present on the classpath.
K
polish  
Keith Donald 已提交
1163 1164
			</para>
			<para>
K
Keith Donald 已提交
1165
				To inject a ConversionService instance with custom formatters and converters registered, set the conversion-service attribute:
K
polish  
Keith Donald 已提交
1166 1167 1168 1169 1170 1171
			</para>
			<programlisting language="xml"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
K
Keith Donald 已提交
1172 1173 1174 1175 1176
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
K
polish  
Keith Donald 已提交
1177 1178 1179 1180 1181 1182 1183

    <mvc:annotation-driven conversion-service="conversionService" />
	
	<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
	
</beans>
]]>
1184
			</programlisting>
K
Keith Donald 已提交
1185
			<para>
K
Keith Donald 已提交
1186
				A custom ConversionService instance is often constructed by a FactoryBean that internally registers custom Formatters and Converters programatically before the ConversionService is returned.
K
polish  
Keith Donald 已提交
1187
				See FormatingConversionServiceFactoryBean for an example.		
K
Keith Donald 已提交
1188
			</para>
1189
		</section>
K
polish  
Keith Donald 已提交
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
	</section>
	<section id="validation.beanvalidation">
		<title>Spring 3 Validation</title>
		<para>
			Spring 3 introduces several enhancements to its validation support.
			First, the JSR-303 Bean Validation API is now fully supported.
			Second, when used programatically, Spring's DataBinder can now validate objects as well as bind to them.
			Third, Spring MVC now has support for declaratively validating @Controller inputs.
		</para>
		<section id="validation.beanvalidation.overview">
K
polish  
Keith Donald 已提交
1200
			<title>Overview of the JSR-303 Bean Validation API</title>
1201
			<para>
K
polish  
Keith Donald 已提交
1202
				JSR-303 standardizes validation constraint declaration and metadata for the Java platform.
K
polish  
Keith Donald 已提交
1203 1204 1205
				Using this API, you annotate domain model properties with declarative validation constraints and the runtime enforces them.
				There are a number of built-in constraints you can can take advantage of.
				You may also define your own custom constraints.
1206
			</para>
K
polish  
Keith Donald 已提交
1207 1208 1209 1210
			<para>
				To illustrate, consider a simple Person model with two properties:
			</para>
			<programlisting language="java"><![CDATA[
1211 1212
public class Person {
    private String name;
K
polish  
Keith Donald 已提交
1213
    private int age;
S
Sam Brannen 已提交
1214
}]]></programlisting>
K
polish  
Keith Donald 已提交
1215 1216 1217 1218
			<para>
				JSR-303 allows you to define declarative validation constraints against such properties:
			</para>
			<programlisting language="java"><![CDATA[
1219 1220 1221 1222 1223
public class Person {

    @NotNull
    @Max(64)
    private String name;
K
polish  
Keith Donald 已提交
1224
    
1225 1226
    @Min(0)
    private int age;
K
polish  
Keith Donald 已提交
1227

S
Sam Brannen 已提交
1228
}]]></programlisting>
K
polish  
Keith Donald 已提交
1229
			<para>
K
polish  
Keith Donald 已提交
1230
				When an instance of this class is validated by a JSR-303 Validator, these constraints will be enforced.
K
polish  
Keith Donald 已提交
1231 1232 1233 1234
			</para>
			<para>
				For general information on JSR-303, see the <ulink url="http://jcp.org/en/jsr/detail?id=303">Bean Validation Specification</ulink>.
				For information on the specific capabilities of the default reference implementation, see the <ulink url="https://www.hibernate.org/412.html">Hibernate Validator</ulink> documentation.
K
polish  
Keith Donald 已提交
1235
				To learn how to setup a JSR-303 implementation as a Spring bean, keep reading.
K
polish  
Keith Donald 已提交
1236 1237 1238 1239 1240 1241 1242
			</para>
		</section>
		<section id="validation.beanvalidation.spring">
			<title>Configuring a Bean Validation Implementation</title>
			<para>
				Spring provides full support for the JSR-303 Bean Validation API.
				This includes convenient support for bootstrapping a JSR-303 implementation as a Spring bean.
K
polish  
Keith Donald 已提交
1243
				This allows a <code>javax.validation.Validator</code> to be injected wherever validation is needed in your application.
K
polish  
Keith Donald 已提交
1244 1245
			</para>
			<para>
1246
				Use the <classname>LocalValidatorFactoryBean</classname> to configure a default JSR-303 Validator as a Spring bean:					
K
polish  
Keith Donald 已提交
1247 1248 1249 1250 1251 1252
			</para>
			<programlisting language="xml"><![CDATA[
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />]]>
			</programlisting>
			<para>
				The basic configuration above will trigger JSR-303 to initialize using its default bootstrap mechanism.
K
polish  
Keith Donald 已提交
1253
				A JSR-303 provider, such as Hibernate Validator, is expected to be present in the classpath and will be detected automatically.
K
polish  
Keith Donald 已提交
1254
			</para>
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264

			<tip>
				<title>Using LocalValidatorFactoryBean programmatically</title>
				<para>If you choose to use <classname>LocalValidatorFactoryBean</classname>
				programmatically – i.e., by instantiating it directly – make sure
				you call its <literal>afterPropertiesSet()</literal> method. Otherwise, the
				<classname>LocalValidatorFactoryBean</classname> will not be
				initialized properly.</para>
			</tip>

K
polish  
Keith Donald 已提交
1265 1266
			<section id="validation.beanvalidation.spring.inject">
				<title>Injecting a Validator</title>
1267
				<para>
1268
					<classname>LocalValidatorFactoryBean</classname> implements both <code>javax.validation.Validator</code> and <code>org.springframework.validation.Validator</code>.
K
polish  
Keith Donald 已提交
1269
					You may inject a reference to one of these two interfaces into beans that need to invoke validation logic.
1270 1271
				</para>
				<para>
K
polish  
Keith Donald 已提交
1272
					Inject a reference to <code>javax.validation.Validator</code> if you prefer to work with the JSR-303 API directly:
1273
				</para>
1274
				<programlisting language="java">import javax.validation.Validator;
1275 1276 1277 1278 1279 1280

@Service
public class MyService {

    @Autowired
    private Validator validator;
1281
</programlisting>
K
polish  
Keith Donald 已提交
1282
				<para>
K
polish  
Keith Donald 已提交
1283
					Inject a reference to <code>org.springframework.validation.Validator</code> if your bean requires the Spring Validation API:
K
polish  
Keith Donald 已提交
1284 1285
				</para>
				<programlisting language="java"><![CDATA[
1286 1287
import org.springframework.validation.Validator;

K
polish  
Keith Donald 已提交
1288 1289
@Service
public class MyService {
1290 1291 1292

    @Autowired
    private Validator validator;
K
polish  
Keith Donald 已提交
1293

S
Sam Brannen 已提交
1294
}]]></programlisting>
K
polish  
Keith Donald 已提交
1295 1296 1297 1298 1299 1300 1301
			</section>
			<section id="validation.beanvalidation.spring.constraints">
				<title>Configuring Custom Constraints</title>
				<para>
					Each JSR-303 validation constraint consists of two parts.
					First, a @Constraint annotation that declares the constraint and its configurable properties.
					Second, an implementation of the <code>javax.validation.ConstraintValidator</code> interface that implements the constraint's behavior.
K
polish  
Keith Donald 已提交
1302 1303
					To associate a declaration with an implementation, each @Constraint annotation references a corresponding ValidationConstraint implementation class.
					At runtime, a <code>ConstraintValidatorFactory</code> instantiates the referenced implementation when the constraint annotation is encountered in your domain model.
K
polish  
Keith Donald 已提交
1304 1305
				</para>
				<para>
1306
					By default, the <classname>LocalValidatorFactoryBean</classname> configures a <code>SpringConstraintValidatorFactory</code> that uses Spring to create ConstraintValidator instances.
K
polish  
Keith Donald 已提交
1307 1308 1309
					This allows your custom ConstraintValidators to benefit from dependency injection like any other Spring bean.
				</para>
				<para>
K
polish  
Keith Donald 已提交
1310
					Shown below is an example of a custom @Constraint declaration, followed by an associated <code>ConstraintValidator</code> implementation that uses Spring for dependency injection:
K
polish  
Keith Donald 已提交
1311 1312
				</para>
				<programlisting language="java"><![CDATA[
1313 1314 1315 1316
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyConstraint {
S
Sam Brannen 已提交
1317
}]]></programlisting>					
K
polish  
Keith Donald 已提交
1318
				<programlisting language="java"><![CDATA[
1319 1320 1321 1322 1323 1324 1325
import javax.validation.ConstraintValidator;

public class MyConstraintValidator implements ConstraintValidator {

    @Autowired;
    private Foo aDependency;

K
polish  
Keith Donald 已提交
1326
    ...
S
Sam Brannen 已提交
1327
}]]></programlisting>
K
polish  
Keith Donald 已提交
1328
				<para>
K
polish  
Keith Donald 已提交
1329
					As you can see, a ConstraintValidator implementation may have its dependencies @Autowired like any other Spring bean.
K
polish  
Keith Donald 已提交
1330
				</para>			
1331
			</section>
K
polish  
Keith Donald 已提交
1332 1333
			<section id="validation.beanvalidation.spring.other">
				<title>Additional Configuration Options</title>
1334
				<para>
1335
					The default <classname>LocalValidatorFactoryBean</classname> configuration should prove sufficient for most cases.
K
polish  
Keith Donald 已提交
1336
					There are a number of other configuration options for various JSR-303 constructs, from message interpolation to traversal resolution.
1337
					See the JavaDocs of <classname>LocalValidatorFactoryBean</classname> more information on these options.
1338
				</para>
K
polish  
Keith Donald 已提交
1339 1340 1341 1342 1343
			</section>
		</section>
		<section id="validation.binder">
			<title>Configuring a DataBinder</title>
			<para>
K
polish  
Keith Donald 已提交
1344
				Since Spring 3, a DataBinder instance can be configured with a Validator.
K
polish  
Keith Donald 已提交
1345
				Once configured, the Validator may be invoked by calling <code>binder.validate()</code>.
1346
				Any validation Errors are automatically added to the binder's BindingResult.
K
polish  
Keith Donald 已提交
1347 1348
			</para>
			<para>
K
polish  
Keith Donald 已提交
1349
				When working with the DataBinder programatically, this can be used to invoke validation logic after binding to a target object:
K
polish  
Keith Donald 已提交
1350
			</para>
1351
			<programlisting language="java">Foo target = new Foo();
K
polish  
Keith Donald 已提交
1352
DataBinder binder = new DataBinder(target);
1353 1354
binder.setValidator(new FooValidator());

1355
<lineannotation>// bind to the target object</lineannotation>
1356 1357
binder.bind(propertyValues);

1358
<lineannotation>// validate the target object</lineannotation>
1359 1360
binder.validate();

1361 1362 1363
<lineannotation>// get BindingResult that includes any validation errors</lineannotation>
BindingResult results = binder.getBindingResult();
</programlisting>
K
polish  
Keith Donald 已提交
1364 1365 1366 1367
		</section>
		<section id="validation.mvc">
			<title>Spring MVC 3 Validation</title>
			<para>
K
polish  
Keith Donald 已提交
1368 1369
				Beginning with Spring 3, Spring MVC has the ability to automatically validate @Controller inputs.
				In previous versions it was up to the developer to manually invoke validation logic.
K
polish  
Keith Donald 已提交
1370 1371
			</para>
			<section id="validation.mvc.triggering">
K
polish  
Keith Donald 已提交
1372
				<title>Triggering @Controller Input Validation</title>
1373
				<para>
K
polish  
Keith Donald 已提交
1374
					To trigger validation of a @Controller input, simply annotate the input argument as @Valid:
1375
				</para>
1376
				<programlisting language="java">@Controller
1377 1378 1379
public class MyController {

    @RequestMapping("/foo", method=RequestMethod.POST)
1380 1381
    public void processFoo(<emphasis role="bold">@Valid</emphasis> Foo foo) { <lineannotation>/* ... */</lineannotation> }
</programlisting>
K
polish  
Keith Donald 已提交
1382 1383 1384 1385
				<para>
					Spring MVC will validate a @Valid object after binding so-long as an appropriate Validator has been configured.
				</para>
				<note>
1386
					<para>
K
polish  
Keith Donald 已提交
1387
						The @Valid annotation is part of the standard JSR-303 Bean Validation API, and is not a Spring-specific construct.
1388
					</para>
K
polish  
Keith Donald 已提交
1389 1390 1391 1392 1393 1394
				</note>
			</section>
			<section id="validation.mvc.configuring">
				<title>Configuring a Validator for use by Spring MVC</title>
				<para>
					The Validator instance invoked when a @Valid method argument is encountered may be configured in two ways.
K
polish  
Keith Donald 已提交
1395
					First, you may call binder.setValidator(Validator) within a @Controller's @InitBinder callback.
K
polish  
Keith Donald 已提交
1396 1397 1398
					This allows you to configure a Validator instance per @Controller class:
				</para>
				<programlisting language="java"><![CDATA[
1399 1400 1401 1402 1403 1404 1405
@Controller
public class MyController {

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(new FooValidator());
    }
K
polish  
Keith Donald 已提交
1406
    
1407
    @RequestMapping("/foo", method=RequestMethod.POST)
K
polish  
Keith Donald 已提交
1408 1409
    public void processFoo(@Valid Foo foo) { ... }
	
S
Sam Brannen 已提交
1410
}]]></programlisting>
K
polish  
Keith Donald 已提交
1411 1412 1413 1414 1415
				<para>
					Second, you may call setValidator(Validator) on the global WebBindingInitializer.
					This allows you to configure a Validator instance across all @Controllers:
				</para>
				<programlisting language="xml"><![CDATA[
1416 1417 1418 1419 1420 1421 1422 1423
<!-- Invokes Spring MVC @Controller methods -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="webBindingInitializer">
        <!-- Configures Spring MVC DataBinder instances -->
        <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
            <property name="validator" ref="validator" />
        </bean>
    </property>
S
Sam Brannen 已提交
1424
</bean>]]></programlisting>
K
polish  
Keith Donald 已提交
1425 1426 1427 1428
			</section>
			<section id="validation.mvc.jsr303">
				<title>Configuring a JSR-303 Validator for use by Spring MVC</title>
				<para>
K
polish  
Keith Donald 已提交
1429
					With JSR-303, the default <code>javax.validation.Validator</code> implementation is generic.
K
polish  
Keith Donald 已提交
1430
					A single instance typically coordinates the validation of <emphasis>all</emphasis> application objects that declare validation constraints.
1431
					To configure such a general purpose Validator for use by Spring MVC, simply inject a <classname>LocalValidatorFactoryBean</classname> reference into the <code>WebBindingInitializer</code>.
K
polish  
Keith Donald 已提交
1432 1433 1434 1435 1436
				</para>
				<para>
					A full configuration example showing injection of a JSR-303 backed Validator into Spring MVC is shown below:
				</para>
				<programlisting language="xml"><![CDATA[
1437 1438 1439 1440 1441 1442 1443
<!-- Invokes Spring MVC @Controller methods -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="webBindingInitializer">
        <!-- Configures Spring MVC DataBinder instances -->
        <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
            <property name="validator" ref="validator" />
        </bean>
K
polish  
Keith Donald 已提交
1444
    </property>
1445 1446 1447
</bean>

<!-- Creates the JSR-303 Validator -->
S
Sam Brannen 已提交
1448
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />]]></programlisting>
K
polish  
Keith Donald 已提交
1449
				<para>
K
polish  
Keith Donald 已提交
1450 1451
					With this configuration, anytime a @Valid @Controller input is encountered, it will be validated by the JSR-303 provider.
					JSR-303, in turn, will enforce any constraints declared against the input.
1452
					Any ConstaintViolations will automatically be exposed as errors in the BindingResult renderable by standard Spring MVC form tags.
K
polish  
Keith Donald 已提交
1453
				</para>
1454 1455
			</section>
		</section>
1456
	</section>
K
Keith Donald 已提交
1457 1458 1459
	<section id="org.springframework.mapping">
		<title>Spring 3 Object Mapping</title>
		<para>
K
polish  
Keith Donald 已提交
1460
			There are scenarios, particularly in large message-oriented business applications, where object transformation is required.
K
polish  
Keith Donald 已提交
1461
			For example, consider a complex Web Service where there is a separation between the data exchange model and the internal domain model used to structure business logic.
K
polish  
Keith Donald 已提交
1462
			In cases like this, a general-purpose object-to-object mapping facility can be useful for automating the mapping between these disparate models.
1463
			Spring 3 introduces such a facility built on the <link linkend="expressions-intro">Spring Expression Language</link> (SpEL).
K
Keith Donald 已提交
1464 1465 1466 1467 1468
			This facility is described in this section.
		</para>
		<section id="mapping-Mapping-API">
			<title>Mapper API</title>
			<para>
K
polish  
Keith Donald 已提交
1469
				The API to implement object mapping logic is simple and strongly typed:
K
Keith Donald 已提交
1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500
			</para>
			<programlisting language="java"><![CDATA[
package org.springframework.mapping;
    
public interface Mapper<S, T> {

    T map(S source, T target);   
        
}]]></programlisting>
			<para>
				To create your own Mapper, simply implement the interface above.
				Parameterize S as the type you are mapping from, and T as the type you are mapping to.
				The source and target arguments provided to you should never be null.
				Your Mapper may throw any RuntimeException if mapping fails.
				Take care to ensure your Mapper implementation is thread-safe.
			</para>
			<para>
				Consider the following hand-coded Mapper example:
			</para>
			<programlisting language="java">
public class PersonDtoPersonMapper implements Mapper&lt;PersonDto, Person&gt; {

    public Person map(PersonDto source, Person target) {
        String[] names = source.getName().split(" ");
        target.setFirstName(names[0]);
        target.setLastName(names[1]);
        return target;
    }
    
}</programlisting>
			<para>
K
polish  
Keith Donald 已提交
1501 1502
				In this trivial example, the Mapper maps the PersonDto's <literal>name</literal> property to the Person's <literal>firstName</literal> and <literal>lastName</literal> properties.
				The fully mapped Person object is returned.
K
Keith Donald 已提交
1503 1504 1505
			</para>
		</section>
		<section id="mapping.SpelMapper">
K
polish  
Keith Donald 已提交
1506
			<title>General Purpose Object Mapper Implementation</title>
K
Keith Donald 已提交
1507
			<para>
K
polish  
Keith Donald 已提交
1508
				A general purpose object-to-object mapping system exists in the <classname>org.springframework.mapping.support</classname> package.
K
Keith Donald 已提交
1509
				Built on the Spring Expression Language (SpEL), this system is capable of mapping between a variety of object types, including JavaBeans, Arrays, Collections, and Maps.
K
polish  
Keith Donald 已提交
1510
				It can perform field-to-field, field-to-multi-field, multi-field-to-field, and conditional mappings.
K
Keith Donald 已提交
1511
				It also can carry out type conversion and recursive mapping, which are often required with rich object models.
K
Keith Donald 已提交
1512 1513 1514 1515
			</para>
			<section id="mapping.SpelMapper-usage">
				<title>Usage</title>
				<para>
K
Keith Donald 已提交
1516
					To obtain a general purpose object Mapper with its default configuration, simply call <methodname>MappingFactory.getDefaultMapper()</methodname>.
K
polish  
Keith Donald 已提交
1517
					Then invoke the Mapper by calling its <literal>map(Object, Object)</literal> operation:
K
Keith Donald 已提交
1518 1519
				</para>
				<programlisting language="java"><![CDATA[
K
polish  
Keith Donald 已提交
1520 1521
MappingFactory.defaultMapper().map(aSource, aTarget);]]>
				</programlisting>
K
Keith Donald 已提交
1522
				<para>
K
polish  
Keith Donald 已提交
1523
					By default, the defaultMapper will map the fields on the source and target that have the same names.
1524
					If the field types differ, the mapping system will attempt a type conversion using Spring 3's <link linkend="core.convert">type conversion system</link>.
K
polish  
Keith Donald 已提交
1525
					Nested bean properties are mapped recursively.
K
Keith Donald 已提交
1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541
					Any mapping failures will trigger a MappingException to be thrown.
					If there are multiple failures, they will be collected and returned in the MappingException thrown to the caller.
				</para>
				<para>
					To illustrate this default behavior, consider the following source object type:
				</para>
				<programlisting language="java"><![CDATA[
public class CreateAccountDto {
    private String number;
    private String name;
    private AddressDto address;
       
    public static class AddressDto {
        private String street;
        private String zip;    
    }
1542
}]]></programlisting>				
K
Keith Donald 已提交
1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557
				<para>
					And the following target object type:
				</para>
				<programlisting language="java"><![CDATA[
public class Account {
    private Long number;
    private String name;
    private Address address;
    
    public static class Address {
        private String street;
        private String city
        private String state;
        private String zip;    
    }
1558
}]]></programlisting>
K
Keith Donald 已提交
1559
				<para>
K
polish  
Keith Donald 已提交
1560
					Now mapped in the following service method:
K
Keith Donald 已提交
1561 1562
				</para>
				<programlisting language="java"><![CDATA[
K
polish  
Keith Donald 已提交
1563 1564 1565 1566 1567
public void createAccount(CreateAccountDto dto) {
    Account account = (Account) MapperFactory.getDefaultMapper().map(dto, new Account());
    // work with the mapped account instance
}]]>
				</programlisting>
K
Keith Donald 已提交
1568 1569 1570 1571 1572 1573 1574 1575 1576 1577
				<para>
					In this example, the <literal>number</literal>, <literal>name</literal>, and <literal>address</literal> properties are automatically mapped since they are present on both the source and target objects.
					The AccountDto's <literal>address</literal> property is a JavaBean, so its nested properties are also recursively mapped.
					Recursively, the <literal>street</literal> and <literal>zip</literal> properties are automatically mapped since they are both present on the nested AddressDto and Address objects.
					Nothing is mapped to the Address's <literal>city</literal> and <literal>state</literal> properties since these properties do not exist on the AddressDto source.
				</para>
			</section>
			<section id="mapping.SpelMapper-Explicit">
				<title>Registering Explicit Mappings</title>
				<para>
K
polish  
Keith Donald 已提交
1578
					When default mapping rules are not sufficient, explicit mapping rules can be registered by obtaining a <classname>MapperBuilder</classname> and using it to construct a <classname>Mapper</classname>.
K
Keith Donald 已提交
1579
					Explicit mapping rules always override the default rule.
K
polish  
Keith Donald 已提交
1580
					The MapperBuilder provides a fluent API for registering object-to-object Mapping rules:
K
Keith Donald 已提交
1581
				</para>
K
polish  
Keith Donald 已提交
1582
				<programlisting language="java"><![CDATA[
K
builder  
Keith Donald 已提交
1583 1584 1585 1586 1587
Mapper<PersonDto, Person> mapper =
    MappingFactory.mappingBuilder(PersonDto.class, Person.class)
        .addMapping(...)
        .addMapping(...)
        .getMapper();
K
polish  
Keith Donald 已提交
1588
]]>
K
polish  
Keith Donald 已提交
1589 1590 1591 1592 1593 1594 1595 1596 1597 1598
				</programlisting>
			</section>	
			<section id="mapping.SpelMapper-Explicit-differentFieldNames">
				<title>Mapping between two fields with different names</title>
				<para>
					Suppose you need to map <literal>AccountDto.name</literal> to <literal>Account.fullName</literal>.
					Since these two field names are not the same, the default auto-mapping rule would not apply.
					Handle a requirement like this by explicitly registering a mapping rule:
				</para>
				<programlisting language="java"><![CDATA[
K
polish  
Keith Donald 已提交
1599
builder.addMapping("name", "fullName")]]>
K
polish  
Keith Donald 已提交
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612
				</programlisting>			
				<para>
					In the example above, the <literal>name</literal> field will be mapped to the <literal>fullName</literal> field when the mapper is executed.
					No default mapping will be performed for <literal>name</literal> since an explicit mapping rule has been configured for this field.
				</para>
			</section>
			<section id="mapping.SpelMapper-Explicit-singleFieldToMultipleField">
				<title>Mapping a single field to multiple fields</title>
				<para>
					Suppose you need to map <literal>PersonDto.name</literal> to <literal>Person.firstName</literal> and <literal>Person.lastName</literal>.
					Handle a field-to-multi-field requirement like this by explicitly registering a mapping rule:
				</para>
				<programlisting language="java"><![CDATA[
K
polish  
Keith Donald 已提交
1613 1614 1615 1616 1617 1618 1619 1620
builder.addMapping("name", new Mapper<String, Person>() {
    public Person map(String name, Person person) {
        String[] names = name.split(" ");
        person.setFirstName(names[0]);
        person.setLastName(names[1]);
        return person;        
    }
});]]>
K
polish  
Keith Donald 已提交
1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633
				</programlisting>			
				<para>
					In the example above, the first part of the <literal>name</literal> field will be mapped to the <literal>firstName</literal> field and the second part will be mapped to the <literal>lastName</literal> field.
					No default mapping will be performed for <literal>name</literal> since an explicit mapping rule has been configured for this field.
				</para>
			</section>
			<section id="mapping.SpelMapper-Explicit-multipleFieldsToField">
				<title>Mapping multiple fields to a single field</title>
				<para>
					Suppose you need to map <literal>CreateAccountDto.activationDay</literal> and <literal>CreateAccountDto.activationTime</literal> to <literal>Account.activationDateTime</literal>.
					Handle a multi-field-to-field requirement like this by explicitly registering a mapping rule:
				</para>
				<programlisting language="java"><![CDATA[
K
polish  
Keith Donald 已提交
1634 1635 1636 1637 1638 1639 1640 1641
builder.addMapping(new String[] { "activationDay", "activationTime" }, new Mapper<CreateAccountDto, AccountDto>() {
    public Account map(CreateAccountDto dto, Account account) {
        DateTime dateTime = ISODateTimeFormat.dateTime().parseDateTime(
            dto.getActivationDay() + "T" + dto.getActivationTime());
        account.setActivationDateTime(dateTime);
        return account;
    }
});]]>
K
polish  
Keith Donald 已提交
1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
				</programlisting>			
				<para>
					In the example above, the <literal>activationDay</literal> and <literal>activationTime</literal> fields are mapped to the single <literal>activationDateTime</literal> field.
					No default mapping is performed for <literal>activationDay</literal> or <literal>activationTime</literal> since an explicit mapping rule has been configured for these fields.
				</para>
			</section>
			<section id="mapping.SpelMapper-Explicit-conditionalMappings">
				<title>Mapping conditionally</title>
				<para>
					Suppose you need to map <literal>Map.countryCode</literal> to <literal>PhoneNumber.countryCode</literal> only if the source Map contains a international phone number.
					Handle conditional mapping requirements like this by explicitly registering a mapping rule:
				</para>
				<programlisting language="java"><![CDATA[
K
Keith Donald 已提交
1655
builder.addConditionalMapping("countryCode", "international == 'true'");]]>
K
polish  
Keith Donald 已提交
1656 1657 1658 1659 1660 1661 1662 1663 1664 1665
				</programlisting>			
				<para>
					In the example above, the <literal>countryCode</literal> field will only be mapped if the international field is 'true'.
					<literal>international == 'true'</literal> is a boolean expression that must evaluate to true for the mapping to be executed.
					No default mapping is performed for <literal>countryCode</literal> since an explicit mapping rule has been configured for this field.
				</para>
			</section>
			<section id="mapping.SpelMapper-Explicit-forcing">
				<title>Forcing Explicit Mappings</title>
				<para>
K
polish  
Keith Donald 已提交
1666
					You can force that <emphasis>all</emphasis> mapping rules be explicitly defined by disabling the "auto mapping" feature:
K
polish  
Keith Donald 已提交
1667 1668
				</para>
				<programlisting language="java"><![CDATA[
K
polish  
Keith Donald 已提交
1669
builder.setAutoMappingEnabled(false);]]>
K
polish  
Keith Donald 已提交
1670
				</programlisting>
K
Keith Donald 已提交
1671 1672
			</section>
			<section id="mapping.SpelMapper-CustomConverter">
K
polish  
Keith Donald 已提交
1673
				<title>Registering Custom Mapping Converters</title>
K
Keith Donald 已提交
1674 1675 1676 1677 1678
				<para>
					Sometimes you need to apply field specific type conversion or data transformation logic when mapping a value.
					Do this by registering a converter with a Mapping:
				</para>
				<programlisting language="java"><![CDATA[
K
polish  
Keith Donald 已提交
1679
builder.addMapping("name", "fullName").setConverter() { new Converter<String, String>() {
K
Keith Donald 已提交
1680 1681 1682 1683
    public String convert(String value) {
        // do transformation
        // return transformed value
    }
K
polish  
Keith Donald 已提交
1684 1685
});]]>
				</programlisting>
K
Keith Donald 已提交
1686 1687 1688 1689 1690
			</section>
			<section id="mapper.SpelMapper-IgnoringFields">
				<title>Ignoring Fields</title>
				<para>
					Sometimes you need to exclude a specific field on a source object from being mapped.
K
polish  
Keith Donald 已提交
1691
					Do this by marking one or more source fields as excluded:
K
Keith Donald 已提交
1692
				</para>
K
Keith Donald 已提交
1693 1694 1695
				<programlisting language="java"><![CDATA[
builder.setExcludedFields("name");]]>
				</programlisting>
K
Keith Donald 已提交
1696 1697 1698 1699
			</section>
			<section id="mapper.SpelMapper-CustomTypeConverters">
				<title>Registering Custom Type Converters</title>
				<para>
K
polish  
Keith Donald 已提交
1700
					You may also register custom Converters to convert values between mapped fields of different types:
K
Keith Donald 已提交
1701 1702
				</para>
				<programlisting language="java"><![CDATA[
K
polish  
Keith Donald 已提交
1703
builder.addConverter(new Converter<String, Date>() {
K
Keith Donald 已提交
1704 1705 1706 1707
    public Date convert(String value) {
        // do conversion
        // return transformed value    
    }
K
polish  
Keith Donald 已提交
1708 1709
});]]>
				</programlisting>
K
Keith Donald 已提交
1710
				<para>
K
polish  
Keith Donald 已提交
1711
					The example Converter above will be invoked anytime a String field is mapped to a Date field.
K
Keith Donald 已提交
1712 1713 1714 1715 1716
				</para>			
			</section>
			<section id="mapper.SpelMapper-CustomNestedMappers">
				<title>Registering Custom Nested Mappers</title>
				<para>
K
polish  
Keith Donald 已提交
1717
					When mapping between two object graphs, you may find you need to register explicit mapping rules for nested bean properties.
K
Keith Donald 已提交
1718 1719 1720
					Do this by adding a nested Mapper:
				</para>
				<programlisting language="java"><![CDATA[
K
polish  
Keith Donald 已提交
1721
builder.addNestedMapper(new Mapper<AddressDto, Address>() {
K
Keith Donald 已提交
1722 1723 1724 1725
    public Address map(AddressDto source, Address target) {
        // do target bean mapping here
        return target; 
    }
K
polish  
Keith Donald 已提交
1726 1727
});]]>
				</programlisting>
K
Keith Donald 已提交
1728
				<para>
K
polish  
Keith Donald 已提交
1729
					The example Mapper above will map nested AddressDto properties to nested Address properties.
K
polish  
Keith Donald 已提交
1730
					This particular nested Mapper is "hand-coded", but it could have easily been another Mapper instance built by a MapperBuilder.
K
Keith Donald 已提交
1731 1732 1733 1734 1735 1736
				</para>
			</section>
		</section>
		<section id="org.springframework.mapping-FurtherReading">
			<title>Further Reading</title>
			<para>
K
polish  
Keith Donald 已提交
1737
				Consult the JavaDocs of <classname>MapperFactory</classname> and <classname>MapperBuilder</classname> in the <filename>org.springframework.mapping.support</filename> package for more information on the available configuration options.
K
Keith Donald 已提交
1738 1739 1740 1741 1742 1743 1744
			</para>
			<para>
				Dozer is another general-purpose object mapper available in the open source Java community.
				Check it out at <ulink url="http://dozer.sourceforge.net">dozer.sourceforge.net</ulink>.
			</para>
		</section>	
	</section>
1745
</chapter>