Cannot use ContentService.find().withSpace() and ContentType.ATTACHMENT

It seems that the withSpace method of AbstractContentFinder does not set the contentContainerId. This results in a null value being passed to the AttachmentContentTypeApiSupport.getAttachments method which results in a NullPointerException when it tries to call the asLong() method on the null value.

I am using Confluence 7.0.1 so perhaps this has already been fixed?

[relevant stacktrace]

Cause
java.lang.NullPointerException
at com.atlassian.confluence.api.impl.service.content.typebinding.AttachmentContentTypeApiSupport.getAttachments(AttachmentContentTypeApiSupport.java:98)

java.lang.NullPointerException
at com.atlassian.confluence.api.impl.service.content.typebinding.AttachmentContentTypeApiSupport.getAttachments(AttachmentContentTypeApiSupport.java:98)
at com.atlassian.confluence.api.impl.service.content.finder.ContentFinderFactory$ContentFinderImpl.internalFetchAttachments(ContentFinderFactory.java:149)
at com.atlassian.confluence.api.impl.service.content.finder.ContentFinderFactory$ContentFinderImpl.fetchMany(ContentFinderFactory.java:134)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

I also have this exact problem on 7.11.0. Did you ever find a solution @robertegan305?

I cannot use the ContentService to find attachments using a simple query like this:

contentService.find(Expansions.of(CONTAINER).toArray()).withStatus(ContentStatus.CURRENT).fetchMany(ATTACHMENT, new SimplePageRequest(0, 200))

It always errors out with:

java.lang.NullPointerException
	at com.atlassian.confluence.api.impl.service.content.typebinding.AttachmentContentTypeApiSupport.getAttachments(AttachmentContentTypeApiSupport.java:98)
	at com.atlassian.confluence.api.impl.service.content.finder.ContentFinderFactory$ContentFinderImpl.internalFetchAttachments(ContentFinderFactory.java:148)
	at com.atlassian.confluence.api.impl.service.content.finder.ContentFinderFactory$ContentFinderImpl.fetchMany(ContentFinderFactory.java:133)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)

@jponting you wrote a post on how to use the ContentService, could you check whether this is a bug or not?

Hello hello,

From what I recall , ContentService and AttachmentService only allow you to look up attachments by content (which is a container).

However, I must admit that the service API gets a bit confusing because a space is also a container , the javadoc needs to be more explicit.

That said, to lookup attachments in a space, you can use the CQLSearchService as follow:

import com.atlassian.confluence.api.model.pagination.SimplePageRequest;
import com.atlassian.confluence.api.model.search.SearchOptions;
import com.atlassian.confluence.api.model.search.SearchPageResponse;
import com.atlassian.confluence.api.model.search.SearchResult;
import com.atlassian.confluence.api.service.search.CQLSearchService;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
import org.springframework.beans.factory.annotation.Autowired;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;

@Path("/attachment")
public class AttachmentResource {

    private final CQLSearchService searchService;

    @Autowired
    public AttachmentResource(
            @ComponentImport final CQLSearchService searchService
    ) {
        this.searchService = searchService;
    }

    @GET
    @Path("/by-space/{spaceKey}")
    @Produces("application/json")
    public Response getBySpace(@PathParam("spaceKey") final String spaceKey) {
        SearchPageResponse<SearchResult> result = searchService.search(
                "type=attachment AND space=" + spaceKey,
                SearchOptions.builder().build(),
                new SimplePageRequest(0, 20)
        );
        return Response.ok(result).build();
    }
}

So in a way, if the contentService / attachmentService / spaceService fall short for whatever reason, you can always rely on CQLSearchService; it obviously implies that indexing has gone through.

I tried this solution, and here are my thoughts:

  • For me, this isn’t a solution at all. How would it make sense that, for searching a page I use a service, for searching a space I use another service, and when I want to search for an attachment I have to use a generic CQL service, which BTW I can also use to find spaces, or pages, but only if a reindexing has been done (which, on my tests, wasn’t necessary, but is it never? sometimes yes, sometimes not?).

  • The CQL Service needs a user to be set via AuthenticatedUserThreadLocal. Getting the current user give null back. Yeah, knowing Atlassian there is probably another way of getting/setting the user.

Regards,
Ansgar