blob: 7ab6b107d7b561a859aae239678c6099f12bc046 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="Date-Revision-yyyymmdd" content="20140918"/>
<meta http-equiv="Content-Language" content="en"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>JSON plugin</title>
<link href="//fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,400italic,600italic,700italic" rel="stylesheet" type="text/css">
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
<link href="/css/main.css" rel="stylesheet">
<link href="/css/custom.css" rel="stylesheet">
<link href="/highlighter/github-theme.css" rel="stylesheet">
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="/bootstrap/js/bootstrap.js"></script>
<script type="text/javascript" src="/js/community.js"></script>
</head>
<body>
<a href="http://github.com/apache/struts" class="github-ribbon">
<img style="position: absolute; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub">
</a>
<header>
<nav>
<div role="navigation" class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" data-toggle="collapse" data-target="#struts-menu" class="navbar-toggle">
Menu
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="/index.html" class="navbar-brand logo"><img src="/img/struts-logo.svg"></a>
</div>
<div id="struts-menu" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Home<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/index.html">Welcome</a></li>
<li><a href="/download.cgi">Download</a></li>
<li><a href="/releases.html">Releases</a></li>
<li><a href="/announce.html">Announcements</a></li>
<li><a href="http://www.apache.org/licenses/">License</a></li>
<li><a href="https://www.apache.org/foundation/thanks.html">Thanks!</a></li>
<li><a href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Support<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/mail.html">User Mailing List</a></li>
<li><a href="https://issues.apache.org/jira/browse/WW">Issue Tracker</a></li>
<li><a href="/security.html">Reporting Security Issues</a></li>
<li class="divider"></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Migration+Guide">Version Notes</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Security+Bulletins">Security Bulletins</a></li>
<li class="divider"></li>
<li><a href="/maven/project-info.html">Maven Project Info</a></li>
<li><a href="/maven/struts2-core/dependencies.html">Struts Core Dependencies</a></li>
<li><a href="/maven/struts2-plugins/modules.html">Plugin Dependencies</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Documentation<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/birdseye.html">Birds Eye</a></li>
<li><a href="/primer.html">Key Technologies</a></li>
<li><a href="/kickstart.html">Kickstart FAQ</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Home">Wiki</a></li>
<li class="divider"></li>
<li><a href="/getting-started/">Getting Started</a></li>
<li><a href="/security/">Security Guide</a></li>
<li><a href="/core-developers/">Core Developers Guide</a></li>
<li><a href="/tag-developers/">Tag Developers Guide</a></li>
<li><a href="/maven-archetypes/">Maven Archetypes</a></li>
<li><a href="/plugins/">Plugins</a></li>
<li><a href="/maven/struts2-core/apidocs/index.html">Struts Core API</a></li>
<li><a href="/tag-developers/tag-reference.html">Tag reference</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/FAQs">FAQs</a></li>
<li><a href="http://cwiki.apache.org/S2PLUGINS/home.html">Plugin registry</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Contributing<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/youatstruts.html">You at Struts</a></li>
<li><a href="/helping.html">How to Help FAQ</a></li>
<li><a href="/dev-mail.html">Development Lists</a></li>
<li><a href="/contributors/">Contributors Guide</a></li>
<li class="divider"></li>
<li><a href="/submitting-patches.html">Submitting patches</a></li>
<li><a href="/builds.html">Source Code and Builds</a></li>
<li><a href="/coding-standards.html">Coding standards</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Contributors+Guide">Contributors Guide</a></li>
<li class="divider"></li>
<li><a href="/release-guidelines.html">Release Guidelines</a></li>
<li><a href="/bylaws.html">PMC Charter</a></li>
<li><a href="/volunteers.html">Volunteers</a></li>
<li><a href="https://gitbox.apache.org/repos/asf?p=struts.git">Source Repository</a></li>
<li><a href="/updating-website.html">Updating the website</a></li>
</ul>
</li>
<li class="apache"><a href="http://www.apache.org/"><img src="/img/apache.png"></a></li>
</ul>
</div>
</div>
</div>
</nav>
</header>
<article class="container">
<section class="col-md-12">
<a class="edit-on-gh" href="https://github.com/apache/struts-site/edit/master/source/plugins/json/index.md" title="Edit this page on GitHub">Edit on GitHub</a>
<a href="../" title="back to Plugins"><< back to Plugins</a>
<h1 class="no_toc" id="json-plugin">JSON Plugin</h1>
<ul id="markdown-toc">
<li><a href="#description" id="markdown-toc-description">Description</a></li>
<li><a href="#installation" id="markdown-toc-installation">Installation</a></li>
<li><a href="#customizing-serialization-and-deserialization" id="markdown-toc-customizing-serialization-and-deserialization">Customizing Serialization and Deserialization</a> <ul>
<li><a href="#excluding-properties" id="markdown-toc-excluding-properties">Excluding properties</a></li>
<li><a href="#including-properties" id="markdown-toc-including-properties">Including properties</a></li>
<li><a href="#root-object" id="markdown-toc-root-object">Root Object</a></li>
<li><a href="#wrapping" id="markdown-toc-wrapping">Wrapping</a></li>
<li><a href="#wrap-with-comments" id="markdown-toc-wrap-with-comments">Wrap with Comments</a></li>
<li><a href="#prefix" id="markdown-toc-prefix">Prefix</a></li>
<li><a href="#base-classes" id="markdown-toc-base-classes">Base Classes</a></li>
<li><a href="#enumerations" id="markdown-toc-enumerations">Enumerations</a></li>
<li><a href="#compressing-the-output" id="markdown-toc-compressing-the-output">Compressing the output</a></li>
<li><a href="#preventing-the-browser-from-caching-the-response" id="markdown-toc-preventing-the-browser-from-caching-the-response">Preventing the browser from caching the response</a></li>
<li><a href="#excluding-properties-with-null-values" id="markdown-toc-excluding-properties-with-null-values">Excluding properties with null values</a></li>
<li><a href="#status-and-error-code" id="markdown-toc-status-and-error-code">Status and Error code</a></li>
<li><a href="#jsonp" id="markdown-toc-jsonp">JSONP</a></li>
<li><a href="#content-type" id="markdown-toc-content-type">Content Type</a></li>
<li><a href="#encoding" id="markdown-toc-encoding">Encoding</a></li>
<li><a href="#customizing-the-output" id="markdown-toc-customizing-the-output">Customizing the output</a></li>
</ul>
</li>
<li><a href="#example" id="markdown-toc-example">Example</a> <ul>
<li><a href="#setup-action" id="markdown-toc-setup-action">Setup Action</a></li>
<li><a href="#write-the-mapping-for-the-action" id="markdown-toc-write-the-mapping-for-the-action">Write the mapping for the action</a></li>
<li><a href="#json-example-output" id="markdown-toc-json-example-output">JSON example output</a></li>
<li><a href="#accepting-json" id="markdown-toc-accepting-json">Accepting JSON</a></li>
</ul>
</li>
<li><a href="#json-rpc" id="markdown-toc-json-rpc">JSON RPC</a></li>
<li><a href="#proxied-objects" id="markdown-toc-proxied-objects">Proxied objects</a></li>
</ul>
<h2 id="description">Description</h2>
<p>The JSON plugin provides a <code class="highlighter-rouge">json</code> result type that serializes actions into JSON</p>
<ol>
<li>The <code class="highlighter-rouge">content-type</code> must be <code class="highlighter-rouge">application/json</code></li>
<li>The JSON content must be well formed, see <a href="http://www.json.org">json.org</a> for grammar.</li>
<li>Action must have a public “setter” method for fields that must be populated.</li>
<li>Supported types for population are: Primitives (int,long…String), Date, List, Map, Primitive Arrays,
other class (more on this later), and Array of Other class.</li>
<li>Any object in JSON, that is to be populated inside a list, or a map, will be of type Map (mapping from properties
to values), any whole number will be of type Long, any decimal number will be of type Double, and any array of type List.</li>
</ol>
<p>Given this JSON string:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="s2">"doubleValue"</span><span class="p">:</span><span class="w"> </span><span class="mf">10.10</span><span class="p">,</span><span class="w">
</span><span class="s2">"nestedBean"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Mr Bean"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="s2">"list"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"A"</span><span class="p">,</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="mf">20.20</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"firstName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"El Zorro"</span><span class="w">
</span><span class="p">}],</span><span class="w">
</span><span class="s2">"array"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="mi">20</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>The action must have a <code class="highlighter-rouge">setDoubleValue</code> method, taking either a <code class="highlighter-rouge">float</code> or a <code class="highlighter-rouge">double</code> argument (the interceptor will
convert the value to the right one). There must be a <code class="highlighter-rouge">setNestedBean</code> whose argument type can be any class, that has
a <code class="highlighter-rouge">setName</code> method taking as argument an <code class="highlighter-rouge">String</code>. There must be a <code class="highlighter-rouge">setList</code> method that takes a <code class="highlighter-rouge">List</code> as argument,
that list will contain: “A” (<code class="highlighter-rouge">String</code>), 10 (<code class="highlighter-rouge">Long</code>), 20.20 (<code class="highlighter-rouge">Double</code>), Map (<code class="highlighter-rouge">firstName</code> -&gt; <code class="highlighter-rouge">El Zorro</code>).
The <code class="highlighter-rouge">setArray</code> method can take as parameter either a <code class="highlighter-rouge">List</code>, or any numeric array.</p>
<blockquote>
<p>So serialize your objects to JSON in javascript see <a href="http://json.org/json2.js">json2</a>.</p>
</blockquote>
<p><code class="highlighter-rouge">root</code> attribute must be set on the <code class="highlighter-rouge">JSONInterceptor</code> when dealing with JSON array.</p>
<p>This plugin also provides <a href="json-ajax-validation">JSON Ajax Validation</a>.</p>
<h2 id="installation">Installation</h2>
<p>This plugin can be installed by copying the plugin jar into your application’s <code class="highlighter-rouge">/WEB-INF/lib</code> directory. No other
files need to be copied or created.</p>
<p>To use maven, add this to your pom:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;dependencies&gt;</span>
...
<span class="nt">&lt;dependency&gt;</span>
<span class="nt">&lt;groupId&gt;</span>org.apache.struts<span class="nt">&lt;/groupId&gt;</span>
<span class="nt">&lt;artifactId&gt;</span>struts2-json-plugin<span class="nt">&lt;/artifactId&gt;</span>
<span class="nt">&lt;version&gt;</span>STRUTS_VERSION<span class="nt">&lt;/version&gt;</span>
<span class="nt">&lt;/dependency&gt;</span>
...
<span class="nt">&lt;/dependencies&gt;</span>
</code></pre></div></div>
<h2 id="customizing-serialization-and-deserialization">Customizing Serialization and Deserialization</h2>
<p>Use the JSON annotation to customize the serialization/deserialization process. Available JSON annotation fields:</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Default Value</th>
<th>Serialization</th>
<th>Deserialization</th>
</tr>
</thead>
<tbody>
<tr>
<td>name</td>
<td>Customize field name</td>
<td>empty</td>
<td>yes</td>
<td>no</td>
</tr>
<tr>
<td>serialize</td>
<td>Include in serialization</td>
<td>true</td>
<td>yes</td>
<td>no</td>
</tr>
<tr>
<td>deserialize</td>
<td>Include in deserialization</td>
<td>true</td>
<td>no</td>
<td>yes</td>
</tr>
<tr>
<td>format</td>
<td>Format used to format/parse a Date field</td>
<td>“yyyy-MM-dd’T’HH:mm:ss”</td>
<td>yes</td>
<td>yes</td>
</tr>
</tbody>
</table>
<h3 id="excluding-properties">Excluding properties</h3>
<p>A comma-delimited list of regular expressions can be passed to the JSON Result and Interceptor, properties matching
any of these regular expressions will be ignored on the serialization process:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- Result fragment --&gt;</span>
<span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"excludeProperties"</span><span class="nt">&gt;</span>
login.password,
studentList.*.sin
<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
<span class="c">&lt;!-- Interceptor fragment --&gt;</span>
<span class="nt">&lt;interceptor-ref</span> <span class="na">name=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"enableSMD"</span><span class="nt">&gt;</span>true<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"excludeProperties"</span><span class="nt">&gt;</span>
login.password,
studentList.*.sin
<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/interceptor-ref&gt;</span>
</code></pre></div></div>
<h3 id="including-properties">Including properties</h3>
<p>A comma-delimited list of regular expressions can be passed to the JSON Result to restrict which properties will
be serialized. ONLY properties matching any of these regular expressions will be included in the serialized output.</p>
<blockquote>
<p>Exclude property expressions take precedence over include property expressions. That is, if you use include
and exclude property expressions on the same result, include property expressions will not be applied if an
exclude property expression matches a property first.</p>
</blockquote>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- Result fragment --&gt;</span>
<span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"includeProperties"</span><span class="nt">&gt;</span>
^entries\[\d+\].clientNumber,
^entries\[\d+\].scheduleNumber,
^entries\[\d+\].createUserId
<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<h3 id="root-object">Root Object</h3>
<p>Use the <code class="highlighter-rouge">root</code> attribute (OGNL expression) to specify the root object to be serialized.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"root"</span><span class="nt">&gt;</span>
person.job
<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<p>The <code class="highlighter-rouge">root</code> attribute (OGNL expression) can also be used on the interceptor to specify the object that must be
populated, <strong>make sure this object is not null</strong>.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;interceptor-ref</span> <span class="na">name=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"root"</span><span class="nt">&gt;</span>bean1.bean2<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/interceptor-ref&gt;</span>
</code></pre></div></div>
<h3 id="wrapping">Wrapping</h3>
<p>For several reasons you might want to wrap the JSON output with some text, like wrapping with comments, adding a prefix,
or to use file uploads which require the result to be wrapped in a textarea. Use <code class="highlighter-rouge">wrapPrefix</code> to add content in
the beginning and <code class="highlighter-rouge">wrapPostfix</code> to add content at the end. This settings take precedence over <code class="highlighter-rouge">wrapWithComments</code>
and <code class="highlighter-rouge">prefix</code> which are deprecated from 0.34 on. Examples:</p>
<ul>
<li>Wrap with comments:</li>
</ul>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"wrapPrefix"</span><span class="nt">&gt;</span>/*<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"wrapSuffix"</span><span class="nt">&gt;</span>*/<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<ul>
<li>Add a prefix:</li>
</ul>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"wrapPrefix"</span><span class="nt">&gt;</span>{}<span class="err">&amp;&amp;</span><span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<ul>
<li>Wrap for file upload:</li>
</ul>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"wrapPrefix"</span><span class="nt">&gt;</span><span class="cp">&lt;![CDATA[&lt;html&gt;&lt;body&gt;&lt;textarea&gt;]]&gt;</span><span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"wrapSuffix"</span><span class="nt">&gt;</span><span class="cp">&lt;![CDATA[&lt;/textarea&gt;&lt;/body&gt;&lt;/html&gt;]]&gt;</span><span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<h3 id="wrap-with-comments">Wrap with Comments</h3>
<p><code class="highlighter-rouge">wrapWithComments</code> is deprecated from 0.34, use <code class="highlighter-rouge">wrapPrefix</code> and <code class="highlighter-rouge">wrapSuffix</code> instead.</p>
<blockquote>
<p><code class="highlighter-rouge">wrapWithComments</code> can turn safe JSON text into dangerous text. For example,
<code class="highlighter-rouge">"\*/ alert('XSS'); /\*"</code>
Thanks to Douglas Crockford for the tip! Consider using <strong>prefix</strong> instead.</p>
</blockquote>
<p>If the serialized JSON is <code class="highlighter-rouge">{name: 'El Zorro'}</code>. Then the output will be: <code class="highlighter-rouge">{}&amp;&amp; ({name: 'El Zorro'})</code>.</p>
<p>If the <code class="highlighter-rouge">wrapWithComments</code> (false by default) attribute is set to true, the generated JSON is wrapped with comments like:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">/*</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"doubleVal"</span><span class="p">:</span><span class="w"> </span><span class="mf">10.10</span><span class="p">,</span><span class="w">
</span><span class="s2">"nestedBean"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Mr Bean"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="s2">"list"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"A"</span><span class="p">,</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="mf">20.20</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"firstName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"El Zorro"</span><span class="w">
</span><span class="p">}],</span><span class="w">
</span><span class="s2">"array"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="mi">20</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w"> </span><span class="err">*/</span><span class="w">
</span></code></pre></div></div>
<p>To strip those comments use:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">responseObject</span> <span class="o">=</span> <span class="kr">eval</span><span class="p">(</span><span class="s2">"("</span><span class="o">+</span><span class="nx">data</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s2">"</span><span class="err">\</span><span class="s2">/</span><span class="err">\</span><span class="s2">*"</span><span class="p">)</span><span class="o">+</span><span class="mi">2</span><span class="p">,</span> <span class="nx">data</span><span class="p">.</span><span class="nx">lastIndexOf</span><span class="p">(</span><span class="s2">"</span><span class="err">\</span><span class="s2">*</span><span class="err">\</span><span class="s2">/"</span><span class="p">))</span><span class="o">+</span><span class="s2">")"</span><span class="p">);</span>
</code></pre></div></div>
<h3 id="prefix">Prefix</h3>
<p><code class="highlighter-rouge">prefix</code> is deprecated from 0.34, use <code class="highlighter-rouge">wrapPrefix</code> and <code class="highlighter-rouge">wrapSuffix</code> instead.</p>
<p>If the parameter <code class="highlighter-rouge">prefix</code> is set to true, the generated JSON will be prefixed with <code class="highlighter-rouge">{}&amp;&amp; </code>. This will help prevent
hijacking. See <a href="http://trac.dojotoolkit.org/ticket/6380">this Dojo Ticket</a> for details:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"prefix"</span><span class="nt">&gt;</span>true<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<h3 id="base-classes">Base Classes</h3>
<p>By default properties defined on base classes of the <code class="highlighter-rouge">root</code> object won’t be serialized, to serialize properties
in all base classes (up to Object) set <code class="highlighter-rouge">ignoreHierarchy</code> to false in the JSON result:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"ignoreHierarchy"</span><span class="nt">&gt;</span>false<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<h3 id="enumerations">Enumerations</h3>
<p>By default, an Enum is serialized as a <code class="highlighter-rouge">name=value</code> pair where <code class="highlighter-rouge">value = name()</code>.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">public</span> <span class="kd">enum</span> <span class="n">AnEnum</span> <span class="o">{</span>
<span class="n">ValueA</span><span class="o">,</span>
<span class="n">ValueB</span>
<span class="o">}</span>
</code></pre></div></div>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="s2">"myEnum"</span><span class="p">:</span><span class="s2">"ValueA"</span><span class="w">
</span></code></pre></div></div>
<p>Use the <code class="highlighter-rouge">enumAsBean</code> result parameter to serialize Enum’s as a bean with a special property <code class="highlighter-rouge">_name</code> with value <code class="highlighter-rouge">name()</code>.
All properties of the enum are also serialized.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">public</span> <span class="kd">enum</span> <span class="n">AnEnum</span> <span class="o">{</span>
<span class="n">ValueA</span><span class="o">(</span><span class="s">"A"</span><span class="o">),</span>
<span class="n">ValueB</span><span class="o">(</span><span class="s">"B"</span><span class="o">);</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">val</span><span class="o">;</span>
<span class="kd">public</span> <span class="nf">AnEnum</span><span class="o">(</span><span class="n">val</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">val</span> <span class="o">=</span> <span class="n">val</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="nf">getVal</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">val</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="err">myEnum</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ValueA"</span><span class="p">,</span><span class="w"> </span><span class="s2">"val"</span><span class="p">:</span><span class="w"> </span><span class="s2">"A"</span><span class="w"> </span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Enable this parameter through <code class="highlighter-rouge">struts.xml</code>:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"enumAsBean"</span><span class="nt">&gt;</span>true<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<h3 id="compressing-the-output">Compressing the output</h3>
<p>Set the <code class="highlighter-rouge">enableGZIP</code> attribute to true to gzip the generated json response. The request <strong>must</strong> include <code class="highlighter-rouge">gzip</code>
in the <code class="highlighter-rouge">Accept-Encoding</code> header for this to work.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"enableGZIP"</span><span class="nt">&gt;</span>true<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<h3 id="preventing-the-browser-from-caching-the-response">Preventing the browser from caching the response</h3>
<p>Set <code class="highlighter-rouge">noCache</code> to true (false by default) to set the following headers in the response:</p>
<ul>
<li><code class="highlighter-rouge">Cache-Control: no-cache</code></li>
<li><code class="highlighter-rouge">Expires: 0</code></li>
<li><code class="highlighter-rouge">Pragma: No-cache</code></li>
</ul>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"noCache"</span><span class="nt">&gt;</span>true<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<h3 id="excluding-properties-with-null-values">Excluding properties with null values</h3>
<p>By default fields with null values are serialized like <code class="highlighter-rouge">{property_name: null}</code>. This can be prevented
by setting <code class="highlighter-rouge">excludeNullProperties</code> to true.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"excludeNullProperties"</span><span class="nt">&gt;</span>true<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<h3 id="status-and-error-code">Status and Error code</h3>
<p>Use <code class="highlighter-rouge">statusCode</code> to set the status of the response:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"statusCode"</span><span class="nt">&gt;</span>304<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<p>And <code class="highlighter-rouge">errorCode</code> to send an error (the server might end up sending something to the client which is not the serialized JSON):</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">&lt;result</span><span class="w"> </span><span class="err">type=</span><span class="s2">"json"</span><span class="err">&gt;</span><span class="w">
</span><span class="err">&lt;param</span><span class="w"> </span><span class="err">name=</span><span class="s2">"errorCode"</span><span class="err">&gt;</span><span class="mi">404</span><span class="err">&lt;/param&gt;</span><span class="w">
</span><span class="err">&lt;/result&gt;</span><span class="w">
</span></code></pre></div></div>
<h3 id="jsonp">JSONP</h3>
<p>To enable JSONP, set the parameter <code class="highlighter-rouge">callbackParameter</code> in either the JSON Result or the Interceptor. A parameter with
that name will be read from the request, and it value will be used as the JSONP function. Assuming that a request is
made with the parameter “callback”=”exec”:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"callbackParameter"</span><span class="nt">&gt;</span>callback<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<p>And that the serialized JSON is <code class="highlighter-rouge">{name: 'El Zorro'}</code>. Then the output will be: <code class="highlighter-rouge">exec({name: 'El Zorro'})</code>.</p>
<h3 id="content-type">Content Type</h3>
<p>Content type will be set to <code class="highlighter-rouge">application/json-rpc</code> by default if SMD is being used, or <code class="highlighter-rouge">application/json</code> otherwise.
Sometimes it is necessary to set the content type to something else, like when uploading files with Dojo and YUI.
Use the <code class="highlighter-rouge">contentType</code> parameter in those cases.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"contentType"</span><span class="nt">&gt;</span>text/html<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<h3 id="encoding">Encoding</h3>
<p>User can define encoding per result or base on default assigned to <code class="highlighter-rouge">struts.i18n.encoding</code>. To define encoding for
given result add encoding param as below:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"encoding"</span><span class="nt">&gt;</span>UTF-8<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
</code></pre></div></div>
<h3 id="customizing-the-output">Customizing the output</h3>
<p>Since Struts 2.5.14, you can implement the <code class="highlighter-rouge">org.apache.struts2.json.JSONWriter</code> interface to customize the generated json response.
The implementation should then be defined in <code class="highlighter-rouge">struts.xml</code> like:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;struts&gt;</span>
<span class="nt">&lt;bean</span> <span class="na">type=</span><span class="s">"org.apache.struts2.json.JSONWriter"</span> <span class="na">name=</span><span class="s">"myJSONWriter"</span> <span class="na">class=</span><span class="s">"com.mycompany.MyJSONWriter"</span>
<span class="na">scope=</span><span class="s">"prototype"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;constant</span> <span class="na">name=</span><span class="s">"struts.json.writer"</span> <span class="na">value=</span><span class="s">"myJSONWriter"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/struts&gt;</span>
</code></pre></div></div>
<p>There is an example at <a href="https://gitbox.apache.org/repos/asf?p=struts-examples.git;a=blob_plain;f=json-customize/src/main/java/org/demo/FlexJSONWriter.java;hb=HEAD">struts-examples/json-customize/FlexJSONWriter.java</a>.
It replaces Struts default json serializer with <a href="http://flexjson.sourceforge.net/">Flexjson</a> as below:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">flexjson.JSONSerializer</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">flexjson.transformer.DateTransformer</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.apache.struts2.json.JSONException</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.apache.struts2.json.JSONWriter</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">FlexJSONWriter</span> <span class="kd">implements</span> <span class="n">JSONWriter</span> <span class="o">{</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">dateFormatter</span><span class="o">;</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">write</span><span class="o">(</span><span class="n">Object</span> <span class="n">object</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">JSONException</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="n">object</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">write</span><span class="o">(</span><span class="n">Object</span> <span class="n">object</span><span class="o">,</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">Pattern</span><span class="o">&gt;</span> <span class="n">excludeProperties</span><span class="o">,</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">Pattern</span><span class="o">&gt;</span> <span class="n">includeProperties</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">excludeNullProperties</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">JSONException</span> <span class="o">{</span>
<span class="n">JSONSerializer</span> <span class="n">serializer</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JSONSerializer</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">excludeProperties</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">for</span> <span class="o">(</span><span class="n">Pattern</span> <span class="n">p</span> <span class="o">:</span> <span class="n">excludeProperties</span><span class="o">)</span> <span class="o">{</span>
<span class="n">serializer</span> <span class="o">=</span> <span class="n">serializer</span><span class="o">.</span><span class="na">exclude</span><span class="o">(</span><span class="n">p</span><span class="o">.</span><span class="na">pattern</span><span class="o">());</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">includeProperties</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">for</span> <span class="o">(</span><span class="n">Pattern</span> <span class="n">p</span> <span class="o">:</span> <span class="n">includeProperties</span><span class="o">)</span> <span class="o">{</span>
<span class="n">serializer</span> <span class="o">=</span> <span class="n">serializer</span><span class="o">.</span><span class="na">include</span><span class="o">(</span><span class="n">p</span><span class="o">.</span><span class="na">pattern</span><span class="o">());</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">excludeNullProperties</span><span class="o">)</span> <span class="o">{</span>
<span class="n">serializer</span> <span class="o">=</span> <span class="n">serializer</span><span class="o">.</span><span class="na">transform</span><span class="o">(</span><span class="k">new</span> <span class="n">ExcludeTransformer</span><span class="o">(),</span> <span class="kt">void</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">dateFormatter</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">serializer</span> <span class="o">=</span> <span class="n">serializer</span><span class="o">.</span><span class="na">transform</span><span class="o">(</span><span class="k">new</span> <span class="n">DateTransformer</span><span class="o">(</span><span class="n">dateFormatter</span><span class="o">),</span> <span class="n">Date</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">serializer</span><span class="o">.</span><span class="na">serialize</span><span class="o">(</span><span class="n">object</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">//...</span>
</code></pre></div></div>
<blockquote>
<p>Flexjson is a lightweight library for serializing and deserializing Java objects into and from JSON.</p>
</blockquote>
<h2 id="example">Example</h2>
<h3 id="setup-action">Setup Action</h3>
<p>This simple action has some fields:</p>
<p>Example:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">java.util.HashMap</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.Map</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.Action</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">JSONExample</span> <span class="o">{</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">field1</span> <span class="o">=</span> <span class="s">"str"</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">int</span><span class="o">[]</span> <span class="n">ints</span> <span class="o">=</span> <span class="o">{</span><span class="mi">10</span><span class="o">,</span> <span class="mi">20</span><span class="o">};</span>
<span class="kd">private</span> <span class="n">Map</span> <span class="n">map</span> <span class="o">=</span> <span class="k">new</span> <span class="n">HashMap</span><span class="o">();</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">customName</span> <span class="o">=</span> <span class="s">"custom"</span><span class="o">;</span>
<span class="c1">//'transient' fields are not serialized</span>
<span class="kd">private</span> <span class="kd">transient</span> <span class="n">String</span> <span class="n">field2</span><span class="o">;</span>
<span class="c1">//fields without getter method are not serialized</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">field3</span><span class="o">;</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">execute</span><span class="o">()</span> <span class="o">{</span>
<span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"John"</span><span class="o">,</span> <span class="s">"Galt"</span><span class="o">);</span>
<span class="k">return</span> <span class="n">Action</span><span class="o">.</span><span class="na">SUCCESS</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getField1</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">field1</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setField1</span><span class="o">(</span><span class="n">String</span> <span class="n">field1</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">field1</span> <span class="o">=</span> <span class="n">field1</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">int</span><span class="o">[]</span> <span class="nf">getInts</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">ints</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setInts</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">ints</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">ints</span> <span class="o">=</span> <span class="n">ints</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="n">Map</span> <span class="nf">getMap</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">map</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setMap</span><span class="o">(</span><span class="n">Map</span> <span class="n">map</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">map</span> <span class="o">=</span> <span class="n">map</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@JSON</span><span class="o">(</span><span class="n">name</span><span class="o">=</span><span class="s">"newName"</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getCustomName</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">customName</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h3 id="write-the-mapping-for-the-action">Write the mapping for the action</h3>
<ol>
<li>Add the map inside a package that extends <code class="highlighter-rouge">json-default</code></li>
<li>Add a result of type <code class="highlighter-rouge">json</code></li>
</ol>
<p>Example with Convention Plugin Configuration:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">java.util.HashMap</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.Map</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Result</span><span class="o">;</span>
<span class="nd">@Result</span><span class="o">(</span><span class="n">type</span> <span class="o">=</span> <span class="s">"json"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">JSONExample</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span>
<span class="c1">// action code</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Example with XML Configuration:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;</span>
<span class="cp">&lt;!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd"&gt;</span>
<span class="nt">&lt;struts&gt;</span>
<span class="nt">&lt;package</span> <span class="na">name=</span><span class="s">"example"</span> <span class="na">extends=</span><span class="s">"json-default"</span><span class="nt">&gt;</span>
<span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"JSONExample"</span> <span class="na">class=</span><span class="s">"example.JSONExample"</span><span class="nt">&gt;</span>
<span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/action&gt;</span>
<span class="nt">&lt;/package&gt;</span>
<span class="nt">&lt;/struts&gt;</span>
</code></pre></div></div>
<h3 id="json-example-output">JSON example output</h3>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="s2">"field1"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"str"</span><span class="p">,</span><span class="w">
</span><span class="s2">"ints"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="mi">20</span><span class="p">],</span><span class="w">
</span><span class="s2">"map"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"John"</span><span class="p">:</span><span class="s2">"Galt"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="s2">"newName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"custom"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<h3 id="accepting-json">Accepting JSON</h3>
<p>Your actions can accept incoming JSON if they are in package which uses <code class="highlighter-rouge">json</code> interceptor or by adding reference
to it as follow:</p>
<pre><code class="language-jaba">@InterceptorRef(value="json")
</code></pre>
<p>By default <code class="highlighter-rouge">Content-Type</code> of value <code class="highlighter-rouge">application/json</code> is recognised to be used for de-serialisation
and <code class="highlighter-rouge">application/json-rpc</code> to execute SMD processing. You can override those settings be defining <code class="highlighter-rouge">jsonContentType</code>
and <code class="highlighter-rouge">jsonRpcContentType</code> params, see example:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;interceptor-ref</span> <span class="na">name=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"jsonContentType"</span><span class="nt">&gt;</span>text/json<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"jsonRpcContentType"</span><span class="nt">&gt;</span>text/json-rpc<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/interceptor-ref&gt;</span>
</code></pre></div></div>
<p>Please be aware that those are scoped params per stack, which means, once set it will be used by actions in scope of this stack.</p>
<h2 id="json-rpc">JSON RPC</h2>
<p>The json plugin can be used to execute action methods from javascript and return the output. This feature was developed
with Dojo in mind, so it uses <a href="http://manual.dojotoolkit.org/WikiHome/DojoDotBook/Book9">Simple Method Definition</a>
to advertise the remote service. Let’s work it out with an example(useless as most examples).</p>
<p>First write the action:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="n">smd</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.googlecode.jsonplugin.annotations.SMDMethod</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.Action</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">SMDAction</span> <span class="o">{</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">smd</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">Action</span><span class="o">.</span><span class="na">SUCCESS</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@SMDMethod</span>
<span class="kd">public</span> <span class="n">Bean</span> <span class="nf">doSomething</span><span class="o">(</span><span class="n">Bean</span> <span class="n">bean</span><span class="o">,</span> <span class="kt">int</span> <span class="n">quantity</span><span class="o">)</span> <span class="o">{</span>
<span class="n">bean</span><span class="o">.</span><span class="na">setPrice</span><span class="o">(</span><span class="n">quantity</span> <span class="o">*</span> <span class="mi">10</span><span class="o">);</span>
<span class="k">return</span> <span class="n">bean</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Methods that will be called remotely <strong>must</strong> be annotated with the <code class="highlighter-rouge">SMDMethod</code> annotation, for security reasons.
The method will take a bean object, modify its price and return it. The action can be annotated with the <code class="highlighter-rouge">SMD</code> annotation
to customize the generated SMD (more on that soon), and parameters can be annotated with <code class="highlighter-rouge">SMDMethodParameter</code>. As you
can see, we have a “dummy”, <code class="highlighter-rouge">smd</code> method. This method will be used to generate the Simple Method Definition
(a definition of all the services provided by this class), using the <code class="highlighter-rouge">json</code> result.</p>
<p>The bean class:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="n">smd</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Bean</span> <span class="o">{</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">type</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">price</span><span class="o">;</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getType</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setType</span><span class="o">(</span><span class="n">String</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">type</span> <span class="o">=</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getPrice</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">price</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setPrice</span><span class="o">(</span><span class="kt">int</span> <span class="n">price</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">price</span> <span class="o">=</span> <span class="n">price</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The mapping:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;package</span> <span class="na">name=</span><span class="s">"RPC"</span> <span class="na">namespace=</span><span class="s">"/nodecorate"</span> <span class="na">extends=</span><span class="s">"json-default"</span><span class="nt">&gt;</span>
<span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"SMDAction"</span> <span class="na">class=</span><span class="s">"smd.SMDAction"</span> <span class="na">method=</span><span class="s">"smd"</span><span class="nt">&gt;</span>
<span class="nt">&lt;interceptor-ref</span> <span class="na">name=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"enableSMD"</span><span class="nt">&gt;</span>true<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/interceptor-ref&gt;</span>
<span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"enableSMD"</span><span class="nt">&gt;</span>true<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;/action&gt;</span>
<span class="nt">&lt;/package&gt;</span>
</code></pre></div></div>
<p>Nothing special here, except that <strong>both</strong> the interceptor and the result must be applied to the action, and <code class="highlighter-rouge">enableSMD</code>
must be enabled for both.</p>
<p>Now the javascript code:</p>
<pre><code class="language-jsp">&lt;s:url id="smdUrl" namespace="/nodecorate" action="SMDAction" /&gt;
&lt;script type="text/javascript"&gt;
//load dojo RPC
dojo.require("dojo.rpc.*");
//create service object(proxy) using SMD (generated by the json result)
var service = new dojo.rpc.JsonService("${smdUrl}");
//function called when remote method returns
var callback = function(bean) {
alert("Price for " + bean.type + " is " + bean.price);
};
//parameter
var bean = {type: "Mocca"};
//execute remote method
var defered = service.doSomething(bean, 5);
//attach callback to defered object
defered.addCallback(callback);
&lt;/script&gt;
</code></pre>
<p>Dojo’s JsonService will make a request to the action to load the SMD, which will return a JSON object with the definition
of the available remote methods, using that information Dojo creates a “proxy” for those methods. Because of the asynchronous
nature of the request, when the method is executed, a deferred object is returned, to which a callback function can be attached.
The callback function will receive as a parameter the object returned from your action. That’s it.</p>
<h2 id="proxied-objects">Proxied objects</h2>
<p>As annotations are not inherited in Java, some user might experience problems while trying to serialize objects that
are proxied. eg. when you have attached AOP interceptors to your action.</p>
<p>In this situation, the plugin will not detect the annotations on methods in your action.</p>
<p>To overcome this, set the <code class="highlighter-rouge">ignoreInterfaces</code> result parameter to false (true by default) to request that the plugin
inspects all interfaces and superclasses of the action for annotations on the action’s methods.</p>
<blockquote>
<p>This parameter should only be set to false if your action could be a proxy as there is a performance cost caused
by recursion through the interfaces.</p>
</blockquote>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"contact"</span> <span class="na">class=</span><span class="s">"package.ContactAction"</span> <span class="na">method=</span><span class="s">"smd"</span><span class="nt">&gt;</span>
<span class="nt">&lt;interceptor-ref</span> <span class="na">name=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"enableSMD"</span><span class="nt">&gt;</span>true<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"ignoreSMDMethodInterfaces"</span><span class="nt">&gt;</span>false<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/interceptor-ref&gt;</span>
<span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"enableSMD"</span><span class="nt">&gt;</span>true<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"ignoreInterfaces"</span><span class="nt">&gt;</span>false<span class="nt">&lt;/param&gt;</span>
<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;interceptor-ref</span> <span class="na">name=</span><span class="s">"default"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/action&gt;</span>
</code></pre></div></div>
</section>
</article>
<footer class="container">
<div class="col-md-12">
Copyright &copy; 2000-2018 <a href="http://www.apache.org/">The Apache Software Foundation </a>.
All Rights Reserved.
</div>
<div class="col-md-12">
Apache Struts, Struts, Apache, the Apache feather logo, and the Apache Struts project logos are
trademarks of The Apache Software Foundation.
</div>
<div class="col-md-12">Logo and website design donated by <a href="https://softwaremill.com/">SoftwareMill</a>.</div>
</footer>
<script>!function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (!d.getElementById(id)) {
js = d.createElement(s);
js.id = id;
js.src = "//platform.twitter.com/widgets.js";
fjs.parentNode.insertBefore(js, fjs);
}
}(document, "script", "twitter-wjs");</script>
<script src="https://apis.google.com/js/platform.js" async="async" defer="defer"></script>
<div id="fb-root"></div>
<script>(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s);
js.id = id;
js.src = "//connect.facebook.net/en_GB/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
</body>
</html>