Java API

Last modified by Vincent Massol on 2026/09/10 21:24

Reference

Release Notes Application 2.7+ Three Component roles in org.xwiki.contrib.releasenotes create, read and search release notes and changes from Java, so an extension does not have to know which xobject holds what. They are the same components the Script Service and the REST API call.

<dependency>
  <groupId>org.xwiki.contrib.releasenotes</groupId>
  <artifactId>application-releasenotes-api</artifactId>
  <version>2.7</version>
</dependency>

ReleaseNoteManager

MethodReturnsDescription
createReleaseNote(note)DocumentReferenceCreates the release note from its template and returns its page. Throws ReleaseNoteAlreadyExistsException when that version of that product already has one.
updateReleaseNote(note)ReleaseNoteRelease Notes Application 2.8+ Replaces the release note that product and version locate, and returns it as stored. Only date and released are written, and a value the passed note leaves out is emptied rather than kept.
getReleaseNoteReference(product, version)DocumentReferenceThe page a release note has, or would have, whether or not it exists.
getReleaseNote(reference)ReleaseNoteReads a release note back. Throws ReleaseNotesNotFoundException when the page carries none.
getReleaseNotes(product)List<ReleaseNote>Every release note of a product, or of every product when product is null.
getAggregatedVersions(noteReference)List<String>The versions a note covers: its own, plus its milestones and release candidates when it is a final version.

ChangeManager

MethodReturnsDescription
createChange(change)DocumentReferenceAllocates the next Entry001 page of the release note, writes both objects and saves once.
reserveNextEntry(product, version)DocumentReferenceAllocates and saves that page empty, for a caller that then opens it in the editor: the edit action applies the change template to a page with no content, so the objects are created once, by the template. This is what the "Add Change" buttons use.
updateChange(reference, change)ChangeRelease Notes Application 2.8+ Replaces the change that page holds and returns it as stored. Every property is written, so one the passed change leaves out is emptied; product and version are not, since they are the release note it belongs to.
getChange(reference)ChangeReads a change back. Throws ReleaseNotesNotFoundException when the page carries none.
search(query)ChangeSearchResultRuns a ChangeQuery and reports the pages found, their compact references and whether a further page exists.

ReleaseNotesConfiguration

MethodReturnsDescription
getDefaultProduct()StringThe product new release notes get when the caller names none.
getDefaultTemplate()DocumentReferenceThe template new release notes start from when the caller names none.

Model

TypeHolds
ReleaseNoteproduct, version, date (Date), released (boolean), template (DocumentReference).
Changeproduct, version, title, summary, description, audience, importance, category, screenshots (List<String>). It is both the write input and the read output, and carries no reference of its own: the reference is what createChange returns and what getChange takes.
AudienceUSER, ADMINISTRATOR, DEVELOPER.
ImportanceLOW, MEDIUM, HIGH, stored as 0, 1 and 2.
ChangeQueryA List<ChangeFilter> per filtered field, plus limit (100 by default) and offset. A ChangeFilter is an Operator, one of LIKE, EQUALS, LT, LTE, GT or GTE, and a value.
ChangeSearchResultgetChanges(), getChangeNames() and hasMore().

A ChangeQuery is built field by field, or parsed from the lenient comma-separated strings the macros and the REST resources take, with ChangeQueryParser:

@Inject
private ChangeManager changeManager;

@Inject
private ChangeQueryParser queryParser;

public List<DocumentReference> highImportanceUserChanges(String version) throws ReleaseNotesException
{
    ChangeQuery query = this.queryParser.parse(Map.of(
        "products", "MyProduct", "versions", version, "audience", "user", "importance", ">=medium"));
    return this.changeManager.search(query).getChanges();
}

Writing a change is typed, so an invalid value fails at the call rather than in the database, while querying keeps the wildcards and the operator prefixes of the filter language:

Change change = new Change();
change.setProduct("MyProduct");
change.setVersion("3.0-milestone-1");
change.setTitle("Live Data replaces the Live Table");
change.setAudience(Audience.USER);
change.setImportance(Importance.HIGH);
DocumentReference created = this.changeManager.createChange(change);

Rights and errors

Every write checks edit right on the page it is about to create, for the context user and for the context author, inside the component. A caller cannot skip that check by going through Java rather than through a script, and a component reached from a script service must not assume its own author's rights are enough. A refusal is a ReleaseNotesAccessDeniedException.

Everything that can fail throws ReleaseNotesException, a checked exception; ReleaseNoteAlreadyExistsException, ReleaseNotesAccessDeniedException and ReleaseNotesNotFoundException extend it and carry the page concerned.

The whole surface is @Unstable, so it may still change from one release to the next.

FAQ

Is the change search rights-filtered?

No. search reports every change matching the query, which is what the release notes and the reports themselves display.

Why is there no method to delete a change?

Deleting needs no name allocated and no template applied, so it stays an ordinary document write. Replacing one does not: updateChange exists because a caller that only set the ChangeClass properties itself would have to know which of them a change is made of.

Which module do I depend on?

application-releasenotes-api. The XAR of the application already brings it, so an extension only needs it at compile time.

Related

Get Connected