blob: 40aae6b9074494aeb853b553faed7eda7cf90698 [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="/css/syntax.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>
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
/* We explicitly disable cookie tracking to avoid privacy issues */
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//analytics.apache.org/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '41']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<!-- End Matomo Code -->
</head>
<body>
<a href="https://github.com/apache/struts" class="github-ribbon">
<img decoding="async" loading="lazy" style="position: absolute; right: 0; border: 0;" width="149" height="149" src="https://github.blog/wp-content/uploads/2008/12/forkme_right_red_aa0000.png?resize=149%2C149" class="attachment-full size-full" alt="Fork me on GitHub" data-recalc-dims="1">
</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-2024.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>
<li><a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy Policy</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><a href="/commercial-support.html">Commercial Support</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 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="/contributors/">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="language-plaintext highlighter-rouge">json</code> result type that serializes actions into JSON</p>
<ol>
<li>The <code class="language-plaintext highlighter-rouge">content-type</code> must be <code class="language-plaintext 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="nl">"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="nl">"nestedBean"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"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="nl">"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="nl">"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="nl">"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="language-plaintext highlighter-rouge">setDoubleValue</code> method, taking either a <code class="language-plaintext highlighter-rouge">float</code> or a <code class="language-plaintext highlighter-rouge">double</code> argument (the interceptor will
convert the value to the right one). There must be a <code class="language-plaintext highlighter-rouge">setNestedBean</code> whose argument type can be any class, that has
a <code class="language-plaintext highlighter-rouge">setName</code> method taking as argument an <code class="language-plaintext highlighter-rouge">String</code>. There must be a <code class="language-plaintext highlighter-rouge">setList</code> method that takes a <code class="language-plaintext highlighter-rouge">List</code> as argument,
that list will contain: “A” (<code class="language-plaintext highlighter-rouge">String</code>), 10 (<code class="language-plaintext highlighter-rouge">Long</code>), 20.20 (<code class="language-plaintext highlighter-rouge">Double</code>), Map (<code class="language-plaintext highlighter-rouge">firstName</code> -&gt; <code class="language-plaintext highlighter-rouge">El Zorro</code>).
The <code class="language-plaintext highlighter-rouge">setArray</code> method can take as parameter either a <code class="language-plaintext 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="language-plaintext highlighter-rouge">root</code> attribute must be set on the <code class="language-plaintext 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="language-plaintext 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="language-plaintext 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="language-plaintext 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="language-plaintext highlighter-rouge">wrapPrefix</code> to add content in
the beginning and <code class="language-plaintext highlighter-rouge">wrapPostfix</code> to add content at the end. This settings take precedence over <code class="language-plaintext highlighter-rouge">wrapWithComments</code>
and <code class="language-plaintext 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="language-plaintext highlighter-rouge">wrapWithComments</code> is deprecated from 0.34, use <code class="language-plaintext highlighter-rouge">wrapPrefix</code> and <code class="language-plaintext highlighter-rouge">wrapSuffix</code> instead.</p>
<blockquote>
<p><code class="language-plaintext highlighter-rouge">wrapWithComments</code> can turn safe JSON text into dangerous text. For example,
<code class="language-plaintext 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="language-plaintext highlighter-rouge">{name: 'El Zorro'}</code>. Then the output will be: <code class="language-plaintext highlighter-rouge">{}&amp;&amp; ({name: 'El Zorro'})</code>.</p>
<p>If the <code class="language-plaintext 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="nl">"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="nl">"nestedBean"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"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="nl">"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="nl">"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="nl">"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="nb">eval</span><span class="p">(</span><span class="dl">"</span><span class="s2">(</span><span class="dl">"</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="dl">"</span><span class="se">\</span><span class="s2">/</span><span class="se">\</span><span class="s2">*</span><span class="dl">"</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="dl">"</span><span class="se">\</span><span class="s2">*</span><span class="se">\</span><span class="s2">/</span><span class="dl">"</span><span class="p">))</span><span class="o">+</span><span class="dl">"</span><span class="s2">)</span><span class="dl">"</span><span class="p">);</span>
</code></pre></div></div>
<h3 id="prefix">Prefix</h3>
<p><code class="language-plaintext highlighter-rouge">prefix</code> is deprecated from 0.34, use <code class="language-plaintext highlighter-rouge">wrapPrefix</code> and <code class="language-plaintext highlighter-rouge">wrapSuffix</code> instead.</p>
<p>If the parameter <code class="language-plaintext highlighter-rouge">prefix</code> is set to true, the generated JSON will be prefixed with <code class="language-plaintext 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="language-plaintext highlighter-rouge">root</code> object won’t be serialized, to serialize properties
in all base classes (up to Object) set <code class="language-plaintext 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="language-plaintext highlighter-rouge">name=value</code> pair where <code class="language-plaintext 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="nc">AnEnum</span> <span class="o">{</span>
<span class="nc">ValueA</span><span class="o">,</span>
<span class="nc">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="nl">"myEnum"</span><span class="p">:</span><span class="s2">"ValueA"</span><span class="w">
</span></code></pre></div></div>
<p>Use the <code class="language-plaintext highlighter-rouge">enumAsBean</code> result parameter to serialize Enum’s as a bean with a special property <code class="language-plaintext highlighter-rouge">_name</code> with value <code class="language-plaintext 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="nc">AnEnum</span> <span class="o">{</span>
<span class="nc">ValueA</span><span class="o">(</span><span class="s">"A"</span><span class="o">),</span>
<span class="nc">ValueB</span><span class="o">(</span><span class="s">"B"</span><span class="o">);</span>
<span class="kd">private</span> <span class="nc">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="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"_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="nl">"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="language-plaintext 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="language-plaintext highlighter-rouge">enableGZIP</code> attribute to true to gzip the generated json response. The request <strong>must</strong> include <code class="language-plaintext highlighter-rouge">gzip</code>
in the <code class="language-plaintext 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="language-plaintext highlighter-rouge">noCache</code> to true (false by default) to set the following headers in the response:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">Cache-Control: no-cache</code></li>
<li><code class="language-plaintext highlighter-rouge">Expires: 0</code></li>
<li><code class="language-plaintext 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="language-plaintext highlighter-rouge">{property_name: null}</code>. This can be prevented
by setting <code class="language-plaintext 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="language-plaintext 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="language-plaintext 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="language-plaintext 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="language-plaintext highlighter-rouge">{name: 'El Zorro'}</code>. Then the output will be: <code class="language-plaintext highlighter-rouge">exec({name: 'El Zorro'})</code>.</p>
<h3 id="content-type">Content Type</h3>
<p>Content type will be set to <code class="language-plaintext highlighter-rouge">application/json-rpc</code> by default if SMD is being used, or <code class="language-plaintext 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="language-plaintext 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="language-plaintext 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="language-plaintext highlighter-rouge">org.apache.struts2.json.JSONWriter</code> interface to customize the generated json response.
The implementation should then be defined in <code class="language-plaintext 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="nc">JSONWriter</span> <span class="o">{</span>
<span class="kd">private</span> <span class="nc">String</span> <span class="n">dateFormatter</span><span class="o">;</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="nf">write</span><span class="o">(</span><span class="nc">Object</span> <span class="n">object</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">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="nc">String</span> <span class="nf">write</span><span class="o">(</span><span class="nc">Object</span> <span class="n">object</span><span class="o">,</span> <span class="nc">Collection</span><span class="o">&lt;</span><span class="nc">Pattern</span><span class="o">&gt;</span> <span class="n">excludeProperties</span><span class="o">,</span> <span class="nc">Collection</span><span class="o">&lt;</span><span class="nc">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="nc">JSONException</span> <span class="o">{</span>
<span class="nc">JSONSerializer</span> <span class="n">serializer</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">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="nc">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="nc">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="nc">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="nc">DateTransformer</span><span class="o">(</span><span class="n">dateFormatter</span><span class="o">),</span> <span class="nc">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="nc">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="nc">Map</span> <span class="n">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o">();</span>
<span class="kd">private</span> <span class="nc">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="nc">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="nc">String</span> <span class="n">field3</span><span class="o">;</span>
<span class="kd">public</span> <span class="nc">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="nc">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="nc">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="nc">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="nc">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="nc">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="nc">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="language-plaintext highlighter-rouge">json-default</code></li>
<li>Add a result of type <code class="language-plaintext 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="nc">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="nl">"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="nl">"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="nl">"map"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"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="nl">"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="language-plaintext 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="language-plaintext highlighter-rouge">Content-Type</code> of value <code class="language-plaintext highlighter-rouge">application/json</code> is recognised to be used for de-serialisation
and <code class="language-plaintext highlighter-rouge">application/json-rpc</code> to execute SMD processing. You can override those settings be defining <code class="language-plaintext highlighter-rouge">jsonContentType</code>
and <code class="language-plaintext 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="nn">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="nc">String</span> <span class="nf">smd</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="nc">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="nc">Bean</span> <span class="nf">doSomething</span><span class="o">(</span><span class="nc">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="language-plaintext 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="language-plaintext highlighter-rouge">SMD</code> annotation
to customize the generated SMD (more on that soon), and parameters can be annotated with <code class="language-plaintext highlighter-rouge">SMDMethodParameter</code>. As you
can see, we have a “dummy”, <code class="language-plaintext 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="language-plaintext 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="nn">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="nc">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="nc">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="nc">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="language-plaintext highlighter-rouge">enableSMD</code>
must be enabled for both.</p>
<p>Now the javascript code:</p>
<div class="language-jsp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;s:url </span><span class="na">id=</span><span class="s">"smdUrl"</span><span class="na"> namespace=</span><span class="s">"/nodecorate"</span><span class="na"> action=</span><span class="s">"SMDAction"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">&gt;</span>
<span class="c1">//load dojo RPC</span>
<span class="nx">dojo</span><span class="p">.</span><span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">dojo.rpc.*</span><span class="dl">"</span><span class="p">);</span>
<span class="c1">//create service object(proxy) using SMD (generated by the json result)</span>
<span class="kd">var</span> <span class="nx">service</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">dojo</span><span class="p">.</span><span class="nx">rpc</span><span class="p">.</span><span class="nx">JsonService</span><span class="p">(</span><span class="dl">"</span><span class="s2">${smdUrl}</span><span class="dl">"</span><span class="p">);</span>
<span class="c1">//function called when remote method returns</span>
<span class="kd">var</span> <span class="nx">callback</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">bean</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">Price for </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">bean</span><span class="p">.</span><span class="nx">type</span> <span class="o">+</span> <span class="dl">"</span><span class="s2"> is </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">bean</span><span class="p">.</span><span class="nx">price</span><span class="p">);</span>
<span class="p">};</span>
<span class="c1">//parameter</span>
<span class="kd">var</span> <span class="nx">bean</span> <span class="o">=</span> <span class="p">{</span><span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Mocca</span><span class="dl">"</span><span class="p">};</span>
<span class="c1">//execute remote method</span>
<span class="kd">var</span> <span class="nx">defered</span> <span class="o">=</span> <span class="nx">service</span><span class="p">.</span><span class="nx">doSomething</span><span class="p">(</span><span class="nx">bean</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
<span class="c1">//attach callback to defered object</span>
<span class="nx">defered</span><span class="p">.</span><span class="nx">addCallback</span><span class="p">(</span><span class="nx">callback</span><span class="p">);</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>
<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="language-plaintext 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-2022 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
Apache Struts, Struts, Apache, the Apache feather logo, and the Apache Struts project logos are
trademarks of The Apache Software Foundation. All Rights Reserved.
</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>