Skip to content

Commit 876e319

Browse files
rwinchgregturn
authored andcommitted
Implement Antora-based reference docs.
See #2876
1 parent c4c959b commit 876e319

40 files changed

+3856
-3
lines changed

.github/workflows/deploy-docs.yml

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Deploy Docs
2+
on:
3+
push:
4+
branches-ignore: [ gh-pages ]
5+
tags: '**'
6+
repository_dispatch:
7+
types: request-build-reference # legacy
8+
#schedule:
9+
#- cron: '0 10 * * *' # Once per day at 10am UTC
10+
workflow_dispatch:
11+
permissions:
12+
actions: write
13+
jobs:
14+
build:
15+
runs-on: ubuntu-latest
16+
# FIXME enable when pushed to spring-projects
17+
# if: github.repository_owner == 'spring-projects'
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v3
21+
with:
22+
ref: docs-build
23+
fetch-depth: 1
24+
- name: Dispatch (partial build)
25+
if: github.ref_type == 'branch'
26+
env:
27+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28+
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }}
29+
- name: Dispatch (full build)
30+
if: github.ref_type == 'tag'
31+
env:
32+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33+
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD)

.gitignore

+5-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@ src/ant/.ant-targets-upload-dist.xml
1414
*.ipr
1515
*.iws
1616
/.idea/
17-
*.graphml
17+
*.graphml
18+
node
19+
node_modules
20+
package-lock.json
21+
package.json

antora-playbook.yml

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# PACKAGES [email protected] @antora/atlas-extension:1.0.0-alpha.1 @antora/[email protected] @springio/[email protected] @asciidoctor/[email protected] @opendevise/[email protected]
2+
#
3+
# The purpose of this Antora playbook is to build the docs in the current branch.
4+
antora:
5+
extensions:
6+
- '@antora/collector-extension'
7+
- require: '@springio/antora-extensions/root-component-extension'
8+
root_component_name: 'data-commons'
9+
site:
10+
title: Spring Data Reference
11+
url: https://https://rwinch.github.io/spring-data-commons/
12+
content:
13+
sources:
14+
- url: .
15+
branches: HEAD
16+
start_path: .
17+
worktrees: true
18+
asciidoc:
19+
attributes:
20+
page-pagination: ''
21+
hide-uri-scheme: '@'
22+
tabs-sync-option: '@'
23+
chomp: 'all'
24+
extensions:
25+
- '@asciidoctor/tabs'
26+
- '@springio/asciidoctor-extensions'
27+
sourcemap: true
28+
urls:
29+
latest_version_segment: ''
30+
runtime:
31+
log:
32+
failure_level: warn
33+
format: pretty
34+
ui:
35+
bundle:
36+
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.3.0/ui-bundle.zip
37+
snapshot: true

antora.yml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: data-commons
2+
version: true
3+
title: Spring Data Commons
4+
nav:
5+
- modules/ROOT/nav.adoc
6+
ext:
7+
collector:
8+
- run:
9+
command: mvnw resources:resources
10+
local: true
11+
scan:
12+
dir: ./target/classes/antora-resources
58.3 KB
Loading
+11
Loading

modules/ROOT/nav.adoc

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
* xref:index.adoc[Overview]
2+
* xref:dependencies.adoc[]
3+
* xref:upgrade.adoc[]
4+
* xref:object-mapping.adoc[]
5+
* xref:repositories.adoc[]
6+
** xref:repositories/core-concepts.adoc[]
7+
** xref:repositories/query-methods.adoc[]
8+
** xref:repositories/definition.adoc[]
9+
** xref:repositories/query-methods-details.adoc[]
10+
** xref:repositories/create-instances.adoc[]
11+
** xref:repositories/custom-implementations.adoc[]
12+
** xref:repositories/core-domain-events.adoc[]
13+
** xref:repositories/core-extensions.adoc[]
14+
* xref:repositories-scrolling.adoc[]
15+
* xref:repositories-null-handling.adoc[]
16+
* xref:repository-projections.adoc[]
17+
* xref:query-by-example.adoc[]
18+
* xref:auditing.adoc[]
19+
* xref:custom-conversions.adoc[]
20+
* xref:entity-callbacks.adoc[]
21+
* xref:is-new-state-detection.adoc[]
22+
* xref:kotlin.adoc[]
23+
** xref:kotlin/requirements.adoc[]
24+
** xref:kotlin/null-safety.adoc[]
25+
** xref:kotlin/object-mapping.adoc[]
26+
** xref:kotlin/extensions.adoc[]
27+
** xref:kotlin/coroutines.adoc[]
28+
* Appendices
29+
** xref:repository-namespace-reference.adoc[]
30+
** xref:repository-populator-namespace-reference.adoc[]
31+
** xref:repository-query-keywords-reference.adoc[]
32+
** xref:repository-query-return-types-reference.adoc[]

modules/ROOT/pages/auditing.adoc

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
[[auditing]]
2+
= Auditing
3+
4+
[[auditing.basics]]
5+
== Basics
6+
Spring Data provides sophisticated support to transparently keep track of who created or changed an entity and when the change happened.To benefit from that functionality, you have to equip your entity classes with auditing metadata that can be defined either using annotations or by implementing an interface.
7+
Additionally, auditing has to be enabled either through Annotation configuration or XML configuration to register the required infrastructure components.
8+
Please refer to the store-specific section for configuration samples.
9+
10+
[NOTE]
11+
====
12+
Applications that only track creation and modification dates are not required do make their entities implement xref:auditing.adoc#auditing.auditor-aware[`AuditorAware`].
13+
====
14+
15+
[[auditing.annotations]]
16+
=== Annotation-based Auditing Metadata
17+
We provide `@CreatedBy` and `@LastModifiedBy` to capture the user who created or modified the entity as well as `@CreatedDate` and `@LastModifiedDate` to capture when the change happened.
18+
19+
.An audited entity
20+
[source,java]
21+
----
22+
class Customer {
23+
24+
@CreatedBy
25+
private User user;
26+
27+
@CreatedDate
28+
private Instant createdDate;
29+
30+
// … further properties omitted
31+
}
32+
----
33+
34+
As you can see, the annotations can be applied selectively, depending on which information you want to capture.
35+
The annotations, indicating to capture when changes are made, can be used on properties of type JDK8 date and time types, `long`, `Long`, and legacy Java `Date` and `Calendar`.
36+
37+
Auditing metadata does not necessarily need to live in the root level entity but can be added to an embedded one (depending on the actual store in use), as shown in the snippet below.
38+
39+
.Audit metadata in embedded entity
40+
[source,java]
41+
----
42+
class Customer {
43+
44+
private AuditMetadata auditingMetadata;
45+
46+
// … further properties omitted
47+
}
48+
49+
class AuditMetadata {
50+
51+
@CreatedBy
52+
private User user;
53+
54+
@CreatedDate
55+
private Instant createdDate;
56+
57+
}
58+
----
59+
60+
[[auditing.interfaces]]
61+
=== Interface-based Auditing Metadata
62+
In case you do not want to use annotations to define auditing metadata, you can let your domain class implement the `Auditable` interface. It exposes setter methods for all of the auditing properties.
63+
64+
[[auditing.auditor-aware]]
65+
=== `AuditorAware`
66+
67+
In case you use either `@CreatedBy` or `@LastModifiedBy`, the auditing infrastructure somehow needs to become aware of the current principal. To do so, we provide an `AuditorAware<T>` SPI interface that you have to implement to tell the infrastructure who the current user or system interacting with the application is. The generic type `T` defines what type the properties annotated with `@CreatedBy` or `@LastModifiedBy` have to be.
68+
69+
The following example shows an implementation of the interface that uses Spring Security's `Authentication` object:
70+
71+
.Implementation of `AuditorAware` based on Spring Security
72+
[source, java]
73+
----
74+
class SpringSecurityAuditorAware implements AuditorAware<User> {
75+
76+
@Override
77+
public Optional<User> getCurrentAuditor() {
78+
79+
return Optional.ofNullable(SecurityContextHolder.getContext())
80+
.map(SecurityContext::getAuthentication)
81+
.filter(Authentication::isAuthenticated)
82+
.map(Authentication::getPrincipal)
83+
.map(User.class::cast);
84+
}
85+
}
86+
----
87+
88+
The implementation accesses the `Authentication` object provided by Spring Security and looks up the custom `UserDetails` instance that you have created in your `UserDetailsService` implementation. We assume here that you are exposing the domain user through the `UserDetails` implementation but that, based on the `Authentication` found, you could also look it up from anywhere.
89+
90+
[[auditing.reactive-auditor-aware]]
91+
=== `ReactiveAuditorAware`
92+
93+
When using reactive infrastructure you might want to make use of contextual information to provide `@CreatedBy` or `@LastModifiedBy` information.
94+
We provide an `ReactiveAuditorAware<T>` SPI interface that you have to implement to tell the infrastructure who the current user or system interacting with the application is. The generic type `T` defines what type the properties annotated with `@CreatedBy` or `@LastModifiedBy` have to be.
95+
96+
The following example shows an implementation of the interface that uses reactive Spring Security's `Authentication` object:
97+
98+
.Implementation of `ReactiveAuditorAware` based on Spring Security
99+
[source, java]
100+
----
101+
class SpringSecurityAuditorAware implements ReactiveAuditorAware<User> {
102+
103+
@Override
104+
public Mono<User> getCurrentAuditor() {
105+
106+
return ReactiveSecurityContextHolder.getContext()
107+
.map(SecurityContext::getAuthentication)
108+
.filter(Authentication::isAuthenticated)
109+
.map(Authentication::getPrincipal)
110+
.map(User.class::cast);
111+
}
112+
}
113+
----
114+
115+
The implementation accesses the `Authentication` object provided by Spring Security and looks up the custom `UserDetails` instance that you have created in your `UserDetailsService` implementation. We assume here that you are exposing the domain user through the `UserDetails` implementation but that, based on the `Authentication` found, you could also look it up from anywhere.

0 commit comments

Comments
 (0)