Broken Java API in Confluence 8 EAP: ContentSearch, getById(), etc

Hi All,

Replying to the above.

From the first block

Classes such as SiteSearchPermissionsSearchFilter have been removed, so we can’t apply user permissions when searching (which is a security breach awaiting to happen)

All the classes the implement the SearchFilter interface are still available in 7.20. They will only be removed in Confluence 8.0 as all SearchFilter will be replaced with SearchQuery. You should be able to find equivalent SearchQuery classes in Confluence 8.0. In the particular case of the SiteSearchPermissionsSearchFilter you can use the SiteSearchPermissionsQuery (available since 7.20) instead. Please refer to Searching using the v2 search API for examples

Last but not least, they change method signatures without notice!

** In 7.19: ContentSearch(SearchQuery query, SearchSort sort, SearchFilter searchFilter, int startOffset, int limit)

** In 7.20: ContentSearch(@NonNull SearchQuery query, SearchSort sort, int startOffset, int limit),

** The ‘searchFilter’ argument was simply removed, no deprecation, it’s a public API class, so we can’t write code for 7.20 which works in 7.19, and we can’t write code for 7.19 that works in 7.20.

The signature ContentSearch(SearchQuery query, SearchSort sort, SearchFilter searchFilter, int startOffset, int limit) was only deprecated since 7.20 and removed from 8.0. The interface SearchFilter and all of the classes that implement this interface was deprecated in 7.20 and removed from 8.0 in preparation for the future upgrade of Lucene library. This is required because as of Lucene 6 all of the Filter classes have been removed.

You can find additional information on our deprecated code paths removed in 8.0 page.

To your questions in the second block

How to perform a CQL search

CQL search can be done via CQLSearchService . You can find examples in the JavaDoc.

  • How to simply get a page by ID, a page version by ID and a space by key, and hopefully a page by title
  • How to modify the body of a page and save it as a new version (since getById() is deprecated, I suspect it is impossible)

Here are some example of the usage of ContentService:

Finding a page by page ID

contentService.find()
                .withStatus(ContentStatus.CURRENT)
                .withId(contentId)
                .fetch()
                .orElseThrow(notFound("No content found with id : " + contentId));

Finding a page by page version by ID

contentService.find(new Expansion("version"))
				.withIdAndVersion(page.getContentId(), page.getVersion())
				.fetchOrNull();

Note: in this example, we need to load “version” attribute in order to use withIdAndVersion
Finding a Space with Space key

spaceService.find()
                    .withKeys(spaceKey)
                    .fetch()

Finding a page by page title and Space

contentService.find(Expansions.of(VERSION, HISTORY, STATUS, SPACE).toArray()) // Load extra attributes: VERSION, HISTORY, STATUS, SPACE
                .withSpace(Space.build().key("SPACE_KEY"))
                .withTitle("Some page title")
                .withType(ContentType.PAGE) // This indicates which content type to be loaded: PAGE, BLOG_POST...
                .withStatus(CURRENT);

Update a Content’s body by ID

Content foundContent = contentService.find()
                .withStatus(ContentStatus.CURRENT)
                .withId(contentId)
                .fetch()
                .orElseThrow(notFound("No content found with id : " + contentId));
Content toBeUpdatedContent = Content.builder(foundContent)
	.body("new body", ContentRepresentation.STORAGE);
contentService.update(foundContent);

All of this using using genuine ContentEntityObject.java (Page, Blog, Comment, Space.java) and not a shell object like those returned by the search. If necessary, show us how to return shell objects into complete objects.

We’re attempting to remove dependancies on Hibernate objects. The ContentEntityObject is a Hibernate object. The service APIs expose similar capabilities, so we’d recommend using that API instead of depending on the ContentEntityObject previously used.

Hopefully this meets your exacting requirements.

Dutifully,
James Ponting
Engineering Manager - Confluence Data Center

5 Likes