| <!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> -> <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"><dependencies></span> |
| ... |
| <span class="nt"><dependency></span> |
| <span class="nt"><groupId></span>org.apache.struts<span class="nt"></groupId></span> |
| <span class="nt"><artifactId></span>struts2-json-plugin<span class="nt"></artifactId></span> |
| <span class="nt"><version></span>STRUTS_VERSION<span class="nt"></version></span> |
| <span class="nt"></dependency></span> |
| ... |
| <span class="nt"></dependencies></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"><!-- Result fragment --></span> |
| <span class="nt"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"excludeProperties"</span><span class="nt">></span> |
| login.password, |
| studentList.*.sin |
| <span class="nt"></param></span> |
| <span class="nt"></result></span> |
| |
| <span class="c"><!-- Interceptor fragment --></span> |
| <span class="nt"><interceptor-ref</span> <span class="na">name=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"enableSMD"</span><span class="nt">></span>true<span class="nt"></param></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"excludeProperties"</span><span class="nt">></span> |
| login.password, |
| studentList.*.sin |
| <span class="nt"></param></span> |
| <span class="nt"></interceptor-ref></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"><!-- Result fragment --></span> |
| <span class="nt"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"includeProperties"</span><span class="nt">></span> |
| ^entries\[\d+\].clientNumber, |
| ^entries\[\d+\].scheduleNumber, |
| ^entries\[\d+\].createUserId |
| <span class="nt"></param></span> |
| <span class="nt"></result></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"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"root"</span><span class="nt">></span> |
| person.job |
| <span class="nt"></param></span> |
| <span class="nt"></result></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"><interceptor-ref</span> <span class="na">name=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"root"</span><span class="nt">></span>bean1.bean2<span class="nt"></param></span> |
| <span class="nt"></interceptor-ref></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"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"wrapPrefix"</span><span class="nt">></span>/*<span class="nt"></param></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"wrapSuffix"</span><span class="nt">></span>*/<span class="nt"></param></span> |
| <span class="nt"></result></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"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"wrapPrefix"</span><span class="nt">></span>{}<span class="err">&&</span><span class="nt"></param></span> |
| <span class="nt"></result></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"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"wrapPrefix"</span><span class="nt">></span><span class="cp"><![CDATA[<html><body><textarea>]]></span><span class="nt"></param></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"wrapSuffix"</span><span class="nt">></span><span class="cp"><![CDATA[</textarea></body></html>]]></span><span class="nt"></param></span> |
| <span class="nt"></result></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">{}&& ({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">{}&& </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"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"prefix"</span><span class="nt">></span>true<span class="nt"></param></span> |
| <span class="nt"></result></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"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"ignoreHierarchy"</span><span class="nt">></span>false<span class="nt"></param></span> |
| <span class="nt"></result></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"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"enumAsBean"</span><span class="nt">></span>true<span class="nt"></param></span> |
| <span class="nt"></result></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"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"enableGZIP"</span><span class="nt">></span>true<span class="nt"></param></span> |
| <span class="nt"></result></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"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"noCache"</span><span class="nt">></span>true<span class="nt"></param></span> |
| <span class="nt"></result></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"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"excludeNullProperties"</span><span class="nt">></span>true<span class="nt"></param></span> |
| <span class="nt"></result></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"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"statusCode"</span><span class="nt">></span>304<span class="nt"></param></span> |
| <span class="nt"></result></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"><result</span><span class="w"> </span><span class="err">type=</span><span class="s2">"json"</span><span class="err">></span><span class="w"> |
| </span><span class="err"><param</span><span class="w"> </span><span class="err">name=</span><span class="s2">"errorCode"</span><span class="err">></span><span class="mi">404</span><span class="err"></param></span><span class="w"> |
| </span><span class="err"></result></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"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"callbackParameter"</span><span class="nt">></span>callback<span class="nt"></param></span> |
| <span class="nt"></result></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"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"contentType"</span><span class="nt">></span>text/html<span class="nt"></param></span> |
| <span class="nt"></result></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"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"encoding"</span><span class="nt">></span>UTF-8<span class="nt"></param></span> |
| <span class="nt"></result></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"><struts></span> |
| <span class="nt"><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">/></span> |
| <span class="nt"><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">/></span> |
| <span class="nt"></struts></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"><</span><span class="n">Pattern</span><span class="o">></span> <span class="n">excludeProperties</span><span class="o">,</span> <span class="n">Collection</span><span class="o"><</span><span class="n">Pattern</span><span class="o">></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"><?xml version="1.0" encoding="UTF-8" ?></span> |
| <span class="cp"><!DOCTYPE struts PUBLIC |
| "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" |
| "http://struts.apache.org/dtds/struts-2.0.dtd"></span> |
| |
| <span class="nt"><struts></span> |
| |
| <span class="nt"><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">></span> |
| <span class="nt"><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">></span> |
| <span class="nt"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">/></span> |
| <span class="nt"></action></span> |
| <span class="nt"></package></span> |
| |
| <span class="nt"></struts></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"><interceptor-ref</span> <span class="na">name=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"jsonContentType"</span><span class="nt">></span>text/json<span class="nt"></param></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"jsonRpcContentType"</span><span class="nt">></span>text/json-rpc<span class="nt"></param></span> |
| <span class="nt"></interceptor-ref></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"><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">></span> |
| <span class="nt"><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">></span> |
| <span class="nt"><interceptor-ref</span> <span class="na">name=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"enableSMD"</span><span class="nt">></span>true<span class="nt"></param></span> |
| <span class="nt"></interceptor-ref></span> |
| <span class="nt"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"enableSMD"</span><span class="nt">></span>true<span class="nt"></param></span> |
| <span class="nt"></result></span> |
| <span class="nt"></action></span> |
| <span class="nt"></package></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"><s:url id="smdUrl" namespace="/nodecorate" action="SMDAction" /> |
| <script type="text/javascript"> |
| //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); |
| </script> |
| </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"><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">></span> |
| <span class="nt"><interceptor-ref</span> <span class="na">name=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"enableSMD"</span><span class="nt">></span>true<span class="nt"></param></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"ignoreSMDMethodInterfaces"</span><span class="nt">></span>false<span class="nt"></param></span> |
| <span class="nt"></interceptor-ref></span> |
| <span class="nt"><result</span> <span class="na">type=</span><span class="s">"json"</span><span class="nt">></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"enableSMD"</span><span class="nt">></span>true<span class="nt"></param></span> |
| <span class="nt"><param</span> <span class="na">name=</span><span class="s">"ignoreInterfaces"</span><span class="nt">></span>false<span class="nt"></param></span> |
| <span class="nt"></result></span> |
| <span class="nt"><interceptor-ref</span> <span class="na">name=</span><span class="s">"default"</span><span class="nt">/></span> |
| <span class="nt"></action></span> |
| </code></pre></div></div> |
| |
| </section> |
| </article> |
| |
| |
| <footer class="container"> |
| <div class="col-md-12"> |
| Copyright © 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> |