blob: 3b4fcb4c5f0c45ad1f170ff31737ca9c6e00aaec [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Domain Entities and Services :: Apache Isis</title>
<link rel="canonical" href="https://isis.apache.org/userguide/2.0.0-M5/fun/domain-entities-and-services.html">
<meta name="generator" content="Antora 2.3.4">
<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="stylesheet" href="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.css"/>
<link rel="home" href="https://isis.apache.org" title="Apache Isis">
<link rel="next" href="object-members.html" title="Properties, Collections &amp;amp; Actions">
<link rel="prev" href="overview.html" title="Overview">
</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 hide-for-print">
<span>
<input id="algolia-search-input" placeholder="Search"></span>
</span>
</div>
<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/2.0.0-M5/starters/helloworld.html">Hello World</a>
<a class="navbar-item" href="../../../docs/2.0.0-M5/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/2.0.0-M5/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/2.0.0-M5/resources/cheatsheet.html">Cheatsheet</a>
<a class="navbar-item" href="../../../docs/2.0.0-M5/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/2.0.0-M5/about.html">Setup Guide</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Core</span>
<a class="navbar-item" href="../../../userguide/2.0.0-M5/about.html">User Guide</a>
<a class="navbar-item" href="../../../refguide/2.0.0-M5/about.html">Reference Guide</a>
<a class="navbar-item" href="../../../testing/2.0.0-M5/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/2.0.0-M5/about.html">Subdomain Libraries</a>
<a class="navbar-item" href="../../../valuetypes/2.0.0-M5/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/2.0.0-M5/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/2.0.0-M5/about.html">Incubator</a>
<a class="navbar-item" href="../../../legacy/2.0.0-M5/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/2.0.0-M5/about.html">Web UI (Wicket)</a>
<a class="navbar-item" href="../../../vro/2.0.0-M5/about.html">REST API (Restful Objects)</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Security</span>
<a class="navbar-item" href="../../../security/2.0.0-M5/about.html">Security Guide</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Persistence</span>
<a class="navbar-item" href="../../../pjpa/2.0.0-M5/about.html">JPA (EclipseLink)</a>
<a class="navbar-item" href="../../../pjdo/2.0.0-M5/about.html">JDO (DataNucleus)</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Extensions</span>
<a class="navbar-item" href="../../../extensions/2.0.0-M5/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/2.0.0-M5/support/slack-channel.html">Slack</a>
<a class="navbar-item" href="../../../docs/2.0.0-M5/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/2.0.0-M5/downloads/how-to.html">Downloads</a>
<a class="navbar-item" href="../../../relnotes/2.0.0-M5/about.html">Release Notes</a>
<a class="navbar-item" href="../../../docs/2.0.0-M5/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/2.0.0-M5/about.html">Contributors' Guide</a>
<a class="navbar-item" href="../../../comguide/2.0.0-M5/about.html">Committers' Guide</a>
<a class="navbar-item" href="../../../core/2.0.0-M5/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/2.0.0-M5/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="userguide" data-version="2.0.0-M5">
<aside class="nav">
<div class="panels">
<div class="nav-panel-pagination">
<a class="page-previous" rel="prev" href="overview.html" title="Overview"><span></span></a>
<a class="page-next" rel="next"
href="object-members.html" title="Properties, Collections &amp;amp; Actions"><span></span></a>
<!--
page.parent doesn't seem to be set...
<a class="page-parent disabled" rel="prev" href="" title="Overview"><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">User Guide</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="concepts-patterns.html">Concepts &amp; Patterns</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="overview.html">Overview</a>
</li>
<li class="nav-item is-current-page" data-depth="1">
<a class="nav-link" href="domain-entities-and-services.html">Domain Entities &amp; Services</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="object-members.html">Properties, Collections &amp; Actions</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="ui.html">UI Layout &amp; Hints</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="business-rules.html">Business Rules</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="drop-downs-and-defaults.html">Drop downs and Defaults</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="meta-annotations.html">Meta-annotations</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="view-models.html">View Models</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="mixins.html">Mixins</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="modules.html">Modules</a>
</li>
<li class="nav-item" data-depth="1">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../btb/about.html">Beyond the Basics</a>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../btb/i18n.html">i18n</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../btb/headless-access.html">Headless Access</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../btb/hints-and-tips.html">Hints-n-Tips</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../btb/programming-model.html">Programming Model</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="1">
<button class="nav-item-toggle"></button>
<span class="nav-text">Extensions</span>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../command-log/about.html">Command Log</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../command-replay/about.html">Command Replay</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../flyway/about.html">Flyway</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../model-annotation/about.html">Model Annotation</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../quartz/about.html">Quartz</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
</div>
<div class="nav-panel-explore" data-panel="explore">
<div class="context">
<span class="title">User Guide</span>
<span class="version">2.0.0-M5</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-M5/about.html">2.0.0-M5</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">BC Mapping Libraries</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../mappings/2.0.0-M5/about.html">2.0.0-M5</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-M5/about.html">2.0.0-M5</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-M5/about.html">2.0.0-M5</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Design Docs</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../core/2.0.0-M5/about.html">2.0.0-M5</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-M5/about.html">2.0.0-M5</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-M5/about.html">2.0.0-M5</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-M5/about.html">2.0.0-M5</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">JPA</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../pjpa/2.0.0-M5/about.html">2.0.0-M5</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-M5/about.html">2.0.0-M5</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-M5/about.html">2.0.0-M5</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-M5/about.html">2.0.0-M5</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">REST API (Restful Objects Viewer)</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../vro/2.0.0-M5/about.html">2.0.0-M5</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-M5/about.html">2.0.0-M5</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-M5/about.html">2.0.0-M5</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-M5/about.html">2.0.0-M5</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-M5/about.html">2.0.0-M5</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Tooling</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../tooling/2.0.0-M5/about.html">2.0.0-M5</a>
</li>
</ul>
</li>
<li class="component is-current">
<span class="title">User Guide</span>
<ul class="versions">
<li class="version is-current is-latest">
<a href="../about.html">2.0.0-M5</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-M5/about.html">2.0.0-M5</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Web UI (Wicket Viewer)</span>
<ul class="versions">
<li class="version is-latest">
<a href="../../../vw/2.0.0-M5/about.html">2.0.0-M5</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-M5/about.html" class="home-link"></a>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li><a href="../about.html">User Guide</a></li>
<li><a href="domain-entities-and-services.html">Domain Entities &amp; Services</a></li>
</ul>
</nav>
<div class="edit-this-page"><a href="https://github.com/apache/isis/edit/2.0.0-M5/antora/components/userguide/modules/fun/pages/domain-entities-and-services.adoc">Edit</a></div>
</div>
<article class="doc">
<a name="section-top"></a>
<h1 class="page">Domain Entities and Services</h1>
<div id="preamble">
<div class="sectionbody">
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>This section describes entities using JDO annotations, but (the more widely used) JPA (in conjunction with Spring Data) is also supported.</p>
</div>
<div class="paragraph">
<p>See the <a href="../../../pjdo/2.0.0-M5/about.html" class="page">JDO/DataNucleus</a> and <a href="../../../pjpa/2.0.0-M5/about.html" class="page">JPA/Eclipselink</a> documentation for more details on how to configure one or the other.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="domain-entities"><a class="anchor" href="#domain-entities"></a>Domain Entities</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Domain entities are persistent domain objects, with their persistence handled an ORM (such as <a href="../../../pjdo/2.0.0-M5/about.html" class="page">JDO/DataNucleus</a>).
As such, they are mapped to a persistent object store, typically an RDBMS, with the ORM taking care of both lazy loading and also the persisting of modified ("dirty") objects.</p>
</div>
<div class="paragraph">
<p>The vast majority of such entities will be annotated with <code>@DomainObject(nature=ENTITY)</code>.
In addition they will also require ORM metadata.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>for <a href="../../../pjpa/2.0.0-M5/about.html" class="page">JPA/Eclipselink</a>, this requires the <code>javax.persistence.Entity</code> annotation</p>
</li>
<li>
<p>for <a href="../../../pjdo/2.0.0-M5/about.html" class="page">JDO/DataNucleus</a>, this requires the
<code>@javax.jdo.annotations.PersistenceCapable</code> annotation.</p>
</li>
</ul>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
It is also possible to specify ORM metadata using <code>.xml</code> files.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>In this section we discuss the mechanics of writing domain objects that comply with Apache Isis' programming model.</p>
</div>
<div class="sect2">
<h3 id="entities-jpa"><a class="anchor" href="#entities-jpa"></a>Entities (JPA)</h3>
<div class="paragraph">
<p>JPA entities are typically defined using the <code>@javax.persistence.Entity</code> annotation, with additional annotations to define their primary key, scalar properties and relationships to other entities.</p>
</div>
<div class="paragraph">
<p>For some examples, see:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.baeldung.com/jpa-entities">Baeldung article on JPA entities</a></p>
</li>
<li>
<p><a href="https://spring.io/guides/gs/accessing-data-jpa/">Spring Data tutorial</a></p>
</li>
<li>
<p><a href="https://docs.jboss.org/hibernate/annotations/3.5/reference/en/html/entity.html#entity-mapping">JBoss tutorial</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>See the <a href="../../../pjpa/2.0.0-M5/about.html" class="page">JPA/Eclipselink object store</a> for further information on annotating domain entities.</p>
</div>
</div>
<div class="sect2">
<h3 id="entities-jdo"><a class="anchor" href="#entities-jdo"></a>Entities (JDO)</h3>
<div class="paragraph">
<p>See the <a href="../../../pjdo/2.0.0-M5/about.html" class="page">JDO/DataNucleus object store</a> for further information on annotating domain entities.</p>
</div>
<div class="sect3">
<h4 id="persistencecapable"><a class="anchor" href="#persistencecapable"></a>PersistenceCapable</h4>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
This section is specific to the <a href="../../../pjdo/2.0.0-M5/about.html" class="page">JDO API</a>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>With the <a href="../../../pjdo/2.0.0-M5/about.html" class="page">JDO API</a>, entities are flagged as being "persistence capable", indicating how the ORM should manage their identity:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@javax.jdo.annotations.PersistenceCapable( <i class="conum" data-value="1"></i><b>(1)</b>
identityType=IdentityType.DATASTORE, <i class="conum" data-value="2"></i><b>(2)</b>
schema = "simple", <i class="conum" data-value="3"></i><b>(3)</b>
table = "SimpleObject"
)
@javax.jdo.annotations.DatastoreIdentity( <i class="conum" data-value="4"></i><b>(4)</b>
strategy=javax.jdo.annotations.IdGeneratorStrategy.IDENTITY,
column="id"
)
@javax.jdo.annotations.Version( <i class="conum" data-value="5"></i><b>(5)</b>
strategy= VersionStrategy.DATE_TIME,
column="version"
)
@DomainObject( <i class="conum" data-value="6"></i><b>(6)</b>
objectType = "simple.SimpleObject"
)
public class SimpleObject { /* ... */ }</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>The <code>@PersistenceCapable</code> annotation indicates that this is an entity to DataNucleus.
The DataNucleus enhancer acts on the bytecode of compiled entities, injecting lazy loading and dirty object tracking functionality.
Enhanced entities end up also implementing the <code>javax.jdo.spi.PersistenceCapable</code> interface.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Indicates how identifiers for the entity are handled.
Using <code>DATASTORE</code> means that a DataNucleus is responsible for assigning the value (rather than the application).</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Specifies the RDBMS database schema and table name for this entity will reside.
The schema should correspond with the module in which the entity resides.
The table will default to the entity name if omitted.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>For entities that are using <code>DATASTORE</code> identity, indicates how the id will be assigned.
A common strategy is to allow the database to assign the id, for example using an identity column or a sequence.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>The <code>@Version</code> annotation is useful for optimistic locking; the strategy indicates what to store in the <code>version</code> column.</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>The <code>@DomainObject</code> annotation identifies the domain object to Apache Isis (not DataNucleus).
It isn&#8217;t necessary to include this annotation&#8201;&#8212;&#8201;at least, not for entities&#8201;&#8212;&#8201;but it is nevertheless recommended.
In particular, its strongly recommended that the <code>objectType</code> (which acts like an alias to the concrete domain class) is specified; note that it corresponds to the schema/table for DataNucleus' <code>@PersistenceCapable</code> annotation.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="key-properties-jdo"><a class="anchor" href="#key-properties-jdo"></a>Key Properties (JDO)</h4>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
This section is specific to the <a href="../../../pjdo/2.0.0-M5/about.html" class="page">JDO API</a>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>All domain entities will have some sort of mandatory key properties.
The example below is a very simple case, where the entity is identified by a <code>name</code> property.
This is often used in database unique indices, and in the <code>toString()</code> implementation:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import javax.jdo.annotations.Column;
import javax.jdo.annotations.Unique;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.ToString.Include;
...
@Unique(
name="SimpleObject_name_UNQ", members = {"name"}) <i class="conum" data-value="1"></i><b>(1)</b>
@ToString(onlyExplicitlyIncluded = true)
public class SimpleObject
implements Comparable&lt;SimpleObject&gt; { <i class="conum" data-value="2"></i><b>(2)</b>
public SimpleObject(String name) {
setName(name);
}
@Column(allowsNull="false", length=50) <i class="conum" data-value="3"></i><b>(3)</b>
@Getter @Setter <i class="conum" data-value="4"></i><b>(4)</b>
@ToString.Include <i class="conum" data-value="5"></i><b>(5)</b>
private String name;
private final static Comparator&lt;SimpleObject&gt; comparator =
Comparator.comparing(SimpleObject::getName);
@Override
public int compareTo(final SimpleObject other) {
return comparator.compare(this, other); <i class="conum" data-value="6"></i><b>(6)</b>
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>DataNucleus will automatically add a unique index to the primary surrogate id (discussed above), but additional alternative keys can be defined using the <code>@Unique</code> annotation.
In the example above, the "name" property is assumed to be unique.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Although not required, we strongly recommend that all entities are naturally <code>Comparable</code>.
This then allows parent/child relationships to be defined using <code>SortedSet</code>s; RDBMS after all are set-oriented.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Chances are that some of the properties of the entity will be mandatory, for example any properties that represent an alternate unique key to the entity.
The <code>@Column</code> annotation specifies the length of the column in the RDBMS, and whether it is mandatory.
<div class="paragraph">
<p>Given there is a unique index on <code>name</code>, we want this to be mandatory.</p>
</div>
<div class="paragraph">
<p>We can also represent this using a constructor that defines these mandatory properties.
The ORM will create a no-arg constructor to allow domain entity to be rehydrated from the database at runtime (it then sets all state reflectively).</p>
</div></td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Use Lombok to generate the getters and setters for the <code>name</code> property itself.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>Use Lombok to create a <code>toString()</code> implementation that includes the value of <code>name</code> property.</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>Use <code>java.util.Comparator#comparing()</code> to implement <code>Comparable</code> interface.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="queries-jdo"><a class="anchor" href="#queries-jdo"></a>Queries (JDO)</h4>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
This section is specific to the <a href="../../../pjdo/2.0.0-M5/about.html" class="page">JDO API</a>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>When using JDO, it&#8217;s also common for domain entities to have queries annotated on them.
These are used by repository domain services to query for instances of the entity:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">...
@javax.jdo.annotations.Queries({
@javax.jdo.annotations.Query( <i class="conum" data-value="1"></i><b>(1)</b>
name = "findByName", <i class="conum" data-value="2"></i><b>(2)</b>
value = "SELECT " <i class="conum" data-value="3"></i><b>(3)</b>
+ "FROM domainapp.modules.simple.dom.impl.SimpleObject " <i class="conum" data-value="4"></i><b>(4)</b>
+ "WHERE name.indexOf(:name) &gt;= 0 ") <i class="conum" data-value="5"></i><b>(5)</b>
})
...
public class SimpleObject { /* ... */ }</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>There may be several <code>@Query</code> annotations, nested within a <code>@Queries</code> annotation) defines queries using JDOQL.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Defines the name of the query.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>The definition of the query, using JDOQL syntax.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>The fully-qualified class name.<br>
Must correspond to the class on which the annotation is defined (the framework checks this automatically on bootstrapping).</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>In this particular query, is an implementation of a LIKE "name%" query.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>JDO/DataNucleus provides several APIs for defining queries, including entirely programmatic and type-safe APIs; but JDOQL is very similar to SQL and so easily learnt.</p>
</div>
<div class="paragraph">
<p>To actually use the above definition, the framework provides the <a href="../../../refguide/2.0.0-M5/applib/index/services/repository/RepositoryService.html" class="page">RepositoryService</a>.
This is a generic repository for any domain class.</p>
</div>
<div class="paragraph">
<p>The corresponding repository method for the above query is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public List&lt;SimpleObject&gt; findByName(String name) {
return repositoryService.allMatches( <i class="conum" data-value="1"></i><b>(1)</b>
Query.named(SimpleObject.class, <i class="conum" data-value="2"></i><b>(2)</b>
"findByName") <i class="conum" data-value="3"></i><b>(3)</b>
.withParameter("name", name) <i class="conum" data-value="4"></i><b>(4)</b>
);
}
@javax.inject.Inject
RepositoryService repositoryService;</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>find all instances that match the query</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Specifies the class that is annotated with <code>@Query</code></td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Corresponds to the <code>@Query#name</code> attribute</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Corresponds to the <code>:name</code> parameter in the query JDOQL string</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="domain-services"><a class="anchor" href="#domain-services"></a>Domain Services</h2>
<div class="sectionbody">
<div class="paragraph">
<p><em>Domain services</em> are (usually) singleton stateless services that provide additional functionality.
This may be exposed in the UI, or might be invoked programmatically.</p>
</div>
<div class="paragraph">
<p>However, a service cannot have (persisted) properties, nor can it have (persisted) collections.</p>
</div>
<div class="paragraph">
<p>Domain services that are visible in the UI or REST API are annotated with <a href="../../../refguide/2.0.0-M5/applib/index/annotation/DomainService.html" class="page">@DomainService()</a>, while services that are <em>programmatic</em> in nature should be simply annotated using Spring&#8217;s <a href="#https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Component.html">@Component</a> or one of its specializations, eg
<a href="#https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Service.html">@Service</a>
or<a href="#https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Repository.html">@Repository</a>.</p>
</div>
<div class="paragraph">
<p>Apache Isis runs on top of Spring Boot, and relies on Spring Boot for dependency injection using <code>@javax.inject.Inject</code>.
The Spring <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/annotation/Order.html">@Order</a> annotation is used to prioritize multiple service implementations, effectively allowing any framework-provided domain service to be substituted out by a user-defined one with higher priority if required.</p>
</div>
<div class="paragraph">
<p>This section looks at the programming model for writing your own domain services.</p>
</div>
<div class="sect2">
<h3 id="nature-of-service"><a class="anchor" href="#nature-of-service"></a>Nature of Service</h3>
<div class="paragraph">
<p>Apache Isis uses Spring Boot to instantiate and manage the dependency injection of domain services.
The vast majority of these are singleton (application) scoped; a smaller number are request scoped (using the <a href="../../../refguide/2.0.0-M5/applib/index/annotation/InteractionScope.html" class="page">@IsisSessionScope</a> annotation).</p>
</div>
<div class="paragraph">
<p>Accordingly, all domain services are annotated or meta-annotated using Spring&#8217;s <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Component.html">@Component</a> annotation.</p>
</div>
<div class="paragraph">
<p>For domain services to be visible in the Apache Isis UI, they must be annotated with <a href="../../../refguide/2.0.0-M5/applib/index/annotation/DomainService.html" class="page">@DomainService</a>.
Its <a href="../../../refguide/2.0.0-M5/applib/index/annotation/DomainService.html#nature" class="page">#nature()</a> attribute is either:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>VIEW</code> (the default if not specified)</p>
<div class="paragraph">
<p>which indicates that the actions should appear on the menu of the <a href="../../../vw/2.0.0-M5/about.html" class="page">Web UI (Wicket viewer)</a>, and as top-level actions for the REST API provided by the <a href="../../../vro/2.0.0-M5/about.html" class="page">REST API (Restful Objects viewer)</a>.</p>
</div>
</li>
<li>
<p><code>REST</code></p>
<div class="paragraph">
<p>which indicates that the actions should appear in the REST API provided by the <a href="../../../vro/2.0.0-M5/about.html" class="page">REST API (Restful Objects viewer)</a>, but not rendered by the <a href="../../../vw/2.0.0-M5/about.html" class="page">Web UI (Wicket viewer)</a>.</p>
</div>
</li>
</ul>
</div>
<div class="paragraph">
<p>It&#8217;s also possible to define a "programmatic" domain service, meaning one that is instantiated and injected by Spring Boot, but is not visible in the UI or REST API.
For example, the <a href="../../../subdomains/2.0.0-M5/docx/about.html" class="page">Docx Library</a> provides a domain service that performs mail merge using MS Word, but this domain service is not intended to appear in the UI.
Such programmatic services are usually annotated with Spring&#8217;s <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Service.html">@Service</a> annotation or <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Repository.html">@Repository</a>.</p>
</div>
</div>
<div class="sect2">
<h3 id="repository-and-factory"><a class="anchor" href="#repository-and-factory"></a>Repository and Factory</h3>
<div class="paragraph">
<p>The repository/factory uses an injected <a href="../../../refguide/2.0.0-M5/applib/index/services/repository/RepositoryService.html" class="page">RepositoryService</a> to both instantiate new objects and to query the database for existing objects of a given entity type.
Generally these services are not visible in UI, and so are annotated with <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Repository.html">@Repository</a></p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.springframework.stereotype.Repository;
import lombok.RequiredArgsConstructor;
@Repository <i class="conum" data-value="1"></i><b>(1)</b>
@RequiredArgsConstructor(onConstructor_ = {@Inject} ) <i class="conum" data-value="2"></i><b>(2)</b>
public CustomerRepository {
private final RepositoryService repositoryService;
public List&lt;Customer&gt; findByName(String name) {
return repositoryService.allMatches( <i class="conum" data-value="3"></i><b>(3)</b>
Query.named(Customer.class, "findByName")
.withParameter("name", name));
}
public Customer newCustomer(...) {
Customer Customer =
repositoryService.detachedEntity(Customer.class); <i class="conum" data-value="4"></i><b>(4)</b>
...
return repositoryService.persistAndFlush(Customer); <i class="conum" data-value="5"></i><b>(5)</b>
}
public List&lt;Customer&gt; allCustomers() { <i class="conum" data-value="6"></i><b>(6)</b>
return repositoryService.allInstances(Customer.class);
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Detected and managed by Spring Boot.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Lombok annotation for dependency injection of <a href="../../../refguide/2.0.0-M5/applib/index/services/repository/RepositoryService.html" class="page">RepositoryService</a> through generated constructor.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>uses injected <code>RepositoryService</code> to query via JDOQL.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>uses injected <code>RepositoryService</code> to instantiate a not-yet-persisted domain entity &#8230;&#8203;</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>... and then save into the database a new <code>Customer</code> instance.</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>Returns all instances (useful for prototyping, probably not for production).</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>There is no need to annotate the actions; they are implicitly hidden because of the domain service&#8217;s nature.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>JDO/Datanucleus also supports <a href="http://www.datanucleus.org:15080/products/accessplatform_5_2/jdo/query.html#jdoql_typed">type-safe queries</a>.
These can be executed through the <a href="../../../refguide/2.0.0-M5/persistence/index/jdo/applib/services/JdoSupportService.html" class="page">JdoSupportService</a> domain service.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="menu"><a class="anchor" href="#menu"></a>Menu</h3>
<div class="paragraph">
<p>Menu services provide actions to be rendered on the menu.</p>
</div>
<div class="paragraph">
<p>For the <a href="../../../vw/2.0.0-M5/about.html" class="page">Web UI (Wicket viewer)</a>, each service&#8217;s actions appear as a collection of menu items of a named menu, and this menu is on one of the three menu bars provided by the Wicket viewer.
Although these can be organised using annotations, it&#8217;s usually easier to use a <a href="#vw:ROOT:menubars-layout.adoc#file-based" class="page unresolved">file-based layout file</a> (<code>menubars.layout.xml</code>).</p>
</div>
<div class="paragraph">
<p>For the <a href="../../../vro/2.0.0-M5/about.html" class="page">REST API (Restful Objects viewer)</a>, all menu services are shown in the services representation.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import lombok.RequiredArgsConstructor;
@DomainService(nature = NatureOfService.VIEW) <i class="conum" data-value="1"></i><b>(1)</b>
@RequiredArgsConstructor(onConstructor_ = {@Inject} ) <i class="conum" data-value="2"></i><b>(2)</b>
public class Customers {
@Inject
protected final CustomerRepository customerRepository; <i class="conum" data-value="3"></i><b>(3)</b>
@Action(semantics = SemanticsOf.SAFE)
@ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT)
public List&lt;Customer&gt; findByName( <i class="conum" data-value="4"></i><b>(4)</b>
@ParameterLayout(named="Name") <i class="conum" data-value="5"></i><b>(5)</b>
final String name ) {
return customerRepository.findByName(name); <i class="conum" data-value="6"></i><b>(6)</b>
}
@Action(semantics = SemanticsOf.NON_IDEMPOTENT)
public Customer newCustomer(...) {
return customerRepository.newCustomer(...);
}
@Action( semantics = SemanticsOf.SAFE,
restrictTo = RestrictTo.PROTOTYPING ) <i class="conum" data-value="7"></i><b>(7)</b>
public List&lt;Customer&gt; listAll() {
return customerRepository.listAll();
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Identify the class as a domain service, to render in the menu.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Rendered in the UI as a "Find By Name" menu item underneath the "Customers" menu.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>The <a href="../../../refguide/2.0.0-M5/applib/index/annotation/ParameterLayout.html" class="page">@ParameterLayout</a> provides metadata for the parameter itself, in this case its name.
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>There&#8217;s no need to name the action parameters if the code is compiled using the <code>-parameters</code> flag to the Java compiler (javac); the framework will then use the name of the parameter itself.</p>
</div>
</td>
</tr>
</table>
</div></td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>the action implementation delegates to an injected repository.
The framework can inject into not just other domain services but will also automatically into domain entities and view models.
There is further discussion of service injection <a href="#injecting-services">below</a>.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td><a href="../../../refguide/2.0.0-M5/applib/index/annotation/Action.html#restrictTo" class="page">Prototype</a> actions are rendered only in prototyping mode.
A "list all" action such as this can be useful when exploring the domain with a small dataset.</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>Menu services typically delegate to an underlying repository/ies specific to the domain (rather than use <code>RepositoryService</code> directly, for example).</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Whether you separate out menu services from repository services is to some extent a matter of style.
One perspective is that these two closely related domain services nevertheless have different responsibilities, and so could be kept separate.
An alternative perspective is that the duplication is just unnecessary boilerplate, and conflicts with the naked objects philosophy.</p>
</div>
</div>
<div class="sect2">
<h3 id="event-subscribers"><a class="anchor" href="#event-subscribers"></a>Event Subscribers</h3>
<div class="paragraph">
<p>Domain services acting as event subscribers can subscribe to <a href="overview.html#lifecycle-events" class="page">lifecycle</a> events, influencing the rendering and behaviour of other objects.
Behind the scenes this uses Spring&#8217;s (in-memory) <a href="https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#context-functionality-events-annotation">event bus</a>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.springframework.stereotype.Service;
import org.springframework.context.event.EventListener;
import lombok.RequiredArgsConstructor;
@Service <i class="conum" data-value="1"></i><b>(1)</b>
@lombok.RequiredArgsConstructor(onConstructor_ = {@Inject} )
public class OnCustomerDeletedCascadeDeleteOrders {
private final OrderRepository orderRepository;
@EventListener(Customer.DeletedEvent.class) <i class="conum" data-value="2"></i><b>(2)</b>
public void on(final Customer.DeletedEvent ev) { <i class="conum" data-value="3"></i><b>(3)</b>
Customer customer = ev.getSource();
orderRepository.delete(customer);
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>subscriptions do not appear in the UI at all</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>use Spring Framework&#8217;s <a href="https://javadoc.io/doc/org.springframework/spring-context/latest/org/springframework/context/event/EventListener.html">@EventListener</a></td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>the parameter type of the method corresponds to the event emitted on the event bus.
The actual method name does not matter (though it must have <code>public</code> visibility).</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="scoped-services"><a class="anchor" href="#scoped-services"></a>Scoped services</h3>
<div class="paragraph">
<p>By default all domain services are application-scoped, in other words singletons.
Such domain services are required to be thread-safe, usually satisfied by being intrinsically stateless.</p>
</div>
<div class="paragraph">
<p>Sometimes though a service&#8217;s lifetime is applicable only to a single (http) request.
The framework has a number of such services, including a <a href="../../../refguide/2.0.0-M5/applib/index/services/scratchpad/Scratchpad.html" class="page">Scratchpad</a> service (to share adhoc data between methods), and <a href="../../../refguide/2.0.0-M5/applib/index/services/queryresultscache/QueryResultsCache.html" class="page">QueryResultsCache</a>, which as its name suggests will cache query results.
Such services <em>do</em> hold state, but that state is scoped per (possibly concurrent) request and should be removed afterwards.</p>
</div>
<div class="paragraph">
<p>The requirement for request-scoped services is supported using Apache Isis' own <a href="../../../refguide/2.0.0-M5/applib/index/annotation/InteractionScope.html" class="page">@IsisSessionScope</a> annotation (named because a short-lived <code>IsisSession</code> is created for each request).
This is used by the framework services and can also be used for user-defined services.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Service
@IsisSessionScope
public class MyService {
...
public void doSomething() { ... }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Unlike application-scoped services, these request-scoped services must be injected using a slightly different idiom (borrowed from CDI), using a <code>javax.inject.Provider</code>.
For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import javax.inject.Provider;
public class SomeClient {
...
@Inject
Provider&lt;MyService&gt; myServiceProvider; <i class="conum" data-value="1"></i><b>(1)</b>
public void someMethod() {
myServiceProvider.get() <i class="conum" data-value="2"></i><b>(2)</b>
.doSomething();
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Inject using <code>Provider</code></td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Obtain an instance using <code>Provider#get()</code></td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="configuration"><a class="anchor" href="#configuration"></a>Configuration</h3>
<div class="paragraph">
<p>Spring provides numerous mechanisms to configure domain services, both in terms of binding or passing in the configuration property to the service, and in terms of setting the value within some sort of configuration file.</p>
</div>
<div class="paragraph">
<p>The mechanism prefered by Apache Isis itself, and which you are free to use for your own services, is the type-safe <a href="https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/properties/ConfigurationProperties.html">ConfigurationProperties</a>, whereby the configuration properties are expressed in a series of nested static classes.</p>
</div>
<div class="paragraph">
<p>The <a href="../../../docs/2.0.0-M5/starters/simpleapp.html" class="page">simpleapp starter app</a> includes an example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.springframework.validation.annotation.Validated;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("app.simple-module")
@lombok.Data
@Validated
public static class Configuration {
private final Types types = new Types();
@lombok.Data
public static class Types {
private final Name name = new Name();
@lombok.Data
public static class Name {
private final Validation validation = new Validation();
@lombok.Data
public static class Validation {
private char[] prohibitedCharacters =
"!&amp;%$".toCharArray();
private String message =
"Character '{character}' is not allowed";
}
}
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This configuration property can be injected, like any other component, and makes the configuration value available in a type-safe fashion:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">val prohibitedCharacters =
config.getTypes().getName().getValidation().getProhibitedCharacters();</code></pre>
</div>
</div>
<div class="paragraph">
<p>For this configuration property service to be discovered and managed by Spring, we need to use the <a href="https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/properties/EnableConfigurationProperties.html">EnableConfigurationProperties</a> annotation.
This normally would reside on the owning module (discussed in more detail <a href="modules.html" class="page">later</a>):</p>
</div>
<div class="listingblock">
<div class="title">SimpleModule.java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.springframework.context.annotation.Configuration
@Configuration
// ...
@EnableConfigurationProperties({
SimpleModule.Configuration.class,
})
public class SimpleModule /* ... */ {
// ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>These configuration properties can then be specified using either Spring&#8217;s <code>application.yml</code> or <code>application.properties</code>.
For example:</p>
</div>
<div class="listingblock">
<div class="title">application.yml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-yml hljs" data-lang="yml">app:
simple-module:
types:
name:
validation:
message: "'{character}' is invalid."
prohibited-characters: "&amp;%$"</code></pre>
</div>
</div>
<div class="paragraph">
<p>Moreover, Spring is able to configure the IDE so that these configuration values can be specified using code completion.
All that is required is this dependency:</p>
</div>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;!-- IDE support --&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-configuration-processor&lt;/artifactId&gt;
&lt;optional&gt;true&lt;/optional&gt;
&lt;/dependency&gt;</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="initialization"><a class="anchor" href="#initialization"></a>Initialization</h3>
<div class="paragraph">
<p>Sometimes a domain service needs to perform initialization logic before it is ready to be used.</p>
</div>
<div class="paragraph">
<p>In many cases, such initialization can be performed within the constructor.
If the initialization has dependencies, then these can be injected using standard <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-spring-beans-and-dependency-injection">constructor injection</a>.</p>
</div>
<div class="paragraph">
<p>Alternatively, initialization can be moved into a <code>@PostConstruct</code> <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-postconstruct-and-predestroy-annotations">lifecycle callback</a>.
Shutdown is similar; the framework will call any method annotated with <code>javax.annotation.PreDestroy</code>.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="injecting-services"><a class="anchor" href="#injecting-services"></a>Injecting services</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Apache Isis runs on top of Spring Boot, and uses Spring Boot for dependency injection, both the application&#8217;s own domain services and also the many additional services defined by the framework (such as <a href="../../../refguide/2.0.0-M5/applib/index/services/repository/RepositoryService.html" class="page">RepositoryService</a>).</p>
</div>
<div class="paragraph">
<p>Since this is a core capability of Spring, it&#8217;s worth checking out Spring&#8217;s <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-collaborators">documentation</a> on the topic.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Injection is requested using the JEE <a href="https://docs.oracle.com/javaee/7/api/javax/inject/Inject.html">@javax.inject.Inject</a> annotation.
This is described in Spring&#8217;s documentation, <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-standard-annotations">using JSR330 standard annotations</a>.</p>
</div>
<div class="paragraph">
<p>It is also possible to use Spring&#8217;s own <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html">@Autowired</a> annotation.
Since the two annotations are effectively equivalent, we recommend using the JEE standard.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>However, not only does Apache Isis use Spring to autowire domain services into other services, the framework <em>also</em> ensures that services are injected into any domain object (eg <a href="overview.html#domain-entities" class="page">entity</a>, <a href="overview.html#view-models" class="page">view model</a>, <a href="overview.html#mixins" class="page">mixins</a>, <a href="../../../testing/2.0.0-M5/fixtures/about.html#fixture-scripts" class="page">fixture script</a>, <a href="../../../refguide/2.0.0-M5/applib/index/spec/Specification.html" class="page">specification</a> etc).
This is key enabler to place functionality in the "right place", eg in a domain entity/view model itself, or in a mixin.</p>
</div>
<div class="paragraph">
<p>There are three ways in which to inject the domain services:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>constructor injection (further discussion in the Spring documentation, <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-constructor-injection">here</a>)</p>
<div class="paragraph">
<p>This is recommended approach, but note that it is only supported for domain services, NOT for other domain object types.</p>
</div>
</li>
<li>
<p>setter injection (further discussion <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-setter-injection">here</a>)</p>
</li>
<li>
<p>field injection</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Whether you use setter or field injection for domain objects etc is a matter of style.
Generally field injection is somewhat frowned up.</p>
</div>
<div class="sect2">
<h3 id="constructor-injection"><a class="anchor" href="#constructor-injection"></a>Constructor Injection.</h3>
<div class="paragraph">
<p>As noted above, constructor injection is only available for domain services.
For example:</p>
</div>
<div class="listingblock">
<div class="title">CustomerRepository.java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.springframework.data.repository.Repository; <i class="conum" data-value="1"></i><b>(1)</b>
@Repository
public class CustomerRepository {
private final RepositoryService repositoryService;
public CustomerRepository(
final RepositoryService repositoryService) {
this.repositoryService = repositoryService;
}
// ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>indicates this is a repository service.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>If you wish, Project Lombok can be used to remove some of the boilerplate:</p>
</div>
<div class="listingblock">
<div class="title">CustomerRepository.java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.springframework.stereotype.Repository;
import lombok.RequiredArgsConstructor;
@Repository
@RequiredArgsConstructor(onConstructor_ = {@Inject} ) <i class="conum" data-value="1"></i><b>(1)</b>
public class CustomerRepository {
private final RepositoryService repositoryService;
// ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Generates a constructor for all <code>final</code> fields.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>If the layering between services is well defined, as in the above example (application <code>CustomerRepository</code> depends upon framework <code>RepositoryService</code>), then constructor injection should work out.</p>
</div>
<div class="paragraph">
<p>However, Spring does not support</p>
</div>
<div class="paragraph">
<p>TODO: Cyclic dependencies</p>
</div>
<div class="paragraph">
<p><a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-dependency-resolution">Dependency Resolution Process</a>, ("Circular dependencies" sidebar).</p>
</div>
<div class="paragraph">
<p>TODO: Provider&lt;&gt;</p>
</div>
</div>
<div class="sect2">
<h3 id="setter-and-field-injection"><a class="anchor" href="#setter-and-field-injection"></a>Setter and Field Injection</h3>
<div class="paragraph">
<p>Setter or field injection must be used all objects <em>other</em> than domain services.
For example, setter injection is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import javax.inject.Inject;
public class Customer {
...
OrderRepository orderRepository;
@Inject <i class="conum" data-value="1"></i><b>(1)</b>
public void setOrderRepository(orderRepository) {
this.orderRepository = orderRepository;
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>The framework injects the domain service into the entity, before any further interactions with it.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>It&#8217;s not necessary for the visibility to be <code>public</code>, so it should be as restrictive as possible.
In many cases, default visibility will work (assuming unit tests that mock the dependency are in the same package).</p>
</div>
<div class="paragraph">
<p>Some of the boilerplate can be removed using Project Lombok:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import javax.inject.Inject;
import lombok.Setter;
public class Customer {
...
@Setter(value= AccessLevel.PACKAGE, onMethod_ = {Inject.class}) <i class="conum" data-value="1"></i><b>(1)</b>
OrderRepository orderRepository;
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Generates a package-level setter, annotated with <code>@Inject</code></td>
</tr>
</table>
</div>
<div class="paragraph">
<p>If you want to use field injection, then this is simply:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import javax.inject.Inject;
public class Customer {
...
@Inject OrderRepository orderRepository;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>... and live with or disable any IDE warnings relating to field injection.</p>
</div>
<div class="paragraph">
<p>Using default visibility here still allows the field to be mocked out within unit tests (if placed in the same package as the code under test).</p>
</div>
</div>
<div class="sect2">
<h3 id="multiple-implementations"><a class="anchor" href="#multiple-implementations"></a>Multiple Implementations</h3>
<div class="paragraph">
<p>If there is more than one implementation of the service, then a specific implementation can be requested using either Spring&#8217;s <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Primary.html">@Primary</a> annotation (further discussion <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-autowired-annotation-primary">here</a>) or Spring&#8217;s <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Qualifier.html">Qualifier</a> annotation (further discussion <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-autowired-annotation-qualifiers">here</a>).</p>
</div>
<div class="paragraph">
<p>All of the domain services provided by Apache Isis' are annotated with <code>@Qualifier</code> to enable this.</p>
</div>
</div>
<div class="sect2">
<h3 id="injecting-lists-of-services"><a class="anchor" href="#injecting-lists-of-services"></a>Injecting Lists of Services</h3>
<div class="paragraph">
<p>It&#8217;s also possible to inject a list of services:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import javax.inject.Inject;
public class DocumentService {
...
@Inject
List&lt;PaperclipFactory&gt; paperclipFactories;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>These will be in the order as defined by the Spring <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/annotation/Order.html">@Order</a> annotation.</p>
</div>
<div class="paragraph">
<p>This pattern can be useful when implementing the <a href="https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern">chain of responsibility</a> design pattern, that is, looking for the first implementation that can handle a request.</p>
</div>
<div class="paragraph">
<p>It is also useful to "broadcast" or fan out an implementation.
For example, the framework defines the <a href="../../../refguide/2.0.0-M5/applib/index/services/publishing/spi/ExecutionSubscriber.html" class="page">ExecutionSubscriber</a> SPI, which is used to publish <a href="../../../refguide/2.0.0-M5/schema/ixn.html" class="page">Interaction Execution</a>s to external systems.
The framework provides a simple logging implementation, which will always be called.
All other implementations available will also be called.</p>
</div>
</div>
<div class="sect2">
<h3 id="injecting-isissessionscoped-services"><a class="anchor" href="#injecting-isissessionscoped-services"></a>Injecting `IsisSessionScope`d services</h3>
<div class="paragraph">
<p>Most domain services are application-scoped, in other words they are stateless global singletons that are shared by all concurrent requests.</p>
</div>
<div class="paragraph">
<p>A small number of framework-provided services are annotated using <a href="../../../refguide/2.0.0-M5/applib/index/annotation/InteractionScope.html" class="page">@IsisSessionScope</a>.
This means that they are stateful and scoped with each isis session, in other words HTTP request.
One such service is <a href="../../../refguide/2.0.0-M5/applib/index/services/queryresultscache/QueryResultsCache.html" class="page">QueryResultsCache</a>, used for performance caching.</p>
</div>
<div class="paragraph">
<p>These domain services must be requested using a slightly different idiom, using the <code>Provider</code> interface.
For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import javax.inject.Inject;
import javax.inject.Provider;
public class Customer {
...
@Inject OrderRepository orderRepository;
@Inject Provider&lt;QueryResultsCache&gt; queryResultsCacheProvider; <i class="conum" data-value="1"></i><b>(1)</b>
public List&lt;Order&gt; getOrders() {
Customer customer = this;
return queryResultsCacheProvider
.get() <i class="conum" data-value="2"></i><b>(2)</b>
.execute(
() -&gt; orderRepository.findByCustomer(customer),
Customer.class, "getOrders",
customer)
);
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>inject a <code>Provider</code> for the service, not directly</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Get the cache from the provider</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>If you accidentally inject the service directly (without being wrapped in <code>Provider</code>), then the framework will detect this and fail-fast.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="object-management-crud"><a class="anchor" href="#object-management-crud"></a>Object Management (CRUD)</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This chapter shows the idioms for creating, reading, updating and deleting <a href="overview.html#domain-entities" class="page">domain entities</a>.
The main domain services used for this are <a href="../../../refguide/2.0.0-M5/applib/index/services/repository/RepositoryService.html" class="page">RepositoryService</a> and <a href="../../../refguide/2.0.0-M5/applib/index/services/factory/FactoryService.html" class="page">FactoryService</a>.</p>
</div>
<div class="sect2">
<h3 id="instantiating"><a class="anchor" href="#instantiating"></a>Instantiating</h3>
<div class="paragraph">
<p>Domain entities can be instantiated using the <a href="../../../refguide/2.0.0-M5/applib/index/services/factory/FactoryService.html" class="page">FactoryService</a> provided by the framework.
For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">Customer customer = factoryService.detachedEntity(Customer.class);</code></pre>
</div>
</div>
<div class="paragraph">
<p>The returned domain entity is not persistent and is unknown to the ORM; hence "detached".</p>
</div>
<div class="paragraph">
<p>When the framework instantiates the object, all services are injected into the framework, and an <code>ObjectCreatedEvent</code> <a href="overview.html#lifecycle-events" class="page">lifecycle event</a> will also be emitted.</p>
</div>
<div class="paragraph">
<p>You may prefer however for your domain entities to have regular constructor defining their minimum set of mandatory properties.
For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public class Customer {
public Customer(String reference, String firstName, String lastName) {
// ...
}
// ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>In such cases, the domain object cannot be instantiated using <a href="../../../refguide/2.0.0-M5/applib/index/services/factory/FactoryService.html" class="page">FactoryService</a>.
Instead the <a href="../../../refguide/2.0.0-M5/applib/index/services/inject/ServiceInjector.html" class="page">ServiceInjector</a> service can be used to inject services:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">Customer customer = new Customer(reference, firstName, lastName);
factoryService.detachedEntity(customer);</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you prefer, this can be performed in one step:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">Customer customer = factoryService.detachedEntity(
new Customer(reference, firstName, lastName));</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note though that this does <em>not</em> raise any lifecycle event.</p>
</div>
</div>
<div class="sect2">
<h3 id="persisting"><a class="anchor" href="#persisting"></a>Persisting</h3>
<div class="paragraph">
<p>Once a domain entity has been instantiated and initialized, it can be persisted using the <a href="../../../refguide/2.0.0-M5/applib/index/services/repository/RepositoryService.html" class="page">RepositoryService</a>.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">Customer customer = ...
repositoryService.persist(customer);</code></pre>
</div>
</div>
<div class="paragraph">
<p>If using the no-arg form to instantiate the entity, then (to save having to inject the <code>FactoryService</code> as well), the <code>RepositoryService</code> can also be used to instantiate.
This gives rise to this common idiom:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">Customer customer = repositoryService.instantiate(Customer.class);
customer.setReference(reference);
customer.setFirstName(firstName);
customer.setLastName(lastName);
...
repositoryService.persist(customer);</code></pre>
</div>
</div>
<div class="paragraph">
<p>On the other hand, there is often little need to inject services into the domain entity between its instantiation and persistence.
If the domain entity has an N-arg constructor, then the code is often simpler:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">Customer customer = repositoryService.persist(new Customer(reference, name, lastname));</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that the <code>persist()</code> returns the object passed to it.</p>
</div>
<div class="sect3">
<h4 id="eager-persistence"><a class="anchor" href="#eager-persistence"></a>Eager Persistence</h4>
<div class="paragraph">
<p>It&#8217;s worth being aware that the framework does <em>not</em> eagerly persist the object.
Rather, it queues up an internal command structure representing the object persistence request.
This is then executed either at the end of the transaction, or if a <a href="#finding">query is run</a>, or if the internal queue is manually flushed using <a href="../../../refguide/2.0.0-M5/applib/index/services/xactn/TransactionService.html" class="page">TransactionService</a>'s <code>flush()</code> method.
Flushing also happens when a repository query is executed, so that the pending persist operation is performed first.
Generally therefore the lazy persistence approach works well enough.</p>
</div>
<div class="paragraph">
<p>Nevertheless, if you want to ensure that the persist command is flushed immediately, you can use:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">repositoryService.persistAndFlush(customer);</code></pre>
</div>
</div>
<div class="paragraph">
<p>When an object is persisted the framework will emit <code>ObjectPersistingEvent</code> and <code>ObjectPersistedEvent</code> <a href="overview.html#lifecycle-events" class="page">lifecycle events</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="persistence-by-reachability-jdo"><a class="anchor" href="#persistence-by-reachability-jdo"></a>Persistence by Reachability (JDO)</h4>
<div class="paragraph">
<p>If using <a href="../../../pjdo/2.0.0-M5/about.html" class="page">JDO/DataNucleus</a>, it is possible to configure ORM to automatically persist domain entities if they are associated with other already-persistent entities.
This avoid the need to explicitly call "persist".</p>
</div>
<div class="paragraph">
<p>This is done using <a href="#refguide:config:sections/jdo-datanucleus-conf.adoc#datanucleus.persistenceByReachabilityAtCommit" class="page unresolved">persistence-by-reachability</a> configuration property:</p>
</div>
<div class="listingblock">
<div class="title">application.properties</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-ini hljs" data-lang="ini">datanucleus.persistenceByReachabilityAtCommit=true</code></pre>
</div>
</div>
<div class="paragraph">
<p>One downside is that the code is arguably less easy to debug, and there may be performance implications.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="finding"><a class="anchor" href="#finding"></a>Finding Objects</h3>
<div class="paragraph">
<p>Retrieving domain entities depends on the ORM, though the <a href="../../../refguide/2.0.0-M5/applib/index/services/repository/RepositoryService.html" class="page">RepositoryService</a> can be used as an abstraction over either if required.</p>
</div>
<div class="sect3">
<h4 id="finding-jpa"><a class="anchor" href="#finding-jpa"></a>Finding Objects (JPA)</h4>
<div class="paragraph">
<p>The easiest way to retrieve domain entities if using JPA is to leverage the capabilities of Spring Data.</p>
</div>
<div class="paragraph">
<p>For example, simply by declaring this interface:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public interface UserRepository extends Repository&lt;User, Long&gt; {
List&lt;User&gt; findByEmailAddressAndLastname(String emailAddress, String lastname);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>and Spring Data will create an implementation based on naming conventions.
See the <a href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#reference">Spring Data</a> documentation for further details.</p>
</div>
<div class="paragraph">
<p>It is also possible to declare JPQL queries , either on the repository method (using <code>javax.persistence.Query</code>) or on the entity (using <code>javax.persistence.NamedQuery</code>).</p>
</div>
<div class="paragraph">
<p>On the entity, declare a named query, eg:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@javax.persistence.Entity
@javax.persistence.NamedQueries({
@javax.persistence.NamedQuery( <i class="conum" data-value="1"></i><b>(1)</b>
name = "Customer.findByNameLike", <i class="conum" data-value="2"></i><b>(2)</b>
query = "SELECT c " + <i class="conum" data-value="3"></i><b>(3)</b>
"FROM Customer c " + <i class="conum" data-value="4"></i><b>(4)</b>
"WHERE c.name LIKE :name" <i class="conum" data-value="5"></i><b>(5)</b>
)
})
...
public class Customer {
// ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>There may be several <code>@NamedQuery</code> annotations, nested within a <code>@NamedQueries</code> annotation, defining queries using JPQL.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Defines the name of the query.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>The definition of the query, using JPQL syntax.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>The table name</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>The predicate, expressed using SQL syntax.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>and in the corresponding repository, use <a href="../../../refguide/2.0.0-M5/applib/index/services/repository/RepositoryService.html" class="page">RepositoryService</a>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.springframework.stereotype.Repository;
import lombok.RequiredArgsConstructor;
@Repository
@RequiredArgsConstructor(onConstructor_ = {@Inject} )
public class CustomerRepository {
private final RepositoryService repositoryService;
public List&lt;Customer&gt; findByName(String name) {
return repositoryService.allMatches( <i class="conum" data-value="1"></i><b>(1)</b>
Query.named(Customer.class, "Customer.findByNameLike") <i class="conum" data-value="2"></i><b>(2)</b>
.withParameter("name", "%" + name + "%"); <i class="conum" data-value="3"></i><b>(3)</b>
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>The <a href="../../../refguide/2.0.0-M5/applib/index/services/repository/RepositoryService.html" class="page">RepositoryService</a> is a generic facade over the ORM API.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Specifies the class that is annotated with @NamedQuery, along with the <code>@NamedQuery#name</code> attribute</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>The <code>:name</code> parameter in the query JPQL string, and its corresponding value</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="finding-jdo"><a class="anchor" href="#finding-jdo"></a>Finding Objects (JDO)</h4>
<div class="paragraph">
<p>In the case of <a href="../../../pjdo/2.0.0-M5/about.html" class="page">JDO/DataNucleus</a>, it typically requires a JDOQL query defined on the domain entity, and a corresponding repository service for that domain entity type.
This repository calls the framework-provided <a href="../../../refguide/2.0.0-M5/applib/index/services/repository/RepositoryService.html" class="page">RepositoryService</a> to actually submit the query.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@javax.jdo.annotations.PersistenceCapable
@javax.jdo.annotations.Queries({
@javax.jdo.annotations.Query( <i class="conum" data-value="1"></i><b>(1)</b>
name = "findByName", <i class="conum" data-value="2"></i><b>(2)</b>
value = "SELECT " <i class="conum" data-value="3"></i><b>(3)</b>
+ "FROM com.mydomain.myapp.Customer " <i class="conum" data-value="4"></i><b>(4)</b>
+ "WHERE name.indexOf(:name) &gt;= 0 ") <i class="conum" data-value="5"></i><b>(5)</b>
})
...
public class Customer {
// ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>There may be several <code>@Query</code> annotations, nested within a <code>@Queries</code> annotation, defining queries using JDOQL.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Defines the name of the query.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>The definition of the query, using JDOQL syntax.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>The fully-qualified class name.
Must correspond to the class on which the annotation is defined (the framework checks this automatically on bootstrapping).</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>The predicate, expressed using Java syntax.
In this particular query, is an implementation of a LIKE "name%" query.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>and in the corresponding repository, use <a href="../../../refguide/2.0.0-M5/applib/index/services/repository/RepositoryService.html" class="page">RepositoryService</a>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.springframework.stereotype.Repository;
import lombok.RequiredArgsConstructor;
@Repository
@RequiredArgsConstructor(onConstructor_ = {@Inject} )
public class CustomerRepository {
private final RepositoryService repositoryService;
public List&lt;Customer&gt; findByName(String name) {
return repositoryService.allMatches( <i class="conum" data-value="1"></i><b>(1)</b>
Query.named(Customer.class, "findByName") <i class="conum" data-value="2"></i><b>(2)</b>
.withParameter("name", name); <i class="conum" data-value="3"></i><b>(3)</b>
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>The <a href="../../../refguide/2.0.0-M5/applib/index/services/repository/RepositoryService.html" class="page">RepositoryService</a> is a generic facade over the ORM API.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Specifies the class that is annotated with @Query, along with the <code>@Query#name</code> attribute</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>The <code>:name</code> parameter in the query JDOQL string, and its corresponding value</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Whenever a query is submitted, the framework will automatically "flush" any pending changes.
This ensures that the database query runs against an up-to-date table so that all matching instances (with respect to the current transaction) are correctly retrieved.</p>
</div>
<div class="paragraph">
<p>When an object is loaded from the database the framework will emit <code>ObjectLoadedEvent</code> <a href="overview.html#lifecycle-events" class="page">lifecycle event</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="type-safe-queries"><a class="anchor" href="#type-safe-queries"></a>Type-safe queries</h4>
<div class="paragraph">
<p>DataNucleus also supports type-safe queries; these can be executed using the <a href="../../../refguide/2.0.0-M5/persistence/index/jdo/applib/services/JdoSupportService.html" class="page">JdoSupportService</a> (JDO-specific) domain service.</p>
</div>
<div class="paragraph">
<p>See <a href="../../../refguide/2.0.0-M5/persistence/index/jdo/applib/services/JdoSupportService.html#type-safe-jdoql-queries" class="page">JdoSupportService</a> for further details.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="updating"><a class="anchor" href="#updating"></a>Updating Objects</h3>
<div class="paragraph">
<p>There is no specific API to update a domain entity.
Rather, the ORM (DataNucleus) automatically keeps track of the state of each object and will update the corresponding database rows when the transaction completes.</p>
</div>
<div class="paragraph">
<p>That said, it is possible to "flush" pending changes:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="../../../refguide/2.0.0-M5/applib/index/services/xactn/TransactionService.html" class="page">TransactionService</a> acts at the Apache Isis layer, and flushes any pending object persistence or object deletions</p>
</li>
<li>
<p>(if using <a href="../../../pjdo/2.0.0-M5/about.html" class="page">JDO/DataNucleus</a>), the <a href="../../../refguide/2.0.0-M5/persistence/index/jdo/applib/services/JdoSupportService.html" class="page">JdoSupportService</a> domain service can be used reach down to the underlying JDO API, and perform a flush of pending object updates also.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>When an object is updated the framework will emit <code>ObjectUpdatingEvent</code> and <code>ObjectUpdatedEvent</code> <a href="overview.html#lifecycle-events" class="page">lifecycle events</a>.</p>
</div>
</div>
<div class="sect2">
<h3 id="deleting"><a class="anchor" href="#deleting"></a>Deleting Objects</h3>
<div class="paragraph">
<p>Domain entities can be deleted using <a href="../../../refguide/2.0.0-M5/applib/index/services/repository/RepositoryService.html" class="page">RepositoryService</a>.
For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">Customer customer = ...
repositoryService.remove(customer);</code></pre>
</div>
</div>
<div class="paragraph">
<p>It&#8217;s worth being aware that (as for persisting new entities) the framework does <em>not</em> eagerly delete the object.
Rather, it queues up an internal command structure representing the object deletion request.
This is then executed either at the end of the transaction, or if a <a href="#finding">query is run</a>, or if the internal queue is manually flushed using <a href="../../../refguide/2.0.0-M5/applib/index/services/xactn/TransactionService.html" class="page">TransactionService</a>'s <code>flush()</code> method.</p>
</div>
<div class="paragraph">
<p>Alternatively, you can use:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">repositoryService.removeAndFlush(customer);</code></pre>
</div>
</div>
<div class="paragraph">
<p>to eagerly perform the object deletion from the database.</p>
</div>
<div class="paragraph">
<p>When an object is deleted the framework will emit <code>ObjectRemovingEvent</code> <a href="overview.html#lifecycle-events" class="page">lifecycle event</a>.</p>
</div>
</div>
</div>
</div>
</article>
<aside class="article-aside toc hide-for-print" 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~2021 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: 2.0.0-M5.20210409-1206</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>
<script src="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js"></script>
<script>
function focusSearchInput () { document.querySelector('#algolia-search-input').focus() }
var search = docsearch({
appId: '5ISP5TFAEN',
apiKey: '0fc51c28b4ad46e7318e96d4e97fab7c',
indexName: 'isis-apache-org',
inputSelector: '#algolia-search-input',
autocompleteOptions: { hint: false, keyboardShortcuts: ['s'] },
debug: false,
}).autocomplete
search.on('autocomplete:closed', function () { search.autocomplete.setVal() })
focusSearchInput()
window.addEventListener('load', focusSearchInput);
</script>
<!--
docsearch options:
https://docsearch.algolia.com/docs/behavior/
-->
<!--
https://www.algolia.com/doc/api-reference/api-parameters/
algoliaOptions: { hitsPerPage: 6 },
-->
</body>
</html>