blob: 51ca904093dc556e5ba7376f441cb699f338390b [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>ContentNegotiationService :: Apache Isis</title>
<link rel="canonical" href="https://isis.apache.org/core/2.0.0-M3/runtime-services/ContentNegotiationService.html">
<meta name="generator" content="Antora 2.2.0">
<link rel="stylesheet" href="../../../_/css/site.css">
<link rel="stylesheet" href="../../../_/css/site-custom.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,700,700i|Raleway:300,400,500,700,800|Montserrat:300,400,700" rel="stylesheet">
<link rel="home" href="https://isis.apache.org" title="Apache Isis">
<link rel="next" href="InteractionDtoServiceInternal.html" title="InteractionDtoServiceInternal">
<link rel="prev" href="CommandDtoServiceInternal.html" title="CommandDtoServiceInternal">
</head>
<body class="article">
<header class="header">
<nav class="navbar">
<div class="navbar-brand">
<a class="navbar-item" href="https://isis.apache.org">
<span class="icon">
<img src="../../../_/img/isis-logo-48x48.png"></img>
</span>
<span>Apache Isis</span>
</a>
<button class="navbar-burger" data-target="topbar-nav">
<span></span>
<span></span>
<span></span>
</button>
</div>
<div id="topbar-nav" class="navbar-menu">
<a class="navbar-end">
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="#">Quick Start</a>
<div class="navbar-dropdown">
<span class="navbar-item navbar-heading">Starter Apps</span>
<a class="navbar-item" href="../../../docs/latest/starters/helloworld.html">Hello World</a>
<a class="navbar-item" href="../../../docs/latest/starters/simpleapp.html">Simple App</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Demos &amp; Tutorials</span>
<a class="navbar-item" href="../../../docs/latest/demo/about.html">Demo App</a>
<a class="navbar-item" href="https://danhaywood.gitlab.io/isis-petclinic-tutorial-docs/petclinic/1.16.2/intro.html">Petclinic (tutorial)</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Resources</span>
<a class="navbar-item" href="../../../docs/latest/resources/cheatsheet.html">Cheatsheet</a>
<a class="navbar-item" href="../../../docs/latest/resources/icons.html">Icons</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="#">Guides</a>
<div class="navbar-dropdown">
<span class="navbar-item navbar-heading">Development</span>
<a class="navbar-item" href="../../../setupguide/latest/about.html">Setup Guide</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Core</span>
<a class="navbar-item" href="../../../userguide/latest/about.html">User Guide</a>
<a class="navbar-item" href="../../../refguide/latest/about.html">Reference Guide</a>
<a class="navbar-item" href="../../../testing/latest/about.html">Testing Guide</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="#">Libraries</a>
<div class="navbar-dropdown">
<span class="navbar-item navbar-heading">For Use in Apps</span>
<a class="navbar-item" href="../../../subdomains/latest/about.html">Subdomain Libraries</a>
<a class="navbar-item" href="../../../valuetypes/latest/about.html">Value Types</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Integrate between Apps</span>
<a class="navbar-item" href="../../../mappings/latest/about.html">Bounded Context Mapping Libraries</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Other</span>
<a class="navbar-item" href="../../../incubator/latest/about.html">Incubator</a>
<a class="navbar-item" href="../../../legacy/latest/about.html">Legacy</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="#">Components</a>
<div class="navbar-dropdown">
<span class="navbar-item navbar-heading">Viewers</span>
<a class="navbar-item" href="../../../vw/latest/about.html">Wicket UI</a>
<a class="navbar-item" href="../../../vro/latest/about.html">Restful Objects (REST)</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Security</span>
<a class="navbar-item" href="../../../security/latest/about.html">Security Guide</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Persistence</span>
<a class="navbar-item" href="../../../pjdo/latest/about.html">DataNucleus (JDO)</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Extensions</span>
<a class="navbar-item" href="../../../extensions/latest/about.html">Extensions Catalog</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="#">Support</a>
<div class="navbar-dropdown">
<span class="navbar-item navbar-heading">Contact</span>
<a class="navbar-item" href="../../../docs/latest/support/slack-channel.html">Slack</a>
<a class="navbar-item" href="../../../docs/latest/support/mailing-list.html">Mailing Lists</a>
<a class="navbar-item" href="https://issues.apache.org/jira/browse/ISIS">JIRA</a>
<a class="navbar-item" href="https://stackoverflow.com/questions/tagged/isis">Stack Overflow</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Releases</span>
<a class="navbar-item" href="../../../docs/latest/downloads/how-to.html">Downloads</a>
<a class="navbar-item" href="../../../relnotes/latest/about.html">Release Notes</a>
<a class="navbar-item" href="../../../docs/latest/archive/1-x.html">Archive (1.x)</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Framework</span>
<a class="navbar-item" href="../../../conguide/latest/about.html">Contributors' Guide</a>
<a class="navbar-item" href="../../../comguide/latest/about.html">Committers' Guide</a>
<a class="navbar-item" href="../../../core/latest/about.html">Core Design</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="#">ASF</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="http://www.apache.org/">Apache Homepage</a>
<a class="navbar-item" href="https://www.apache.org/events/current-event">Events</a>
<a class="navbar-item" href="https://www.apache.org/licenses/">Licenses</a>
<a class="navbar-item" href="https://www.apache.org/security/">Security</a>
<a class="navbar-item" href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
<a class="navbar-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a>
<hr class="navbar-divider"/>
<a class="navbar-item" href="https://whimsy.apache.org/board/minutes/Isis.html">PMC board minutes</a>
</div>
</div>
<a class="navbar-item" href="../../../docs/latest/about.html">
<span class="icon">
<img src="../../../_/img/home.png"></img>
</span>
</a>
</div>
</div>
</nav>
</header>
<div class="body ">
<div class="nav-container" data-component="core" data-version="2.0.0-M3">
<aside class="nav">
<div class="panels">
<div class="nav-panel-pagination">
<a class="page-previous" rel="prev" href="CommandDtoServiceInternal.html" title="CommandDtoServiceInternal"><span></span></a>
<a class="page-next" rel="next"
href="InteractionDtoServiceInternal.html" title="InteractionDtoServiceInternal"><span></span></a>
<!--
page.parent doesn't seem to be set...
<a class="page-parent" rel="prev" href="about.html" title="CommandDtoServiceInternal"><span></span></a>
-->
</div>
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<h3 class="title"><a href="../about.html">Design Docs</a></h3>
<ul class="nav-list">
<li class="nav-item" data-depth="0">
<ul class="nav-list">
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../archdesign/about.html">Architecture &amp; Design</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../commons/about.html">Commons</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../codegen-bytebuddy/about.html">Byte Buddy Proxy Factory</a>
</li>
<li class="nav-item" data-depth="1">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../metamodel/about.html">MetaModel</a>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../metamodel/class-diagram.html">Class Diagram</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../runtime/about.html">Runtime</a>
</li>
<li class="nav-item" data-depth="1">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="about.html">Runtime Services</a>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<a class="nav-link" href="ApplicationFeatureFactory.html">ApplicationFeatureFactory</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="AuditerDispatchService.html">AuditerDispatchService</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="AuthenticationSessionProvider.html">AuthenticationSessionProvider</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="ChangedObjectsService.html">ChangedObjectsService</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="CommandDtoServiceInternal.html">CommandDtoServiceInternal</a>
</li>
<li class="nav-item is-current-page" data-depth="2">
<a class="nav-link" href="ContentNegotiationService.html">ContentNegotiationService</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="InteractionDtoServiceInternal.html">InteractionDtoServiceInternal</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="RepresentationService.html">RepresentationService</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="PersistenceSessionServiceInternal.html">PersistenceSessionServiceInternal</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="PublisherDispatchService.html">PublisherDispatchService</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="1">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../webapp/about.html">Webapp</a>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../webapp/webmodules.html"><code>WebModule</code> interface</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../smoketests/about.html">SmokeTest app</a>
</li>
</ul>
</li>
</ul>
</nav>
</div>
<div class="nav-panel-explore" data-panel="explore">
<div class="context">
<span class="title">Design Docs</span>
<span class="version">2.0.0-M3</span>
</div>
<ul class="components">
<li class="component">
<span class="title"> </span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../docs/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">BC Mappings Catalog</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../mappings/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Committers' Guide</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../comguide/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Contributors' Guide</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../conguide/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component is-current">
<span class="title">Design Docs</span>
<ul class="versions">
<li class="version is-current is-latest">
<a href="../about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Extensions Catalog</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../extensions/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Incubator Catalog</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../incubator/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">JDO/DataNucleus</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../pjdo/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Legacy Catalog</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../legacy/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Reference Guide</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../refguide/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Release Notes</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../relnotes/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Restful Objects Viewer</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../vro/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Security Guide</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../security/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Setup Guide</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../setupguide/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Subdomains Catalog</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../subdomains/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Testing Guide</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../testing/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">User Guide</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../userguide/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Value Types Catalog</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../valuetypes/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Wicket Viewer</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../vw/2.0.0-M3/about.html">2.0.0-M3</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</aside>
</div>
<main role="main">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<a href="../../../docs/2.0.0-M3/about.html" class="home-link"></a>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li><a href="../about.html">Design Docs</a></li>
<li><a href="about.html">Runtime Services</a></li>
<li><a href="ContentNegotiationService.html">ContentNegotiationService</a></li>
</ul>
</nav>
<div class="edit-this-page"><a href="https://github.com/apache/isis/edit/2.0.0-M3/core/runtimeservices/src/main/adoc/modules/runtime-services/pages/ContentNegotiationService.adoc">Edit</a></div>
</div>
<article class="doc">
<a name="section-top"></a>
<h1 class="page"><code>ContentNegotiationService</code></h1>
<div id="preamble">
<div class="sectionbody">
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
TODO: this content has not yet been reviewed/updated for v2.0
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <code>ContentNegotiationService</code> is a plug-in point for the <a href="../../../vro/2.0.0-M3/about.html" class="page">RestfulObjects viewer</a> so that it can generate representations according to HTTP <code>Accept</code> header of the request. This idea is discussed in section 34.1 of the <a href="http://restfulobjects.org">Restful Objects spec</a> v1.0.</p>
</div>
<div class="paragraph">
<p>The principal motivation is to allow more flexible representations to be generated for REST clients that (perhaps through their use of a certain Javascript library, say) expect, or at least works best with, a certain style of representation.</p>
</div>
<div class="paragraph">
<p>Another use case is to support "third party" REST clients over which you have no control. In this scenario you <em>must not</em> naively expose entities through the RO viewer, because over time those entities will inevitably evolve and change their structure. If the entities were exposed directly then those REST clients will break.</p>
</div>
<div class="paragraph">
<p>Instead you need to create some sort of stable facade over your domain entities, one which you will preserve even if the domain entities change. There are three ways in which you can do this:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>first is to solve the problem at the domain layer by defining a regular Apache Isis <a href="../../../userguide/2.0.0-M3/fun/overview.html#view-models" class="page">view model</a>. This is then surfaced over the RO viewer. <br></p>
<div class="paragraph">
<p>If the underlying entities change, then care must be taken to ensure that structure of the view model nevertheless is unchanged.</p>
</div>
</li>
<li>
<p>a second option is to solve the problem at the persistence layer, but defining a (SQL) view in the database and then <a href="../../../pjdo/2.0.0-M3/jdo-mappings.html#mapping-to-a-view" class="page">mapping this</a> to a (read-only) entity. Again this is surfaced by the RO viewer. <br></p>
<div class="paragraph">
<p>If the underlying tables change (as the result of a change in their corresponding domain entities) then once more the view must be refactored so that it still presents the same structure.</p>
</div>
</li>
<li>
<p>our third option is to solve the problem at the presentation layer, using the <code>ContentNegotiationService</code> described in this section.<br></p>
<div class="paragraph">
<p>The <code>ContentNegotiationService</code> is responsible for inspecting the HTTP <code>Accept</code> header, and use this to select the correct representation to render. <br></p>
</div>
<div class="paragraph">
<p>The Apache Isis framework provides three implementations of <code>ContentNegotiationService</code> which inspects different elements of the HTTP <code>Accept</code> header. One of these implementations, <code>ContentNegotiationServiceXRoDomainType</code> will further delegate down to the companion <a href="../../../refguide/2.0.0-M3/applib-svc/ContentMappingService.html" class="page"><code>ContentMappingService</code></a> service (if configured/available), based on the value of the "x-ro-domain-type" parameter of the header.<br></p>
</div>
<div class="paragraph">
<p>A typical implementation of <code>ContentMappingService</code> will convert the domain object into some sort of DTO (data transfer object) as specified by the "x-ro-domaintype". If this DTO is annotated with JAXB or Jackson mappings, then the RO viewer (courtesy of the underlying <a href="http://resteasy.jboss.org/">RestEasy</a> framework) can serialize these directly.<br></p>
</div>
<div class="paragraph">
<p>What all that means is that, if the underlying entities change, we are required to update the mappings in the <code>ContentMappingService</code> to map to the same DTOs.</p>
</div>
</li>
</ul>
</div>
<div class="paragraph">
<p>This diagram illustrates the three options available:</p>
</div>
<div class="imageblock">
<div class="content">
<a class="image" href="_images/ContentNegotiationService/facade-choices.png"><img src="_images/ContentNegotiationService/facade-choices.png" alt="facade choices" width="700px"></a>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="spi"><a class="anchor" href="#spi"></a>SPI</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The SPI defined by this service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public interface ContentNegotiationService {
Response.ResponseBuilder buildResponse( <i class="conum" data-value="1"></i><b>(1)</b>
RepresentationService.Context2 renderContext2,
ObjectAdapter objectAdapter);
Response.ResponseBuilder buildResponse( <i class="conum" data-value="2"></i><b>(2)</b>
RepresentationService.Context2 renderContext2,
ObjectAndProperty objectAndProperty);
Response.ResponseBuilder buildResponse( <i class="conum" data-value="3"></i><b>(3)</b>
RepresentationService.Context2 renderContext2,
ObjectAndCollection objectAndCollection);
Response.ResponseBuilder buildResponse( <i class="conum" data-value="4"></i><b>(4)</b>
RepresentationService.Context2 renderContext2,
ObjectAndAction objectAndAction);
Response.ResponseBuilder buildResponse( <i class="conum" data-value="5"></i><b>(5)</b>
RepresentationService.Context2 renderContext2,
ObjectAndActionInvocation objectAndActionInvocation);
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>representation of a single object, as per section 14.4 of the RO spec, v1.0</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>representation of a single property of an object, as per section 16.4 of the RO spec v1.0</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>representation of a single collection of an object, as per section 17.5 of the RO spec v1.0</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>representation of a single action (prompt) of an object, as per section 18.2 of the RO spec v1.0</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>representation of the results of a single action invocation, as per section 19.5 of the RO spec v1.0</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>These methods provide:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>a <code>RepresentationService.Context2</code> which provides access to request-specific context (eg HTTP headers), session-specific context (eg authentication) and global context (eg configuration settings)</p>
</li>
<li>
<p>an object representing the information to be rendered<br></p>
<div class="paragraph">
<p>eg <code>ObjectAdapter</code>, <code>ObjectAndProperty</code>, <code>ObjectAndCollection</code> etc</p>
</div>
</li>
</ul>
</div>
<div class="paragraph">
<p>In all cases, returning <code>null</code> will result in the regular RO spec representation being returned.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="implementation"><a class="anchor" href="#implementation"></a>Implementation</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>ContentNegotiationServiceAbstract</code> (in <code>o.a.i.v.ro.rendering.service.conneg</code>) provides a no-op implementation of the SPI, along with supporting methods:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public abstract class ContentNegotiationServiceAbstract implements ContentNegotiationService {
...
protected Object objectOf(final ObjectAdapter objectAdapter) { /* ... */ }
protected Object returnedObjectOf(ObjectAndActionInvocation objectAndActionInvocation) { /* ... */ }
protected Class&lt;?&gt; loadClass(String cls) { /* ... */ }
protected void ensureJaxbAnnotated(Class&lt;?&gt; domainType) { /* ... */ }
protected void ensureDomainObjectAssignable(
String xRoDomainType, Class&lt;?&gt; domainType, Object domainObject) { /* ... */ }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>As discussed in the introduction, the framework also provides three implementation of this service, one of which is <code>o.a.i.v.ro.rendering.service.conneg.ContentNegotiationServiceXRoDomainType</code>. This implementation handles content negotiation for two of the possible representations, object representations and for action result representations:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>For object representations it will handle requests with HTTP <code>Accept</code> headers of the form:</p>
<div class="ulist">
<ul>
<li>
<p><code>application/json;profile=urn:org.restfulobjects:repr-types/object;x-ro-domain-type=&#8230;&#8203;</code></p>
</li>
<li>
<p><code>application/xml;profile=urn:org.restfulobjects:repr-types/object;x-ro-domain-type=&#8230;&#8203;</code></p>
</li>
</ul>
</div>
</li>
<li>
<p>for action result representations it will similarly handle requests with HTTP <code>Accept</code> headers of the form:</p>
<div class="ulist">
<ul>
<li>
<p><code>application/json;profile=urn:org.restfulobjects:repr-types/action-result;x-ro-domain-type=&#8230;&#8203;</code><br></p>
</li>
<li>
<p><code>application/xml;profile=urn:org.restfulobjects:repr-types/action-result;x-ro-domain-type=&#8230;&#8203;</code></p>
</li>
</ul>
</div>
</li>
</ul>
</div>
<div class="paragraph">
<p>The value of the <code>x-ro-domain-type</code> parameter corresponds to the DTO to be mapped into by the <a href="../../../refguide/2.0.0-M3/applib-svc/ContentMappingService.html" class="page"><code>ContentMappingService</code></a>.</p>
</div>
<div class="paragraph">
<p>If the DTO is annotated with JAXB, then also note that the runtime type must be annotated with the JAXB <code>javax.xml.bind.annotation.XmlRootElement</code> so that RestEasy is able to unambiguously serialize it.</p>
</div>
<div class="paragraph">
<p>The other two implementations of <code>ContentNegotiationService</code> are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>ContentNegotiationServiceForRestfulObjectsV1_0</code><br></p>
<div class="paragraph">
<p>which returns representations according to the <a href="http://restfulobjects.org">Restful Objects</a> spec.</p>
</div>
<div class="paragraph">
<p>One extension (specific to Apache Isis, not part of the RO spec) is that actions can also be invoked with an HTTP <code>Accept</code> header of the form:</p>
</div>
<div class="paragraph">
<p><code>application/json;profile=urn:org.restfulobjects:repr-types/object</code></p>
</div>
<div class="paragraph">
<p>If the action result returns a collection then this will automatically converted to a <code>DomainObjectList</code> view model.
This can be useful for generic viewers.</p>
</div>
</li>
<li>
<p><code>ContentNegotiationServiceOrgApacheIsisV1</code><br></p>
<div class="paragraph">
<p>which returns <a href="../../../vro/2.0.0-M3/simplified-representations.html" class="page">simplified representations</a></p>
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="usage"><a class="anchor" href="#usage"></a>Usage</h2>
<div class="sectionbody">
<div class="paragraph">
<p>For example, consider a todo app that defines a <code>ToDoItemDto</code> class, generated from an XSD and therefore JAXB annotated.</p>
</div>
<div class="paragraph">
<p>An implementation of <code>ContentMappingService</code> that maps the application&#8217;s <code>todoapp.dom.module.todoitem.ToDoItem</code> entities into <code>todoapp.dto.module.todoitem.ToDoItemDto</code> classes.</p>
</div>
<div class="paragraph">
<p>A REST client can therefore request a DTO representation of an entity by invoking</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code>http://localhost:8080/restful/objects/TODO/0</code></pre>
</div>
</div>
<div class="paragraph">
<p>with an <code>Accept</code> header of:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code>application/xml;profile=urn:org.restfulobjects:repr-types/object;x-ro-domain-type=todoapp.dto.module.todoitem.ToDoItemDto</code></pre>
</div>
</div>
<div class="paragraph">
<p>will result in an XML serialization of that class:</p>
</div>
<div class="imageblock">
<div class="content">
<a class="image" href="_images/ContentNegotiationService/accept-xml.png"><img src="_images/ContentNegotiationService/accept-xml.png" alt="accept xml" width="700px"></a>
</div>
</div>
<div class="paragraph">
<p>while similarly hitting the same URL with an <code>Accept</code> header of:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code>application/json;profile=urn:org.restfulobjects:repr-types/object;x-ro-domain-type=todoapp.dto.module.todoitem.ToDoItemDto</code></pre>
</div>
</div>
<div class="paragraph">
<p>will result in the JSON serialization of that class:</p>
</div>
<div class="imageblock">
<div class="content">
<a class="image" href="_images/ContentNegotiationService/accept-json.png"><img src="_images/ContentNegotiationService/accept-json.png" alt="accept json" width="700px"></a>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configuration"><a class="anchor" href="#configuration"></a>Configuration</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The default <code>ContentNegotiationServiceXRoDomainType</code> implementation provides a <a href="../../../refguide/2.0.0-M3/config/about.html" class="page">configuration property</a> which controls whether a mapped domain object is pretty-printed (formatted, indented) or not:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-ini hljs" data-lang="ini">isis.services.ContentNegotiationServiceXRoDomainType.prettyPrint=true</code></pre>
</div>
</div>
<div class="paragraph">
<p>If the property is not set, then the default depends on the <a href="../../../refguide/2.0.0-M3/config/about.html#deployment-types" class="page">deployment type</a>; production mode will disable pretty printing, while prototyping mode will enable it.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="registering-the-services"><a class="anchor" href="#registering-the-services"></a>Registering the Services</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Apache Isis' default implementations of <code>ContentNegotiationService</code> service are automatically registered and injected (it is annotated with <code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use Spring&#8217;s <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/annotation/Order.html"><code>@Order</code></a> annotation (as explained in the <a href="../../../refguide/2.0.0-M3/applib-svc/about.html#overriding-the-services.adoc" class="page">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="related-services"><a class="anchor" href="#related-services"></a>Related Services</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The default implementation of <code>ContentNegotiationService</code> delegates to <a href="../../../refguide/2.0.0-M3/applib-svc/ContentMappingService.html" class="page"><code>ContentMappingService</code></a> (if present) to convert domain entities into a stable form (eg DTO).</p>
</div>
<div class="paragraph">
<p>The <code>ContentNegotiationService</code> is itself called by the (default implementation of) <a href="RepresentationService.html" class="page"><code>RepresentationService</code></a>.</p>
</div>
</div>
</div>
</article>
<aside class="article-aside toc" role="navigation">
<p class="toc-title">On this page</p>
<div id="article-toc"></div>
</aside>
</main>
</div>
<footer class="footer">
<div class="content">
<div class="copyright">
<p>
Copyright © 2010~2020 The Apache Software Foundation, licensed under the Apache License, v2.0.
<br/>
Apache, the Apache feather logo, Apache Isis, and the Apache Isis project logo are all trademarks of The Apache Software Foundation.
</p>
</div>
<div class="revision">
<p>Revision: SNAPSHOT</p>
</div>
</div>
</footer>
<script src="../../../_/js/site.js"></script>
<script async src="../../../_/js/vendor/highlight.js"></script>
<script src="../../../_/js/vendor/jquery-3.4.1.min.js"></script>
<script src="../../../_/js/vendor/jquery-ui-1.12.1.custom.widget-only.min.js"></script>
<script src="../../../_/js/vendor/jquery.tocify.min.js"></script>
<script>
$(function() {
$("#article-toc").tocify( {
showEffect: "slideDown",
hashGenerator: "pretty",
hideEffect: "slideUp",
selectors: "h2, h3",
scrollTo: 120,
smoothScroll: true,
theme: "jqueryui",
highlightOnScroll: true
} );
});
</script>
</body>
</html>