INT-2809: Add/Extract JSON JavaType Headers

* Add `AmqpHeaders` headers
* Add `JavaType` headers mapping to `DefaultAmqpHeaderMapper`
* Add ability to Json Transformers to add/extract `JavaType` headers
* Make `JsonToObjectTransformer#targetClass` as non-required and do fallback
to extract type from `JavaType` headers
* Add `JavaType` extraction in the `JsonObjectMapper` implementors

JIRA: https://jira.springsource.org/browse/INT-2809

INT-2809: Polishing and refactoring

* Introduce `JsonHeaders`, `AbstractJacksonJsonObjectMapper`
* Move `TestPerson` and `TestAddress` to package level
* Now `JsonToObjectTransformer` supports not only `String` payload
* Remove json headers after transformation in the `JsonToObjectTransformer`

INT-2809 Minor Polishing

INT-2809 Docs and What's New
This commit is contained in:
Artem Bilan
2013-10-11 17:18:01 +03:00
committed by Gary Russell
parent c389604c2e
commit 4dd95c41ea
23 changed files with 845 additions and 413 deletions

View File

@@ -206,7 +206,7 @@ public class Kid {
a BeanCreationException will be thrown. 
</note>
<para>
<emphasis>JSON Transformers</emphasis>
<emphasis role="bold">JSON Transformers</emphasis>
</para>
<para>
<emphasis>Object to JSON</emphasis> and <emphasis>JSON to Object</emphasis> transformers are provided.
@@ -279,7 +279,7 @@ public class Foo {
</para>
<important>
<para>
Beginning with version 2.2, the <code>object-to-json-transformer</code> sets the <emphasis>content-type</emphasis>
Beginning with <emphasis>version 2.2</emphasis>, the <code>object-to-json-transformer</code> sets the <emphasis>content-type</emphasis>
header to <code>application/json</code>, by default, if the input message does not already have that header
present.
</para>
@@ -290,66 +290,50 @@ public class Foo {
attribute to an empty string (<code>""</code>). This will result in a message with no <code>content-type</code>
header, unless such a header was present on the input message.
</para>
<para>
The behavior of adding the default header has a side affect - causing applications with the following
sequence to fail:
</para>
<para>
<code>->object-to-json-transformer->amqp-outbound-adapter----></code>
</para>
<para>
<code>---->amqp-inbound-adapter->json-to-object-transformer-></code>
</para>
<para>
This is because the default <classname>SimpleMessageConverter</classname> used by the inbound adapter doesn't
recognize this content type and the adapter emits a message with a <code>byte[]</code> payload instead of
<code>String</code>, which was the case with earlier versions.
</para>
<para>
If you are using this pattern, there are a number of ways to configure the environment so that JSON
conversion will be performed correctly.
</para>
<para>
One solution is to set the content type to a text type, so the inbound converter will convert the JSON to
String. This solution requires a change to just the outbound application.
</para>
<para>
<programlisting language="xml"><![CDATA[<object-to-json-transformer ... content-type="text/x-json"/>]]></programlisting>
</para>
<para>
The second solution is to eliminate the json transformers altogether and use an
<classname>org.springframework.amqp.support.converter.JsonMessageConverter</classname> on both the
outbound and inbound adapters. This configures the adapters to perform the JSON conversion and
the transformers are not necessary. The converter on the outbound adapter adds
type information to the message properties; the inbound converter uses this type information for the conversion.
The converter is provided to the adapters using the <emphasis>message-converter</emphasis> attribute.
This solution requires a change to both the inbound and outbound applications.
</para>
<para>
The third solution is to eliminate the <emphasis>json-to-object-transformer</emphasis> in just
the inbound application and use an
<classname>org.springframework.amqp.support.converter.JsonMessageConverter</classname> on the
inbound adapter. The converter
is provided to the adapter using the <emphasis>message-converter</emphasis> attribute.
However, because there will be no type information in the message properties,
this also requires adding the <emphasis>defaultType</emphasis> to the converter, using the
same type as currently configured on the <emphasis>json-to-object-transformer</emphasis>.
This solution requires a change to just the inbound application. The configuration below shows
how to configure the message converter; it requires <code>spring-amqp</code> 1.1.3 or
above.
</para>
<programlisting language="xml"><![CDATA[<bean id="jsonConverterWithPOType"
class="org.springframework.amqp.support.converter.JsonMessageConverter">
<property name="classMapper">
<bean class="org.springframework.amqp.support.converter.DefaultClassMapper">
<property name="defaultType"
value="foo.PurchaseOrder" />
</bean>
</property>
</bean>
<int-amqp:inbound-channel-adapter ... message-converter="jsonConverterWithPOType" ... />]]></programlisting>
</important>
<para>
Beginning with <emphasis>version 3.0</emphasis>, the <classname>ObjectToJsonTransformer</classname> adds headers,
reflecting the source type, to the message. Similarly, the <classname>JsonToObjectTransformer</classname> can
use those type headers when converting the JSON to an object. These headers are mapped in the AMQP adapters so that
they are entirely compatible with the Spring-AMQP
<ulink url="http://docs.spring.io/spring-amqp/api/">JsonMessageConverter</ulink>.
</para>
<para>
This enables the following flows to work without any special configuration...
</para>
<para>
<code>...->amqp-outbound-adapter----></code>
</para>
<para>
<code>---->amqp-inbound-adapter->json-to-object-transformer->...</code>
</para>
<para>
Where the outbound adapter is configured with a <classname>JsonMessageConverter</classname> and the
inbound adapter uses the default <classname>SimpleMessageConverter</classname>.
</para>
<para>
<code>...->object-to-json-transformer->amqp-outbound-adapter----></code>
</para>
<para>
<code>---->amqp-inbound-adapter->...</code>
</para>
<para>
Where the outbound adapter is configured with a <classname>SimpleMessageConverter</classname> and the
inbound adapter uses the default <classname>JsonMessageConverter</classname>.
</para>
<para>
<code>...->object-to-json-transformer->amqp-outbound-adapter----></code>
</para>
<para>
<code>---->amqp-inbound-adapter->json-to-object-transformer-></code>
</para>
<para>
Where both adapters are configured with a <classname>SimpleMessageConverter</classname>.
</para>
<note>
When using the headers to determine the type, you should <emphasis role="bold">not</emphasis> provide
a <code>class</code> attribute, because it takes precedence over the headers.
</note>
<para>
In addition to JSON Transformers, Spring Integration provides a built-in <emphasis>#jsonPath</emphasis>
SpEL function for use in expressions. For more information see <xref linkend="spel"/>.

View File

@@ -325,10 +325,20 @@
<section id="3.0-json-transformers">
<title>Jackson Support (JSON)</title>
<para>
A new abstraction for JSON conversion has been introduced. Implementations for Jackson 1.x
and Jackson 2 are currently provided, with the version being determined by presence on
the classpath. Previously, only Jackson 1.x was supported. For more information,
see 'JSON Transformers' in <xref linkend="transformer"/>.
<itemizedlist>
<listitem>
A new abstraction for JSON conversion has been introduced. Implementations for Jackson 1.x
and Jackson 2 are currently provided, with the version being determined by presence on
the classpath. Previously, only Jackson 1.x was supported.
</listitem>
<listitem>
The <classname>ObjectToJsonTransformer</classname> and <classname>JsonToObjectTransformer</classname>
now emit/consume headers containing type information.
</listitem>
</itemizedlist>
</para>
<para>
For more information, see 'JSON Transformers' in <xref linkend="transformer"/>.
</para>
</section>
<section id="3.0-http-endpointss">