Documentation fixes: SPR-5748, SPR-5723, SPR-5750, SPR-5753, SPR-5747
This commit is contained in:
@@ -2526,6 +2526,7 @@ public class ReplacementComputeValue implements MethodReplacer {
|
||||
method override would look like this:</para>
|
||||
|
||||
<programlisting language="xml"><bean id="myValueCalculator class="x.y.z.MyValueCalculator">
|
||||
|
||||
<lineannotation><!-- arbitrary method replacement --></lineannotation>
|
||||
<replaced-method name="computeValue" replacer="replacementComputeValue">
|
||||
<arg-type>String</arg-type>
|
||||
@@ -6545,7 +6546,7 @@ public Service userService() {
|
||||
protected abstract Command createCommand();
|
||||
} ]]></programlisting></para>
|
||||
|
||||
<para>Using Java-configurtion support we can easily create a
|
||||
<para>Using Java-configuration support we can easily create a
|
||||
subclass of <code>CommandManager</code> where the abstract
|
||||
<code>createCommand()</code> is overridden in such a way that it
|
||||
'looks up' a brand new (prototype) command object: <programlisting
|
||||
@@ -6851,4 +6852,4 @@ public class CachingMovieCatalog implements MovieCatalog {
|
||||
for more detail. For more on AspectJ load-time weaving, see <xref
|
||||
linkend="aop-aj-ltw" />.</para>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
||||
|
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
||||
<chapter id="expressions">
|
||||
<title>Spring Expression Language (SpEL)</title>
|
||||
|
||||
@@ -12,24 +11,24 @@
|
||||
expression language that supports querying and manipulating an object
|
||||
graph at runtime. The language syntax is similar to Unified EL but offers
|
||||
additional features, most notably method invocation and basic string
|
||||
templating functionality. </para>
|
||||
templating functionality.</para>
|
||||
|
||||
<para>While there are several other Java expression languages available,
|
||||
OGNL, MVEL, and JBoss EL, to name a few, the Spring Expression Language
|
||||
was created to provide the Spring community with a single well supported
|
||||
expression language that can used across all the products in the Spring
|
||||
expression language that can be used across all the products in the Spring
|
||||
portfolio. Its language features are driven by the requirements of the
|
||||
projects in the Spring portfolio, including tooling requirements for code
|
||||
completion support within the eclipse based SpringSource Tool Suite. That
|
||||
said, SpEL is based on an technology agnostic API allowing other
|
||||
expression language implementations to be integreated should the need
|
||||
expression language implementations to be integrated should the need
|
||||
arise.</para>
|
||||
|
||||
<para>While SpEL serves as the foundation for expression evaluation within
|
||||
the Spring portfolio, it is not directly tied to Spring and can be used
|
||||
independently. In order to be self contained, many of the examples in this
|
||||
chapter use SpEL as if it was an independent expression language. This
|
||||
requires creating a few boostrapping infrastructure classes such as the
|
||||
requires creating a few bootstrapping infrastructure classes such as the
|
||||
parser. Most Spring users will not need to deal with this infrastructure
|
||||
and will instead only author expression strings for evaluation. An example
|
||||
of this typical use is the integration of SpEL into creating XML or
|
||||
@@ -38,16 +37,16 @@
|
||||
definitions.</link></para>
|
||||
|
||||
<para>This chapter covers the features of the expression language, its
|
||||
API, and its language sytnax. In several places an Inventor and Inventor's
|
||||
API, and its language syntax. In several places an Inventor and Inventor's
|
||||
Society class are used as the target objects for expression evaluation.
|
||||
These class declarations and the data used to populate them are listed at
|
||||
the end of the chapter. </para>
|
||||
the end of the chapter.</para>
|
||||
</section>
|
||||
|
||||
<section id="expressions-features">
|
||||
<title>Feature Overview</title>
|
||||
|
||||
<para>The expression language support the following functionality</para>
|
||||
<para>The expression language supports the following functionality</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
@@ -126,11 +125,11 @@
|
||||
<para><programlisting language="java">ExpressionParser parser = new SpelAntlrExpressionParser();
|
||||
Expression exp = parser.parseExpression("<emphasis role="bold">'Hello World'</emphasis>");
|
||||
String message = (String) exp.getValue();</programlisting>The value of the
|
||||
message variable is simply 'Hello World'. </para>
|
||||
message variable is simply 'Hello World'.</para>
|
||||
|
||||
<para>The SpEL classes and interfaces you are most likely to use are
|
||||
located in the packages <package>org.springframework.expression</package>
|
||||
and its subpackages <package>spel.antlr</package> and
|
||||
and its sub packages <package>spel.antlr</package> and
|
||||
<package>spel.support</package>.</para>
|
||||
|
||||
<para>The expression language is based on a grammar and uses ANTLR to
|
||||
@@ -143,10 +142,10 @@ String message = (String) exp.getValue();</programlisting>The value of the
|
||||
can be thrown, <classname>ParseException</classname> and
|
||||
<classname>EvaluationException</classname> when calling
|
||||
'<literal>parser.parseExpression</literal>' and
|
||||
'<literal>exp.getValue</literal>' respectedly.</para>
|
||||
'<literal>exp.getValue</literal>' respectfully.</para>
|
||||
|
||||
<para>SpEL supports a wide range of features, such a calling methods,
|
||||
accessing properties and calling constructors. </para>
|
||||
<para>SpEL supports a wide range of features, such as calling methods,
|
||||
accessing properties and calling constructors.</para>
|
||||
|
||||
<para>As an example of method invocation, we call the 'concat' method on
|
||||
the string literal</para>
|
||||
@@ -155,23 +154,28 @@ String message = (String) exp.getValue();</programlisting>The value of the
|
||||
Expression exp = parser.parseExpression("<emphasis role="bold">'Hello World'.concat('!')</emphasis>");
|
||||
String message = (String) exp.getValue();</programlisting>
|
||||
|
||||
<para>The value of message is now 'Hello World!'. </para>
|
||||
<para>The value of message is now 'Hello World!'.</para>
|
||||
|
||||
<para>As an example of calling a JavaBean property, the String property
|
||||
'Bytes' can be called as shown below</para>
|
||||
|
||||
<programlisting language="java">ExpressionParser parser = new SpelAntlrExpressionParser();
|
||||
Expression exp = parser.parseExpression("<emphasis role="bold">'Hello World'.bytes</emphasis>"); // invokes 'getBytes()'
|
||||
|
||||
// invokes 'getBytes()'
|
||||
Expression exp = parser.parseExpression("<emphasis role="bold">'Hello World'.bytes</emphasis>");
|
||||
|
||||
byte[] bytes = (byte[]) exp.getValue();</programlisting>
|
||||
|
||||
<para>
|
||||
SpEL also supports nested properties using standard 'dot' notation, i.e.
|
||||
prop1.prop2.prop3 and the setting of property values</para>
|
||||
<para>SpEL also supports nested properties using standard 'dot' notation,
|
||||
i.e. prop1.prop2.prop3 and the setting of property values</para>
|
||||
|
||||
<para>Public fields may also be accessed</para>
|
||||
|
||||
<programlisting language="java">ExpressionParser parser = new SpelAntlrExpressionParser();
|
||||
Expression exp = parser.parseExpression("<emphasis role="bold">'Hello World'.bytes.length</emphasis>"); // invokes 'getBytes().length'
|
||||
|
||||
// invokes 'getBytes().length'
|
||||
Expression exp = parser.parseExpression("<emphasis role="bold">'Hello World'.bytes.length</emphasis>");
|
||||
|
||||
int length = (Integer) exp.getValue();</programlisting>
|
||||
|
||||
<para>The String's constructor can be called instead of using a string
|
||||
@@ -191,7 +195,7 @@ String message = exp.getValue(String.class);</programlisting>
|
||||
<para>The more common usage of SpEL is provide an expression string that
|
||||
is evaluated against a specific object instance. In the following example
|
||||
we retrieve the <literal>Name</literal> property from an instance of the
|
||||
Inventor class. </para>
|
||||
Inventor class.</para>
|
||||
|
||||
<para><programlisting language="java">// Create and set a calendar
|
||||
GregorianCalendar c = new GregorianCalendar();
|
||||
@@ -211,7 +215,7 @@ String name = (String) exp.getValue(context);</programlisting>In the last
|
||||
Tesla". The class StandardEvaluationContext is where you can specify which
|
||||
object the "Name" property will be evaluated against. You can reuse the
|
||||
same expression over and over again and set a new root object on the
|
||||
evaluation context. Expressions are evaluated using reflection. </para>
|
||||
evaluation context. Expressions are evaluated using reflection.</para>
|
||||
|
||||
<para><note>
|
||||
<para>In standalone usage of SpEL you will need to create the parser
|
||||
@@ -227,10 +231,10 @@ String name = (String) exp.getValue(context);</programlisting>In the last
|
||||
boolean result = exp.getValue(context, Boolean.class); // evaluates to true</programlisting>
|
||||
|
||||
<section>
|
||||
<title>The EvaluationContext interface </title>
|
||||
<title>The EvaluationContext interface</title>
|
||||
|
||||
<para>The interface <interfacename>EvaluationContext</interfacename> is
|
||||
used when evaluating an expression to resolve properties, methods,
|
||||
used when evaluating an expression to resolve properties, methods,
|
||||
fields, and to help perform type conversion. The out-of-the-box
|
||||
implementation, <classname>StandardEvaluationContext</classname>, uses
|
||||
reflection to manipulate the object, caching
|
||||
@@ -257,22 +261,24 @@ boolean result = exp.getValue(context, Boolean.class); // evaluates to true</pr
|
||||
<section>
|
||||
<title>Type Conversion</title>
|
||||
|
||||
<para>By default SpEL uses the conversion service available in
|
||||
Spring core (<literal>org.springframework.core.convert.ConversionService</literal>).
|
||||
This conversion service comes with many converters built in for common conversions
|
||||
but is also fully extensible so custom conversions between
|
||||
types can be added. Additionally it has the key capability that it
|
||||
is generics aware. This means that when working with generic types in
|
||||
expressions, SpEL will attempt conversions to maintain type correctness for any
|
||||
objects it encounters.
|
||||
</para>
|
||||
|
||||
<para>What does this mean in practice? Suppose assignment, using <literal>setValue()</literal>,
|
||||
is being used to set a <literal>List</literal> property. The type of the property is
|
||||
actually <literal>List<Boolean></literal>. SpEL will recognize that the elements
|
||||
of the list need to be converted to <literal>Boolean</literal> before being placed in it.
|
||||
A simple example:</para>
|
||||
|
||||
<para>By default SpEL uses the conversion service available in Spring
|
||||
core
|
||||
(<literal>org.springframework.core.convert.ConversionService</literal>).
|
||||
This conversion service comes with many converters built in for common
|
||||
conversions but is also fully extensible so custom conversions between
|
||||
types can be added. Additionally it has the key capability that it is
|
||||
generics aware. This means that when working with generic types in
|
||||
expressions, SpEL will attempt conversions to maintain type
|
||||
correctness for any objects it encounters.</para>
|
||||
|
||||
<para>What does this mean in practice? Suppose assignment, using
|
||||
<literal>setValue()</literal>, is being used to set a
|
||||
<literal>List</literal> property. The type of the property is actually
|
||||
<literal>List<Boolean></literal>. SpEL will recognize that the
|
||||
elements of the list need to be converted to
|
||||
<literal>Boolean</literal> before being placed in it. A simple
|
||||
example:</para>
|
||||
|
||||
<programlisting>class Simple {
|
||||
public List<Boolean> booleanList = new ArrayList<Boolean>();
|
||||
}
|
||||
@@ -395,33 +401,33 @@ Boolean b = simple.booleanList.get(0);
|
||||
|
||||
<programlisting language="java">public class SimpleMovieLister {
|
||||
|
||||
private MovieFinder movieFinder;
|
||||
private String defaultLocale;
|
||||
private MovieFinder movieFinder;
|
||||
private String defaultLocale;
|
||||
|
||||
@Autowired
|
||||
public void configure(MovieFinder movieFinder,
|
||||
@Value("#{ systemProperties['user.region'] } String defaultLocale) {
|
||||
this.movieFinder = movieFinder;
|
||||
this.defaultLocale = defaultLocale;
|
||||
}
|
||||
@Autowired
|
||||
public void configure(MovieFinder movieFinder,
|
||||
@Value("#{ systemProperties['user.region']"} String defaultLocale) {
|
||||
this.movieFinder = movieFinder;
|
||||
this.defaultLocale = defaultLocale;
|
||||
}
|
||||
|
||||
// ...
|
||||
// ...
|
||||
}</programlisting>
|
||||
|
||||
<para><programlisting language="java">public class MovieRecommender {
|
||||
|
||||
private String defaultLocale;
|
||||
private String defaultLocale;
|
||||
|
||||
private CustomerPreferenceDao customerPreferenceDao;
|
||||
private CustomerPreferenceDao customerPreferenceDao;
|
||||
|
||||
@Autowired
|
||||
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao,
|
||||
@Value("#{ systemProperties['user.country'] } String defaultLocale) {
|
||||
this.customerPreferenceDao = customerPreferenceDao;
|
||||
this.defaultLocale = defaultLocale;
|
||||
}
|
||||
@Autowired
|
||||
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao,
|
||||
@Value("#{ systemProperties['user.country']"} String defaultLocale) {
|
||||
this.customerPreferenceDao = customerPreferenceDao;
|
||||
this.defaultLocale = defaultLocale;
|
||||
}
|
||||
|
||||
// ...
|
||||
// ...
|
||||
}</programlisting></para>
|
||||
</section>
|
||||
</section>
|
||||
@@ -438,15 +444,17 @@ Boolean b = simple.booleanList.get(0);
|
||||
the backslash character. The following listing shows simple usage of
|
||||
literals. Typically they would not be used in isolation like this, but
|
||||
as part of a more complex expression, for example using a literal on one
|
||||
side of a logical comparison operator. </para>
|
||||
side of a logical comparison operator.</para>
|
||||
|
||||
<programlisting language="java">ExpressionParser parser = new SpelAntlrExpressionParser();
|
||||
|
||||
String helloWorld = (String) parser.parseExpression("'Hello World'").getValue(); // evals to "Hello World"
|
||||
// evals to "Hello World"
|
||||
String helloWorld = (String) parser.parseExpression("'Hello World'").getValue();
|
||||
|
||||
double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();
|
||||
|
||||
int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue(); // evals to 2147483647
|
||||
// evals to 2147483647
|
||||
int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();
|
||||
|
||||
boolean trueValue = (Boolean) parser.parseExpression("true").getValue();
|
||||
|
||||
@@ -463,19 +471,20 @@ Object nullValue = parser.parseExpression("null").getValue();
|
||||
|
||||
<para>Navigating with property references is easy, just use a period to
|
||||
indicate a nested property value. The instances of Inventor class, pupin
|
||||
and tesla, were populated with data listed in section Section <link
|
||||
and tesla, were populated with data listed in the section <link
|
||||
linkend="expressions-example-classes">Classes used in the
|
||||
examples</link>. To navigate "down" and get Tesla's year of birth and
|
||||
Pupin's city of birth the following expressions are used </para>
|
||||
Pupin's city of birth the following expressions are used</para>
|
||||
|
||||
<programlisting lang="" language="java">int year = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(context); // 1856
|
||||
<programlisting lang="" language="java">// evals to 1856
|
||||
int year = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(context);
|
||||
|
||||
|
||||
String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context);</programlisting>
|
||||
|
||||
<para>Case insensitivity is allowed for the first letter of property
|
||||
names. The contents of arrays and lists are obtained using square
|
||||
bracket notation. </para>
|
||||
bracket notation.</para>
|
||||
|
||||
<programlisting language="java">ExpressionParser parser = new SpelAntlrExpressionParser();
|
||||
|
||||
@@ -484,7 +493,8 @@ StandardEvaluationContext teslaContext = new StandardEvaluationContext();
|
||||
teslaContext.setRootObject(tesla);
|
||||
|
||||
// evaluates to "Induction motor"
|
||||
String invention = parser.parseExpression("inventions[3]").getValue(teslaContext, String.class);
|
||||
String invention = parser.parseExpression("inventions[3]").getValue(teslaContext,
|
||||
String.class);
|
||||
|
||||
|
||||
// Members List
|
||||
@@ -496,23 +506,27 @@ String name = parser.parseExpression("Members[0].Name").getValue(societyContext,
|
||||
|
||||
// List and Array navigation
|
||||
// evaluates to "Wireless communication"
|
||||
String invention = parser.parseExpression("Members[0].Inventions[6]").getValue(societyContext, String.class);
|
||||
String invention = parser.parseExpression("Members[0].Inventions[6]").getValue(societyContext,
|
||||
String.class);
|
||||
</programlisting>
|
||||
|
||||
<para>The contents of maps are obtained by specifying the
|
||||
literal key value within the brackets. In this case, because keys for
|
||||
the Officers map are strings, we can specify string
|
||||
literal.</para>
|
||||
<para>The contents of maps are obtained by specifying the literal key
|
||||
value within the brackets. In this case, because keys for the Officers
|
||||
map are strings, we can specify string literal.</para>
|
||||
|
||||
<programlisting lang="" language="java">// Officer's Dictionary
|
||||
|
||||
Inventor pupin = parser.parseExpression("Officers['president']").getValue(societyContext, Inventor.class);
|
||||
Inventor pupin = parser.parseExpression("Officers['president']").getValue(societyContext,
|
||||
Inventor.class);
|
||||
|
||||
// evaluates to "Idvor"
|
||||
String city = parser.parseExpression("Officers['president'].PlaceOfBirth.City").getValue(societyContext, String.class);
|
||||
String city =
|
||||
parser.parseExpression("Officers['president'].PlaceOfBirth.City").getValue(societyContext,
|
||||
String.class);
|
||||
|
||||
// setting values
|
||||
parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").setValue(societyContext, "Croatia");
|
||||
parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").setValue(societyContext,
|
||||
"Croatia");
|
||||
|
||||
</programlisting>
|
||||
</section>
|
||||
@@ -527,7 +541,8 @@ parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").setValue(
|
||||
String c = parser.parseExpression("'abc'.substring(2, 3)").getValue(String.class);
|
||||
|
||||
// evaluates to true
|
||||
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(societyContext, Boolean.class);</programlisting>
|
||||
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(societyContext,
|
||||
Boolean.class);</programlisting>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -538,7 +553,7 @@ boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(
|
||||
|
||||
<para>The relational operators; equal, not equal, less than, less than
|
||||
or equal, greater than, and greater than or equal are supported using
|
||||
standard operator notation. </para>
|
||||
standard operator notation.</para>
|
||||
|
||||
<para><programlisting language="java">// evaluates to true
|
||||
boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class);
|
||||
@@ -555,10 +570,12 @@ boolean trueValue = parser.parseExpression("'black' < 'block'").getValue(Bool
|
||||
boolean falseValue = parser.parseExpression("'xyz' instanceof T(int)").getValue(Boolean.class);
|
||||
|
||||
// evaluates to true
|
||||
boolean trueValue = parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
|
||||
boolean trueValue =
|
||||
parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
|
||||
|
||||
//evaluates to false
|
||||
boolean falseValue = parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
|
||||
boolean falseValue =
|
||||
parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
|
||||
|
||||
</programlisting>
|
||||
</section>
|
||||
@@ -605,12 +622,13 @@ boolean falseValue = parser.parseExpression(expression).getValue(societyContext,
|
||||
Subtraction can be used on numbers and dates. Multiplication and
|
||||
division can be used only on numbers. Other mathematical operators
|
||||
supported are modulus (%) and exponential power (^). Standard operator
|
||||
precedence is enforced. These operators are demonstrated below </para>
|
||||
precedence is enforced. These operators are demonstrated below</para>
|
||||
|
||||
<para><programlisting language="java">// Addition
|
||||
int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2
|
||||
|
||||
String testString = parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class); // 'test string'
|
||||
String testString =
|
||||
parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class); // 'test string'
|
||||
|
||||
// Subtraction
|
||||
int four = parser.parseExpression("1 - -3").getValue(Integer.class); // 4
|
||||
@@ -644,7 +662,7 @@ int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class);
|
||||
<para>Setting of a property is done by using the assignment operator.
|
||||
This would typically be done within a call to
|
||||
<literal>setValue</literal> but can also be done inside a call to
|
||||
<literal>getValue</literal> </para>
|
||||
<literal>getValue</literal></para>
|
||||
|
||||
<programlisting language="java">Inventor inventor = new Inventor();
|
||||
StandardEvaluationContext inventorContext = new StandardEvaluationContext();
|
||||
@@ -654,7 +672,8 @@ parser.parseExpression("Name").setValue(inventorContext, "Alexander Seovic2");
|
||||
|
||||
// alternatively
|
||||
|
||||
String aleks = parser.parseExpression("Name = 'Alexandar Seovic'").getValue(inventorContext, String.class);
|
||||
String aleks = parser.parseExpression("Name = 'Alexandar Seovic'").getValue(inventorContext,
|
||||
String.class);
|
||||
</programlisting>
|
||||
|
||||
<para></para>
|
||||
@@ -665,18 +684,20 @@ String aleks = parser.parseExpression("Name = 'Alexandar Seovic'").getValue(inve
|
||||
|
||||
<para>The special 'T' operator can be used to specify an instance of
|
||||
java.lang.Class (the 'type'). Static methods are invoked using this
|
||||
operator as well. The <classname>StandardEvaluationContext</classname>
|
||||
uses a <classname>TypeLocator</classname> to find types and
|
||||
the <classname>StandardTypeLocator</classname> (which can be replaced)
|
||||
is built with an understanding of the java.lang package. This means T()
|
||||
references to types within java.lang do not need to be fully qualified,
|
||||
operator as well. The <classname>StandardEvaluationContext</classname>
|
||||
uses a <classname>TypeLocator</classname> to find types and the
|
||||
<classname>StandardTypeLocator</classname> (which can be replaced) is
|
||||
built with an understanding of the java.lang package. This means T()
|
||||
references to types within java.lang do not need to be fully qualified,
|
||||
but all other type references must be.</para>
|
||||
|
||||
<programlisting language="java">Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
|
||||
|
||||
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
|
||||
|
||||
boolean trueValue = parser.parseExpression("T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR").getValue(Boolean.class);
|
||||
boolean trueValue =
|
||||
parser.parseExpression("T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
|
||||
.getValue(Boolean.class);
|
||||
</programlisting>
|
||||
</section>
|
||||
|
||||
@@ -688,19 +709,23 @@ boolean trueValue = parser.parseExpression("T(java.math.RoundingMode).CEILING &l
|
||||
String (where int, float, etc, can be used).</para>
|
||||
|
||||
<programlisting language="java">Inventor einstein =
|
||||
parser.parseExpression("new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')").getValue(Inventor.class);
|
||||
p.parseExpression("new org.spring.samples.spel.inventor.Inventor('Albert Einstein',
|
||||
'German')")
|
||||
.getValue(Inventor.class);
|
||||
|
||||
//create new inventor instance within add method of List
|
||||
parser.parseExpression("Members.add(new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German'))").getValue(societyContext);
|
||||
p.parseExpression("Members.add(new org.spring.samples.spel.inventor.Inventor('Albert Einstein',
|
||||
'German'))")
|
||||
.getValue(societyContext);
|
||||
</programlisting>
|
||||
</section>
|
||||
|
||||
<section id="expressions-ref-variables">
|
||||
<title>Variables</title>
|
||||
|
||||
<para>Variables can referenced in the expression using the syntax
|
||||
<para>Variables can be referenced in the expression using the syntax
|
||||
#variableName. Variables are set using the method setVariable on the
|
||||
StandardEvaluationContext. </para>
|
||||
StandardEvaluationContext.</para>
|
||||
|
||||
<programlisting language="java">Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
@@ -716,9 +741,9 @@ System.out.println(tesla.getName()) // "Mike Tesla"</programlisting>
|
||||
<section>
|
||||
<title>The #this variable</title>
|
||||
|
||||
<para>The variable #this is always defined and refers to the
|
||||
current evaluation object (the object against which unqualified
|
||||
references will be resolved). </para>
|
||||
<para>The variable #this is always defined and refers to the current
|
||||
evaluation object (the object against which unqualified references
|
||||
will be resolved).</para>
|
||||
|
||||
<programlisting language="java">// create an array of integers
|
||||
List<Integer> primes = new ArrayList<Integer>();
|
||||
@@ -730,10 +755,13 @@ StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
context.setVariable("primes",primes);
|
||||
|
||||
// all prime numbers > 10 from the list (using selection ?{...})
|
||||
List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression("#primes.?[#this>10]").getValue(context);
|
||||
// evaluates to [11, 13, 17]
|
||||
List<Integer> primesGreaterThanTen =
|
||||
(List<Integer>) parser.parseExpression("#primes.?[#this>10]").getValue(context);
|
||||
|
||||
//evaluates to [11, 13, 17]</programlisting>
|
||||
</programlisting>
|
||||
</section>
|
||||
|
||||
<!--
|
||||
<section>
|
||||
<title>The #root variable</title>
|
||||
@@ -772,7 +800,7 @@ List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExp
|
||||
|
||||
public static String reverseString(String input) {
|
||||
StringBuilder backwards = new StringBuilder();
|
||||
for (int i = 0; i < input.length(); i++) {
|
||||
for (int i = 0; i < input.length(); i++)
|
||||
backwards.append(input.charAt(input.length() - 1 - i));
|
||||
}
|
||||
return backwards.toString();
|
||||
@@ -786,18 +814,21 @@ List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExp
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
|
||||
context.registerFunction("reverseString",
|
||||
StringUtils.class.getDeclaredMethod("reverseString", new Class[] { String.class }));
|
||||
StringUtils.class.getDeclaredMethod("reverseString",
|
||||
new Class[] { String.class }));
|
||||
|
||||
String helloWorldReversed = parser.parseExpression("#reverseString('hello')").getValue(context, String.class);</programlisting>
|
||||
String helloWorldReversed =
|
||||
parser.parseExpression("#reverseString('hello')").getValue(context, String.class);</programlisting>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Ternary Operator (If-Then-Else)</title>
|
||||
|
||||
<para>You can use the ternary operator for performing if-then-else
|
||||
conditional logic inside the expression. A minimal example is; </para>
|
||||
conditional logic inside the expression. A minimal example is;</para>
|
||||
|
||||
<programlisting language="java">String falseString = parser.parseExpression("false ? 'trueExp' : 'falseExp'").getValue(String.class);</programlisting>
|
||||
<programlisting language="java">String falseString =
|
||||
parser.parseExpression("false ? 'trueExp' : 'falseExp'").getValue(String.class);</programlisting>
|
||||
|
||||
<para>In this case, the boolean false results in returning the string
|
||||
value 'falseExp'. A less artificial example is shown below.</para>
|
||||
@@ -808,59 +839,65 @@ societyContext.setVariable("queryName", "Nikola Tesla");
|
||||
expression = "isMember(#queryName)? #queryName + ' is a member of the ' " +
|
||||
"+ Name + ' Society' : #queryName + ' is not a member of the ' + Name + ' Society'";
|
||||
|
||||
String queryResultString = parser.parseExpression(expression).getValue(societyContext, String.class);
|
||||
String queryResultString =
|
||||
parser.parseExpression(expression).getValue(societyContext, String.class);
|
||||
// queryResultString = "Nikola Tesla is a member of the IEEE Society"</programlisting>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Collection Selection</title>
|
||||
|
||||
<para>Selection is a powerful expression language feature that
|
||||
allow you to transform some source collection into another by selecting
|
||||
from its entries.</para>
|
||||
<para>Selection is a powerful expression language feature that allow you
|
||||
to transform some source collection into another by selecting from its
|
||||
entries.</para>
|
||||
|
||||
<para>Selection uses the syntax <literal>?[selectionExpression]</literal>. This will
|
||||
filter the collection and return a new collection containing a subset of the
|
||||
original elements. For example, selection would allow us to easily
|
||||
get a list of Serbian inventors:</para>
|
||||
<para>Selection uses the syntax
|
||||
<literal>?[selectionExpression]</literal>. This will filter the
|
||||
collection and return a new collection containing a subset of the
|
||||
original elements. For example, selection would allow us to easily get a
|
||||
list of Serbian inventors:</para>
|
||||
|
||||
<programlisting language="java">List<Inventor> list = (List<Inventor>) parser.parseExpression("Members.?[Nationality == 'Serbian']").getValue(societyContext);</programlisting>
|
||||
<programlisting language="java">List<Inventor> list = (List<Inventor>)
|
||||
parser.parseExpression("Members.?[Nationality == 'Serbian']").getValue(societyContext);</programlisting>
|
||||
|
||||
<para>Selection is possible upon both lists and maps. In the former case
|
||||
the selection criteria is evaluated against each individual list element
|
||||
whilst against a map the selection criteria is evaluated against each
|
||||
map entry (objects of the Java type <literal>Map.Entry</literal>). Map
|
||||
entries have their key and value accessible as properties for use in the
|
||||
selection.</para>
|
||||
|
||||
<para>This expression will return a new map consisting of those elements
|
||||
of the original map where the entry value is less than 27.</para>
|
||||
|
||||
<para>Selection is possible upon both lists and maps. In the former case the
|
||||
selection criteria is evaluated against each individual list element whilst against
|
||||
a map the selection criteria is evaluated against each map entry (objects of the Java
|
||||
type <literal>Map.Entry</literal>). Map entries have their key and value accessible
|
||||
as properties for use in the selection.</para>
|
||||
|
||||
<para>This expression will return a new map consisting of those elements of the
|
||||
original map where the entry value is less than 27.</para>
|
||||
|
||||
<programlisting language="java">Map newMap = parser.parseExpression("map.?[value<27]").getValue();</programlisting>
|
||||
|
||||
<para>In addition to returning all the selected elements, it is possible to retrieve
|
||||
just the first or the last value. To obtain the first entry matching the selection
|
||||
the syntax is <literal>^[...]</literal> whilst to obtain the last matching selection
|
||||
the syntax is <literal>$[...]</literal>.
|
||||
</para>
|
||||
|
||||
<para>In addition to returning all the selected elements, it is possible
|
||||
to retrieve just the first or the last value. To obtain the first entry
|
||||
matching the selection the syntax is <literal>^[...]</literal> whilst to
|
||||
obtain the last matching selection the syntax is
|
||||
<literal>$[...]</literal>.</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<title>Collection Projection</title>
|
||||
|
||||
<para>Projection allows a collection to drive the evaluation of a sub-expression and
|
||||
the result is a new collection. The syntax for projection is <literal>![projectionExpression]</literal>.
|
||||
Most easily understood by example, suppose we have
|
||||
a list of inventors but want the list of cities where they were born. Effectively
|
||||
we want to evaluate 'placeOfBirth.city' for every entry in the inventor list. Using
|
||||
|
||||
<para>Projection allows a collection to drive the evaluation of a
|
||||
sub-expression and the result is a new collection. The syntax for
|
||||
projection is <literal>![projectionExpression]</literal>. Most easily
|
||||
understood by example, suppose we have a list of inventors but want the
|
||||
list of cities where they were born. Effectively we want to evaluate
|
||||
'placeOfBirth.city' for every entry in the inventor list. Using
|
||||
projection:</para>
|
||||
|
||||
|
||||
<programlisting language="java">// returns [ 'Smiljan', 'Idvor' ]
|
||||
List placesOfBirth = (List)parser.parseExpression("Members.![placeOfBirth.city]");</programlisting>
|
||||
|
||||
<para>A map can also be used to drive projection and in this case the projection
|
||||
expression is evaluated against each entry in the map (represented as a Java
|
||||
<literal>Map.Entry</literal>). The result of a projection across a map is a list consisting
|
||||
of the evaluation of the projection expression against each map entry.</para>
|
||||
|
||||
<para>A map can also be used to drive projection and in this case the
|
||||
projection expression is evaluated against each entry in the map
|
||||
(represented as a Java <literal>Map.Entry</literal>). The result of a
|
||||
projection across a map is a list consisting of the evaluation of the
|
||||
projection expression against each map entry.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -872,7 +909,8 @@ List placesOfBirth = (List)parser.parseExpression("Members.![placeOfBirth.city]"
|
||||
<literal>${} </literal>as the delimiters. For example,</para>
|
||||
|
||||
<programlisting language="java">String randomPhrase =
|
||||
parser.parseExpression("random number is ${T(java.lang.Math).random()}", new TemplatedParserContext()).getValue(String.class);
|
||||
parser.parseExpression("random number is ${T(java.lang.Math).random()}",
|
||||
new TemplatedParserContext()).getValue(String.class);
|
||||
|
||||
// evaluates to "random number is 0.7038186818312008"</programlisting>
|
||||
|
||||
@@ -1057,4 +1095,4 @@ public class Society {
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
||||
@@ -67,10 +67,11 @@
|
||||
<section id="new-in-3-new-tutorial">
|
||||
<title>New getting started tutorial</title>
|
||||
|
||||
<para>There is now a new getting started tutorial for developing a basic
|
||||
Spring 3.0 MVC web application. This tutorial is a separate document that can
|
||||
be found at the <ulink url="http://www.springsource.org/documentation">
|
||||
Spring Documentation</ulink> page.</para>
|
||||
<para>There is now a new getting started tutorial for developing a basic
|
||||
Spring 3.0 MVC web application. This tutorial is a separate document that
|
||||
can be found at the <ulink
|
||||
url="http://www.springsource.org/documentation"> Spring
|
||||
Documentation</ulink> page.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-3-modules-build">
|
||||
@@ -205,39 +206,36 @@
|
||||
<listitem>
|
||||
<para>Early support for Java EE 6</para>
|
||||
</listitem>
|
||||
|
||||
|
||||
<listitem>
|
||||
<para>Embedded database support</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
<section id="new-feature-java5">
|
||||
<title>Core APIs updated for Java 5</title>
|
||||
|
||||
<para>BeanFactory interface returns typed bean instances as far as possible:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>T getBean(Stringname, Class<T> requiredType)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Map<String, T> getBeansOfType(Class<T> type)</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>BeanFactory interface returns typed bean instances as far as
|
||||
possible: <itemizedlist>
|
||||
<listitem>
|
||||
<para>T getBean(Stringname, Class<T> requiredType)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Map<String, T> getBeansOfType(Class<T>
|
||||
type)</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
|
||||
<para>Spring's TaskExecutor interface now extends
|
||||
<classname>java.util.concurrent.Executor</classname>:
|
||||
<itemizedlist>
|
||||
<classname>java.util.concurrent.Executor</classname>: <itemizedlist>
|
||||
<listitem>
|
||||
<para>extended AsyncTaskExecutor supports standard Callables with
|
||||
Futures</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
|
||||
<para>New Java 5 based converter API and SPI:
|
||||
<itemizedlist>
|
||||
<para>New Java 5 based converter API and SPI: <itemizedlist>
|
||||
<listitem>
|
||||
<para>stateless ConversionService and Converters</para>
|
||||
</listitem>
|
||||
@@ -297,13 +295,10 @@ public class RewardsTestDatabase {
|
||||
<section id="new-java-configuration">
|
||||
<title>Java based bean metadata</title>
|
||||
|
||||
<para>
|
||||
Some core features from the
|
||||
<ulink url="http://www.springsource.org/javaconfig">JavaConfig</ulink>
|
||||
project have been added to the Spring Framework now. This means
|
||||
that the following annotations are now directly supported:
|
||||
|
||||
<itemizedlist>
|
||||
<para>Some core features from the <ulink
|
||||
url="http://www.springsource.org/javaconfig">JavaConfig</ulink>
|
||||
project have been added to the Spring Framework now. This means that
|
||||
the following annotations are now directly supported: <itemizedlist>
|
||||
<listitem>
|
||||
<para>@Configuration</para>
|
||||
</listitem>
|
||||
@@ -327,8 +322,7 @@ public class RewardsTestDatabase {
|
||||
<listitem>
|
||||
<para>@Value</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</itemizedlist></para>
|
||||
|
||||
<para>Here is an example of a Java class providing basic configuration
|
||||
using the new JavaConfig features: <programlisting language="java">@Configuration
|
||||
@@ -383,8 +377,8 @@ public class AppConfig{
|
||||
<para>Object to XML mapping functionality (OXM) from the Spring Web
|
||||
Services project has been moved to the core Spring Framework now. The
|
||||
functionality is found in the <literal>org.springframework.oxm</literal>
|
||||
package. More information on the use of the <literal>OXM</literal> module
|
||||
can be found in the <link linkend="oxm">Marshalling XML using O/X
|
||||
package. More information on the use of the <literal>OXM</literal>
|
||||
module can be found in the <link linkend="oxm">Marshalling XML using O/X
|
||||
Mappers</link> chapter.</para>
|
||||
</section>
|
||||
|
||||
@@ -409,7 +403,7 @@ public class AppConfig{
|
||||
conversion between objects and their representation in HTTP request
|
||||
and replies.</para>
|
||||
|
||||
<para>The <classname>MarhsallingHttpMessageConverter</classname> uses
|
||||
<para>The <classname>MarshallingHttpMessageConverter</classname> uses
|
||||
the <emphasis>Object to XML mapping</emphasis> functionality mentioned
|
||||
earlier.</para>
|
||||
|
||||
@@ -449,13 +443,13 @@ public class AppConfig{
|
||||
|
||||
<para>Work in progress... not part of the Spring 3.0 M3 release.</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="new-feature-embedded-databases">
|
||||
<title>Support for embedded databases</title>
|
||||
<para>
|
||||
Convenient support for <link linkend="jdbc-embedded-database-support">embedded Java database engines</link>, including HSQL, H2, and Derby, is now provided.
|
||||
</para>
|
||||
<title>Support for embedded databases</title>
|
||||
|
||||
<para>Convenient support for <link
|
||||
linkend="jdbc-embedded-database-support">embedded Java database
|
||||
engines</link>, including HSQL, H2, and Derby, is now provided.</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
||||
|
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
||||
<chapter id="rest">
|
||||
<title>REST support</title>
|
||||
|
||||
@@ -9,7 +8,7 @@
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>The goal of Spring's REST support is to make the development of
|
||||
RESTful Web services and applications easier. </para>
|
||||
RESTful Web services and applications easier.</para>
|
||||
|
||||
<para>Client-side access to RESTful resources is greatly simplified using
|
||||
Spring <classname>RestTemplate</classname>.
|
||||
@@ -18,7 +17,7 @@
|
||||
<classname>JmsTemplate</classname>. Instead of dealing with a verbose
|
||||
lower level API such as Apache Commons <classname>HttpClient</classname>
|
||||
to create RESTful request, RestTemplate provides one liner methods that
|
||||
are purpose built for RESTful programming. </para>
|
||||
are purpose built for RESTful programming.</para>
|
||||
|
||||
<para>On the server-side, Spring's REST support is based upon Spring's
|
||||
existing annotation based MVC framework. (For those interested in the
|
||||
@@ -32,12 +31,11 @@
|
||||
header.</para>
|
||||
|
||||
<para>In this chapter we describe all the features of Spring's REST
|
||||
support. It is divided into two main two chapters, one for the server-side
|
||||
and one for the client-side. For those new to Spring's <link
|
||||
linkend="mvc">MVC framework</link>, you may want to read through the
|
||||
reference documentation on <link linkend="mvc-annotation">annotation-based
|
||||
controller configuration</link> to understand the general programming
|
||||
model.</para>
|
||||
support. It is divided into two main chapters, one for the server-side and
|
||||
one for the client-side. For those new to Spring's <link linkend="mvc">MVC
|
||||
framework</link>, you may want to read through the reference documentation
|
||||
on <link linkend="mvc-annotation">annotation-based controller
|
||||
configuration</link> to understand the general programming model.</para>
|
||||
</section>
|
||||
|
||||
<section id="rest-creating-services">
|
||||
@@ -75,7 +73,7 @@
|
||||
variable. A Spring controller method to process above example is shown
|
||||
below;</para>
|
||||
|
||||
<programlisting language="java">@RequestMapping(value="/users/{userid}", method=RequestMethod.GET)
|
||||
<programlisting language="java">@RequestMapping(value="/users/{userId}", method=RequestMethod.GET)
|
||||
public String getUser(@PathVariable String userId) {
|
||||
// implementation omitted...
|
||||
}</programlisting>
|
||||
@@ -172,7 +170,7 @@ public class RelativePathUriTemplateController {
|
||||
|
||||
<para>The <classname>@RequestBody</classname> method parameter
|
||||
annotation is used to indicate that a method parameter should be bound
|
||||
to the value of the HTTP request body. For example, </para>
|
||||
to the value of the HTTP request body. For example,</para>
|
||||
|
||||
<programlisting language="java">@RequestMapping(value = "/something", method = RequestMethod.PUT)
|
||||
public void handle(@RequestBody String body, Writer writer) throws IOException {
|
||||
@@ -182,8 +180,8 @@ public void handle(@RequestBody String body, Writer writer) throws IOException {
|
||||
<para>The conversion of the request body to the method argument is
|
||||
done using a <interfacename>HttpMessageConverter</interfacename>.
|
||||
<interfacename>HttpMessageConverter</interfacename> is responsible for
|
||||
converting from the HTTP request message to an object
|
||||
and converting from an object to the HTTP response body.
|
||||
converting from the HTTP request message to an object and converting
|
||||
from an object to the HTTP response body.
|
||||
<classname>DispatcherServlet</classname> supports annotation based
|
||||
processing using the
|
||||
<classname>DefaultAnnotationHandlerMapping</classname> and
|
||||
@@ -210,20 +208,20 @@ public void handle(@RequestBody String body, Writer writer) throws IOException {
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><classname>SourceHttpMessageConverter</classname> - convert
|
||||
<para><classname>SourceHttpMessageConverter</classname> - converts
|
||||
to/from a javax.xml.transform.Source;</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><classname>MarshallingHttpMessageConverter</classname> -
|
||||
convert to/from an object using the
|
||||
converts to/from an object using the
|
||||
<classname>org.springframework.oxm</classname> package.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>More information on these converters can be found in the section
|
||||
<link linkend="rest-message-conversion">Message Converters</link>.
|
||||
</para>
|
||||
<link linkend="rest-message-conversion">Message
|
||||
Converters</link>.</para>
|
||||
|
||||
<para>The <classname>MarshallingHttpMessageConverter</classname>
|
||||
requires a <interfacename>Marshaller</interfacename> and
|
||||
@@ -411,7 +409,7 @@ public class ContentController {
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><classname>AbstractAtomFeedView</classname> - return an Atom
|
||||
<para><classname>AbstractAtomFeedView</classname> - returns an Atom
|
||||
feed</para>
|
||||
</listitem>
|
||||
|
||||
@@ -442,7 +440,7 @@ public class ContentController {
|
||||
and RSS Feed views respectfully. They are based on java.net's <ulink
|
||||
url="https://rome.dev.java.net">ROME</ulink> project and are located
|
||||
in the package
|
||||
<literal>org.springframework.web.servlet.view.feed</literal>. </para>
|
||||
<literal>org.springframework.web.servlet.view.feed</literal>.</para>
|
||||
|
||||
<para><classname>AbstractAtomFeedView</classname> requires you to
|
||||
implement the <methodname>buildFeedEntries</methodname> method and
|
||||
@@ -488,10 +486,10 @@ public class ContentController {
|
||||
|
||||
<para>The <methodname>buildFeedItems</methodname> and
|
||||
<methodname>buildFeedEntires</methodname> pass in the HTTP request in
|
||||
case you need to access the Locale. The HTTP response in passed in
|
||||
case you need to access the Locale. The HTTP response is passed in
|
||||
only for the setting of cookies or other HTTP headers. The feed will
|
||||
automatically be written to the response object after the method
|
||||
returns. </para>
|
||||
returns.</para>
|
||||
|
||||
<para>For an example of creating a Atom view please refer to Alef
|
||||
Arendsen's SpringSource TeamBlog <ulink
|
||||
@@ -508,7 +506,11 @@ public class ContentController {
|
||||
explicitly using <classname>MarhsallingView</classname>'s
|
||||
<property>modelKey</property> bean property. Alternatively, the view
|
||||
will iterate over all model properties marhsall only those types that
|
||||
are supported by the <interfacename>Marshaller</interfacename>.</para>
|
||||
are supported by the <interfacename>Marshaller</interfacename>. For
|
||||
more information on the functionality in the
|
||||
<classname>org.springframework.oxm</classname> package refer to the
|
||||
chapter <link linkend="oxm">Marshalling XML using O/X
|
||||
Mappers</link>.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -517,7 +519,7 @@ public class ContentController {
|
||||
|
||||
<para>A key principle of REST is the use of the Uniform Interface. This
|
||||
means that all resources (URLs) can be manipulated using the same four
|
||||
HTTP method: GET, PUT, POST, and DELETE. For each methods, the HTTP
|
||||
HTTP methods: GET, PUT, POST, and DELETE. For each methods, the HTTP
|
||||
specification defines the exact semantics. For instance, a GET should
|
||||
always be a safe operation, meaning that is has no side effects, and a
|
||||
PUT or DELETE should be idempotent, meaning that you can repeat these
|
||||
@@ -566,26 +568,26 @@ public String deletePet(@PathVariable int ownerId, @PathVariable int petId) {
|
||||
used to determine change in content at a given URL. It can be considered
|
||||
to be the more sophisticated successor to the
|
||||
<literal>Last-Modified</literal> header. When a server returns a
|
||||
representation with an ETag header, client can use this header in
|
||||
subsequent GETs, in a <literal>If-None-Match</literal> header. If the
|
||||
representation with an ETag header, the client can use this header in
|
||||
subsequent GETs, in an <literal>If-None-Match</literal> header. If the
|
||||
content has not changed, the server will return <literal>304: Not
|
||||
Modified</literal>.</para>
|
||||
|
||||
<para>Support for ETags is provided by the servlet filter
|
||||
<classname>ShallowEtagHeaderFilter</classname>. Since it is a plain
|
||||
Servlet Filter, and thus can be used in combination any web framework.
|
||||
The <classname>ShallowEtagHeaderFilter</classname> filter creates
|
||||
so-called shallow ETags (as opposed to a deep ETags, more about that
|
||||
later). The way it works is quite simple: the filter simply caches the
|
||||
content of the rendered JSP (or other content), generates a MD5 hash
|
||||
over that, and returns that as a ETag header in the response. The next
|
||||
time a client sends a request for the same resource, it use that hash as
|
||||
the <literal>If-None-Match</literal> value. The filter notices this,
|
||||
renders the view again, and compares the two hashes. If they are equal,
|
||||
a <literal>304</literal> is returned. It is important to note that this
|
||||
filter will not save processing power, as the view is still rendered.
|
||||
The only thing it saves is bandwidth, as the rendered response is not
|
||||
sent back over the wire.</para>
|
||||
Servlet Filter, and thus can be used in combination with any web
|
||||
framework. The <classname>ShallowEtagHeaderFilter</classname> filter
|
||||
creates so-called shallow ETags (as opposed to deep ETags, more about
|
||||
that later). The way it works is quite simple: the filter simply caches
|
||||
the content of the rendered JSP (or other content), generates an MD5
|
||||
hash over that, and returns that as an ETag header in the response. The
|
||||
next time a client sends a request for the same resource, it uses that
|
||||
hash as the <literal>If-None-Match</literal> value. The filter notices
|
||||
this, renders the view again, and compares the two hashes. If they are
|
||||
equal, a <literal>304</literal> is returned. It is important to note
|
||||
that this filter will not save processing power, as the view is still
|
||||
rendered. The only thing it saves is bandwidth, as the rendered response
|
||||
is not sent back over the wire.</para>
|
||||
|
||||
<para>Deep ETags are a bit more complicated. In this case, the ETag is
|
||||
based on the underlying domain objects, RDMBS tables, etc. Using this
|
||||
@@ -623,18 +625,18 @@ public class SimpleController {
|
||||
the types in the list, then the method annotated with the matching
|
||||
<classname>@ExceptionHandler</classname> will be invoked. If the
|
||||
annotation value is not set then the exception types listed as method
|
||||
arguments are used. </para>
|
||||
arguments are used.</para>
|
||||
|
||||
<para>Much like standard controller methods annotated with a
|
||||
<classname>@RequestMapping</classname> annotation, the method arguments
|
||||
and return values of <classname>@ExceptionHandler</classname> methods
|
||||
are very flexible. For example, the
|
||||
<classname>HttpServletRequest</classname> can be access in Servlet
|
||||
<classname>HttpServletRequest</classname> can be accessed in Servlet
|
||||
environments and the <classname>PortletRequest</classname> in Portlet
|
||||
environments. The return type can be a <classname>String</classname>,
|
||||
which is interpreted as a view name or a
|
||||
<classname>ModelAndView</classname> object. Please refer to the API
|
||||
documentation for more details. </para>
|
||||
documentation for more details.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -655,7 +657,7 @@ public class SimpleController {
|
||||
uses the Object-to-XML framework that is part of the
|
||||
<classname>org.springframework.oxm</classname> package. This gives you a
|
||||
wide range of choices of XML to Object mapping technologies to choose
|
||||
from. </para>
|
||||
from.</para>
|
||||
|
||||
<para>This section describes how to use the
|
||||
<classname>RestTemplate</classname> and its associated
|
||||
@@ -684,9 +686,9 @@ if (HttpStatus.SC_CREATED == post.getStatusCode()) {
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para> RestTemplate provides higher level methods that correspond to
|
||||
each of the six main HTTP methods that make invoking many RESTful
|
||||
services a one-liner and enforce REST best practices.</para>
|
||||
<para>RestTemplate provides higher level methods that correspond to each
|
||||
of the six main HTTP methods that make invoking many RESTful services a
|
||||
one-liner and enforce REST best practices.</para>
|
||||
|
||||
<table>
|
||||
<title>Overview of RestTemplate methods</title>
|
||||
@@ -756,9 +758,9 @@ if (HttpStatus.SC_CREATED == post.getStatusCode()) {
|
||||
naming convention, the first part indicates what HTTP method is being
|
||||
invoked and the second part indicates what is returned. For example, the
|
||||
method <methodname>getForObject</methodname> will perform a GET, convert
|
||||
the HTTP response into an object type of your choice, and returns that
|
||||
the HTTP response into an object type of your choice and return that
|
||||
object. The method <methodname>postForLocation</methodname> will do a
|
||||
POST, converting the given object into a HTTP request, and returns the
|
||||
POST, converting the given object into a HTTP request and return the
|
||||
response HTTP Location header where the newly created object can be
|
||||
found In case of an exception processing the HTTP request, an exception
|
||||
of the type <classname>RestClientException</classname> will be
|
||||
@@ -781,20 +783,20 @@ if (HttpStatus.SC_CREATED == post.getStatusCode()) {
|
||||
|
||||
<para>Each method takes URI template arguments in two forms, either as a
|
||||
<literal>String</literal> variable length argument or a
|
||||
<literal>Map<String,String></literal>. For example, </para>
|
||||
<literal>Map<String,String></literal>. For example,</para>
|
||||
|
||||
<programlisting language="java">String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}",
|
||||
String.class,"42", "21");
|
||||
</programlisting>
|
||||
|
||||
<para>using variable length arguments and </para>
|
||||
<para>using variable length arguments and</para>
|
||||
|
||||
<programlisting language="java">Map<String, String> vars = Collections.singletonMap("hotel", 42);
|
||||
<programlisting language="java">Map<String, String> vars = Collections.singletonMap("hotel", "42");
|
||||
String result =
|
||||
restTemplate.getForObject("http://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);
|
||||
</programlisting>
|
||||
|
||||
<para>using a <literal>Map<String,String></literal>. </para>
|
||||
<para>using a <literal>Map<String,String></literal>.</para>
|
||||
|
||||
<para>To create an instance of <classname>RestTemplate</classname> you
|
||||
can simply call the default constructor. This will use standard Java
|
||||
@@ -813,7 +815,7 @@ String result =
|
||||
|
||||
<para>The previous example using Jakarta Commons
|
||||
<classname>HttpClient</classname> directly rewritten to use the
|
||||
<classname>RestTemplate</classname> is shown below </para>
|
||||
<classname>RestTemplate</classname> is shown below</para>
|
||||
|
||||
<programlisting>uri = "http://example.com/hotels/{id}/bookings";
|
||||
|
||||
@@ -836,7 +838,7 @@ URI location = template.postForLocation(uri, booking, String.class, "1");
|
||||
// also has an overload with urlVariables as a Map<String, String>.</programlisting>
|
||||
|
||||
<para>The <interfacename>RequestCallback</interfacename> interface is
|
||||
defined as </para>
|
||||
defined as</para>
|
||||
|
||||
<programlisting language="java">public interface RequestCallback {
|
||||
void doWithRequest(ClientHttpRequest request) throws IOException;
|
||||
@@ -859,7 +861,7 @@ URI location = template.postForLocation(uri, booking, String.class, "1");
|
||||
<methodname>put</methodname> are converted to HTTP requests and from
|
||||
HTTP responses by <interfacename>HttpMessageConverters</interfacename>.
|
||||
The <interfacename>HttpMessageConverter</interfacename> interface is
|
||||
show below to give you a better feel for its functionality</para>
|
||||
shown below to give you a better feel for its functionality</para>
|
||||
|
||||
<programlisting language="java">public interface HttpMessageConverter<T> {
|
||||
|
||||
@@ -883,7 +885,7 @@ URI location = template.postForLocation(uri, booking, String.class, "1");
|
||||
provided in the framework and are registered by default with the
|
||||
<classname>RestTemplate</classname> on the client-side and with
|
||||
<classname>AnnotationMethodHandlerAdapter</classname> on the
|
||||
server-side. </para>
|
||||
server-side.</para>
|
||||
|
||||
<para>The implementations of
|
||||
<classname>HttpMessageConverter</classname>s are described in the
|
||||
@@ -894,7 +896,7 @@ URI location = template.postForLocation(uri, booking, String.class, "1");
|
||||
<section id="rest-string-converter">
|
||||
<title>StringHttpMessageConverter</title>
|
||||
|
||||
<para>A <interfacename>HttpMessageConverter</interfacename>
|
||||
<para>An <interfacename>HttpMessageConverter</interfacename>
|
||||
implementation that can read and write Strings from the HTTP request
|
||||
and response. By default, this converter supports all text media types
|
||||
(<literal>text/*</literal>), and writes with a
|
||||
@@ -905,31 +907,31 @@ URI location = template.postForLocation(uri, booking, String.class, "1");
|
||||
<section id="rest-form-converter">
|
||||
<title>FormHttpMessageConverter</title>
|
||||
|
||||
<para>A <interfacename>HttpMessageConverter</interfacename>
|
||||
<para>An <interfacename>HttpMessageConverter</interfacename>
|
||||
implementation that can read and write form data from the HTTP request
|
||||
and response. By default, this converter reads and writes the media
|
||||
type (<literal>application/x-www-form-urlencoded</literal>). Form data
|
||||
is read from and written into a <literal>MultiValueMap<String,
|
||||
String></literal>. </para>
|
||||
String></literal>.</para>
|
||||
</section>
|
||||
|
||||
<section id="rest-byte-converter">
|
||||
<title>ByteArrayMessageConverter</title>
|
||||
|
||||
<para>A <interfacename>HttpMessageConverter</interfacename>
|
||||
<para>An <interfacename>HttpMessageConverter</interfacename>
|
||||
implementation that can read and write byte arrays from the HTTP
|
||||
request and response. By default, this converter supports all media
|
||||
types (<literal>*/*</literal>), and writes with a
|
||||
<literal>Content-Type</literal> of
|
||||
<literal>application/octet-stream</literal>. This can be overridden by
|
||||
setting the <property>supportedMediaTypes</property> property, and
|
||||
overriding <literal>getContentType(byte[])</literal>. </para>
|
||||
overriding <literal>getContentType(byte[])</literal>.</para>
|
||||
</section>
|
||||
|
||||
<section id="rest-marhsalling-converter">
|
||||
<title>MarshallingHttpMessageConverter</title>
|
||||
|
||||
<para>A <interfacename>HttpMessageConverter</interfacename>
|
||||
<para>An <interfacename>HttpMessageConverter</interfacename>
|
||||
implementation that can read and write XML using Spring's
|
||||
<interfacename>Marshaller</interfacename> and
|
||||
<interfacename>Unmarshaller</interfacename> abstractions from the
|
||||
@@ -944,7 +946,7 @@ URI location = template.postForLocation(uri, booking, String.class, "1");
|
||||
<section id="rest-source-converter">
|
||||
<title>SourceHttpMessageConverter</title>
|
||||
|
||||
<para>A <interfacename>HttpMessageConverter</interfacename>
|
||||
<para>An <interfacename>HttpMessageConverter</interfacename>
|
||||
implementation that can read and write
|
||||
<classname>javax.xml.transform.Source</classname> from the HTTP
|
||||
request and response. Only <classname>DOMSource</classname>,
|
||||
@@ -955,4 +957,4 @@ URI location = template.postForLocation(uri, booking, String.class, "1");
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
approach to software development is certainly advocated by
|
||||
the Spring team, and so coverage of Spring's support for
|
||||
integration testing is covered (alongside best practices for
|
||||
unit testing). The Spring team have found that the correct
|
||||
unit testing). The Spring team has found that the correct
|
||||
use of IoC certainly does make both unit and integration
|
||||
testing easier (in that the presence of setter methods and
|
||||
appropriate constructors on classes makes them
|
||||
|
||||
Reference in New Issue
Block a user