Get spaces by keys with the Confluence API

Audience

This article is for users of the Confluence Java API in ScriptRunner or other places the Java API may be used.  The article does not apply to the REST API.

User Macros

Sorry, but I am still at a loss as to how to get a space object in Velocity in a User Macro.  If you know, please share in a comment.

Overview

Atlassian has deprecated the spaceManager.getSpace(), spaceManager.getSpaces(), and other similar space object instatiators (yes, that's now a word because I said so).

Since it took piecing together multiple Community answers and a lot of trial and error, I thought I'd write this article to share so that others don't have to go through as much trouble as I did just to get a space object now.

Note: if there's an easier way to do this, I'm all for it.  Please let me know in a comment.

The code

Get the SpaceService

To make it cleaner, I'll show you the two ways to get the SpaceService, then use one of them in the examples.  They're about the same.

import com.onresolve.scriptrunner.runner.ScriptRunnerImpl

SpaceService spaceService = ScriptRunnerImpl.getPluginComponent(SpaceService)
import com.onresolve.scriptrunner.runner.customisers.PluginModule

@PluginModule
SpaceService spaceService

Get one space by a key

import com.atlassian.confluence.api.model.content.Space
// this is different from com.atlassian.confluence.spaces.Space
import com.atlassian.confluence.api.model.Expansion
import com.atlassian.confluence.api.service.content.SpaceService
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.ScriptRunnerImpl

// get SpaceService to use to find spaces
SpaceService spaceService = ScriptRunnerImpl.getPluginComponent(SpaceService)

// put the space key you're searching for here, or directly where the variable is used
String spaceKey = "ABC"

// here's the tricky part, just go with it
Space
 space = spaceService.find(new Expansion('name'))
      .withKeys(spaceKey)
      .fetch()
      .get()

// just in case no spaces are found with the keys provided
if
 (!space) {return "No space found."}

// get the space info needed
return
"<p>${space.getKey()}${space.getName()}</p>"

Get multiple spaces by keys

import com.atlassian.confluence.api.model.content.Space
// this is different from com.atlassian.confluence.spaces.Space
import com.atlassian.confluence.api.model.Expansion
import com.atlassian.confluence.api.model.pagination.SimplePageRequest
import com.atlassian.confluence.api.model.pagination.PageResponse
import com.atlassian.confluence.api.service.content.SpaceService

import com.onresolve.scriptrunner.runner.ScriptRunnerImpl

SpaceService spaceService = ScriptRunnerImpl.getPluginComponent(SpaceService)

// declare result variable
String
 result = ""                                                                  

// here's the tricky part, just go with it
PageResponse<Space> spaceResponse = spaceService.find(new Expansion('name'))
      .withKeys("ABC","TEST") // put the space keys you're searching for here
      .fetchMany(new SimplePageRequest(010)) // paginate and tell it how many results you want back

// just in case no spaces are found with the keys provided
if
 (!spaceResponse) {return "No spaces found."}

// now turn the response into a list of spaces (why oh why so many steps?)
List<Space>
 spaces = spaceResponse.getResults()

// loop through the list of spaces
spaces.each { 
space ->
// get the space info needed
    result += 
"<p>${space.getKey()}${space.getName()}</p>"
}

return result

Conclusion

There you have it. From spaceManager.getSpace() to all that mess above. There must be some underlying reason for it, but I'm not privy to it.

I'll probably create a method to call that's like .getSpace() to make it easier on me. If I do, I'll try to remember to post it here or in a new article.

Update: See Get spaces by keys with the Confluence API Part 2

If this article makes your life a little easier, I'd appreciate a Like from you.

About the author

This article was written by little ol' me.  So please don't complain to Atlassian or Adaptavist for any mistakes I may have made. Feel free to complain about the complexity of the deprecation replacement to Atlassian, though.

I'll try to answer any questions that come up, but I may win the lottery one day, if I ever decide to play it.

9 comments

Dominic Lagger
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
February 9, 2022

Hi @WW 

Thanks for this article. 

In which version the spaceManager is depricated? I would say, that although it has been depricated, you can use it till february... 

My velocity approach uses the SpaceManager, so I'm not sure if this works for newer version, but in version 7.13.x it works still fine :) 

#set( $spaceManager = $action.getSpaceManager())
#set( $actualSpace = $spaceManager.getSpace($space.key))

<a href='$actualSpace.getUrlPath()'>$actualSpace.getName()</a>

Regards, Dominic

Like Rafael Corredor likes this
WW
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
February 10, 2022

Hi @Dominic Lagger ,

If you look at any of the latest API documentation, you'll see that SpaceManager.getSpace() was deprecated since 7.3.0.

I don't want to create new code with deprecated methods knowing that one day I'll have to go back and fix it.  I'd rather use the new methods and do it right the first time.

Sure, SpaceManager.getSpace() still works, but deprecated is a warning that means Atlassian could pull the plug at any time.  I don't want to scramble to figure out how to do what may take a while to figure out.  I'd rather figure it out while I have time, and implement it in any new code I write.

Like I said, I don't know how to use the new methods for Velocity User Macros, and sure, the old methods still work.  Those are all we can use until somebody figures out how to make the new methods work.

Dominic Lagger
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
February 10, 2022

I totally understand why you do want to avoid depricated methods... 

For me, it's okay, because I think, till 2024 they won't delete depricated stuff, because then it's end of life. After that, we have to find other solutions :) 

Penn June 15, 2022

Have you had any luck pulling spaces by their categories? With the deprecated methods I can eventually filter on categories and only affect the categories I want with my changes.

Additionally, I'm getting a max of 200 responses, even when I want more. I assume it's the same for you and everyone else? This may be hard coded somewhere?

WW
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
June 16, 2022

Search criteria

I haven't tried to pull by category with the new objects/classes. From the documentation, it looks like these are the available search criteria:

  • withHasRetentionPolicy
  • withIsFavourited
  • withKeys
  • withLabels
  • withStatus
  • withType

Max 200

Atlassian added the maximum results and pagination to these new classes so that no one overwhelms the system by requesting everything in a large instance. The Atlassian REST APIs have been that way, maybe always.

That's part of the change from the old objects/classes that were deprecated. You could use those to pull everything. If you had a huge instance on a puny server, though, it'd cause performance issues.

This part is where you'd specify start and limit (or if what you put goes over the limit, it'll max out at 200):

.fetchMany(new SimplePageRequest(010))

0 being the first pagination page/set of results

10 being the number of results to return

If you wanted to go beyond the  initial 200, you'd need to loop and paginate through each set of 200 results. You might be able to change that limit somewhere in the system, but I'm not sure where. Unless you really, really need to, though, I wouldn't mess with it.

Like Penn likes this
Erik Buchholz
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
November 8, 2022

Hi,

I found that the version with SpaceService gave me com.atlassian.confluence.api.model.content.Space while I needed com.atlassian.confluence.spaces.Space. So I used the alternative with SpaceManagerInternal and came up to the following solution.

import com.atlassian.confluence.internal.spaces.SpaceManagerInternal
import com.atlassian.confluence.core.ListBuilder
import com.atlassian.confluence.spaces.SpacesQuery
import com.atlassian.sal.api.component.ComponentLocator
import com.atlassian.confluence.spaces.Space

final SpaceManagerInternal spaceManager = ComponentLocator.getComponent(SpaceManagerInternal)
final ListBuilder<Space> foundSpaces = spaceManager.getSpaces(SpacesQuery.newQuery().withSpaceKey('SPACE-KEY').build())
if (foundSpaces.isEmpty() || foundSpaces.first().isEmpty()) {
// No space found
return
}
final Space space = foundSpaces.first().first()

Regards

WW
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
November 8, 2022

Much of SpaceManager has been deprecated including the ways to get a space object(s). Deprecated, but still available for use - until they get rid of them.

From what I understand, the classes that end in "Internal" are for Atlassian's use.

But if you were able to get it to work for you, then go for it!

Erik Buchholz
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
November 9, 2022

Hi @WW ,

you're right. I thought that would be a suitable solution as it's mentioned in the deprecation message. But now I found another way to get a com.atlassian.confluence.spaces.Space:

import com.atlassian.confluence.content.service.SpaceService

return ComponentLocator.getComponent(SpaceService)
.getKeySpaceLocator('ABC')
.getSpace()

Please note that this space service is a different one as

com.atlassian.confluence.api.service.content.SpaceService

which is the one you found and is mentioned in the deprecation message.

It also has only this one method. So if you want to find a space by another criteria as by key, you would need to use the other SpaceService and use getKey() of the found com.atlassian.confluence.api.model.content.Space to use this method.

Regards

WW
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
November 9, 2022

I wonder if com.atlassian.confluence.api.model.content.Space is the class made available through the REST API. Not sure.

Comment

Log in or Sign up to comment
TAGS
AUG Leaders

Atlassian Community Events