Creating a Java ReST API extension project - Creating a Java ReST API extension project - Alfresco - Alfresco Events SDK for Out-of-Process Events - Alfresco/Alfresco-Events-SDK-for-Out-of-Process-Events/6.3/Alfresco-Events-SDK-for-Out-of-Process-Events/Install/Creating-a-Java-ReST-API-extension-project - 6.3 - 6.3

Alfresco Events SDK for Out-of-Process Events

Platform
Alfresco
Product
Alfresco Events SDK for Out-of-Process Events
Release
6.3
License
ft:lastPublication
2025-09-04T22:27:16.404000
ft:locale
en-US

Make sure you have completed prerequisites (see Prerequisites) and created a starter project (see Create a starting point Spring project).

  1. Add the following dependency in the Maven project file (i.e. pom.xml):
     <dependencies>
         <!-- Alfresco Java SDK 6 Java ReST API wrapper Spring Boot Starter -->
         <dependency>
         <groupId>org.alfresco</groupId>
         <artifactId>alfresco-acs-java-rest-api-spring-boot-starter</artifactId>
         <version>6.2.0</version>
         </dependency>
     </dependencies>
    
  2. Remove the default Spring Boot starter dependency (i.e. <artifactId>spring-boot-starter</artifactId>).
  3. Modify the contents of the Spring Boot application class (org/alfresco/tutorial/sdk5demo/Sdk5DemoApplication.java) by adding the following com.fasterxml.jackson.databind.ObjectMapper. This is required for deserializing dates:
     package org.alfresco.tutorial.sdk5demo;
    
     import com.fasterxml.jackson.databind.ObjectMapper;
     import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
     import org.springframework.beans.factory.annotation.Autowired;
     import org.springframework.boot.SpringApplication;
     import org.springframework.boot.autoconfigure.SpringBootApplication;
    
     import javax.annotation.PostConstruct;
        
     @SpringBootApplication
     public class Sdk5DemoApplication {
        
         @Autowired
         private ObjectMapper objectMapper;
        
         @PostConstruct
         public void setUp() {
             objectMapper.registerModule(new JavaTimeModule());
         }
        
         public static void main(String[] args) {
             SpringApplication.run(Sdk5DemoApplication.class, args);
         }
     }
    
  4. Test it:
     $ mvn clean package -Dlicense.skip=true
     [INFO] Scanning for projects...
     ...
    
     $ java -jar target/rest-api-0.0.1-SNAPSHOT.jar
    
     .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
     ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
     '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::                (v2.4.2)
    
     2021-04-07 14:31:35.599  INFO 53273 --- [           main] o.a.tutorial.restapi.RestApiApplication  : Starting RestApiApplication v0.0.1-SNAPSHOT using Java 11.0.2 on MBP512-MBERGLJUNG-0917 with PID 53273 (/Users/mbergljung/IDEAProjects/docs-new/sdk5/sdk5-rest-api-java-wrapper-sample/target/rest-api-0.0.1-SNAPSHOT.jar started by mbergljung in /Users/mbergljung/IDEAProjects/docs-new/sdk5/sdk5-rest-api-java-wrapper-sample)
     2021-04-07 14:31:35.605  INFO 53273 --- [           main] o.a.tutorial.restapi.RestApiApplication  : No active profile set, falling back to default profiles: default
     2021-04-07 14:31:36.832  INFO 53273 --- [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=55661aff-d1dc-3db8-94e2-cf0514d3118c
     2021-04-07 14:31:37.443  INFO 53273 --- [           main] o.a.tutorial.restapi.RestApiApplication  : Started RestApiApplication in 2.832 seconds (JVM running for 3.563)
    

    Looks ready for some ReST API code.

  5. Now, start adding your ReST API code, let’s create a command line client that can be used to create sites, create folders, create files, and to search. First update the Spring Boot application class to look like follows, making use of the org.springframework.boot.CommandLineRunner:
    package org.alfresco.tutorial.restapi;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.CommandLineRunner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class RestApiApplication implements CommandLineRunner {
        private static final Logger LOGGER = LoggerFactory.getLogger(RestApiApplication.class);
    
        @Autowired
        CreateSiteCmd createSiteCmd;
    
        @Autowired
        CreateFolderCmd createFolderCmd;
    
        @Autowired
        CreateFileCmd createFileCmd;
    
        @Autowired
        SearchCmd searchCmd;
    
        public static void main(String[] args) {
            SpringApplication.run(RestApiApplication.class, args);
        }
    
        public void run(String... args) throws Exception {
            for (int i = 0; i < args.length; ++i) {
                LOGGER.info("args[{}]: {}", i, args[i]);
            }
    
            String command = args[0];
    
            switch (command) {
                case "create-site":
                    createSiteCmd.execute(args[1]);
                    break;
                case "create-folder":     // siteId, folderName
                    createFolderCmd.execute(args[1], args[2]);
                    break;
                case "create-file":      // parentFolderNodeId, filename
                    createFileCmd.execute(args[1], args[2]);
                    break;
                case "search":          // siteId, term
                    searchCmd.execute(args[1], args[2]);
                    break;
                default:
                    LOGGER.error("Command {} is not available", command);
            }
    
        }
    }
    

    This command line runner uses a number of beans to support creating different things in the Alfresco Repository, such as sites and folders.

  6. Start by creating the CreateSiteCmd bean that will facilitate creating sites via the ReST API Java wrapper, in the same package as the Spring Boot application class create the following class:
    package org.alfresco.tutorial.restapi;
    
    import org.alfresco.core.handler.SitesApi;
    import org.alfresco.core.model.Site;
    import org.alfresco.core.model.SiteBodyCreate;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.io.IOException;
    import java.util.Objects;
    
    @Component
    public class CreateSiteCmd {
        static final Logger LOGGER = LoggerFactory.getLogger(CreateSiteCmd.class);
    
        @Autowired
        SitesApi sitesApi;
    
        public void execute(String siteId) throws IOException {
            Site site = Objects.requireNonNull(sitesApi.createSite(
                    new SiteBodyCreate()
                            .id(siteId)
                            .title("title-" + siteId)
                            .description("description-" + siteId)
                            .visibility(SiteBodyCreate.VisibilityEnum.PUBLIC),
                    null, null, null).getBody()).getEntry();
            LOGGER.info("Created site: {}", site);
        }
    }
    
  7. To use one of the ReST API Java wrapper services, such as SitesApi , auto wire it into the component as in the above class. Creating stuff in the repository usually mean making a HTTP POST in the background. In these cases there is always a body class that we can use to fill in POST data, such as SiteBody in this case. A successful API call will return a populated result object called Site.
  8. In a similar way we add the other three command beans in the same directory as follows, starting with the CreateFolderCmd:
    package org.alfresco.tutorial.restapi;
    
    import org.alfresco.core.handler.NodesApi;
    import org.alfresco.core.handler.SitesApi;
    import org.alfresco.core.model.Node;
    import org.alfresco.core.model.NodeBodyCreate;
    import org.alfresco.core.model.SiteContainer;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.io.IOException;
    import java.util.Objects;
    
    @Component
    public class CreateFolderCmd {
        static final Logger LOGGER = LoggerFactory.getLogger(CreateFolderCmd.class);
    
        @Autowired
        SitesApi sitesApi;
    
        @Autowired
        NodesApi nodesApi;
    
        public void execute(String siteId, String folderName) throws IOException {
            SiteContainer docLibContainer = Objects.requireNonNull(sitesApi.getSiteContainer(siteId,
                    "documentLibrary", null).getBody()).getEntry();
            LOGGER.info("Creating folder in site DocumentLibrary folder Node ID: {}", docLibContainer.getId());
    
            Node folderNode = Objects.requireNonNull(nodesApi.createNode(docLibContainer.getId(),
                    new NodeBodyCreate()
                            .nodeType("cm:folder")
                            .name(folderName),
                    null, null, null, null, null).getBody()).getEntry();
    
            LOGGER.info("Created folder: {}", folderNode.toString());
        }
    }
    

    The NodesApi is one of the main APIs that we will use a lot to manipulate folders and files. We use it here to create a folder node in the site’s document library.

  9. Next we create the CreateFileCmd as follows in the same directory:
    package org.alfresco.tutorial.restapi;
    
    import org.alfresco.core.handler.NodesApi;
    import org.alfresco.core.model.Node;
    import org.alfresco.core.model.NodeBodyCreate;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.io.IOException;
    import java.util.Objects;
    
    @Component
    public class CreateFileCmd {
        static final Logger LOGGER = LoggerFactory.getLogger(CreateFileCmd.class);
    
        @Autowired
        NodesApi nodesApi;
    
        public void execute(String parentFolderId, String fileName) throws IOException {
            // Get the parent folder where file should be stored
            Node parentFolderNode = Objects.requireNonNull(nodesApi.getNode(parentFolderId, null,  null,
                    null).getBody()).getEntry();
            LOGGER.info("Got parent folder node: {}", parentFolderNode.toString());
    
            // Create the file node metadata
            Node fileNode = Objects.requireNonNull(nodesApi.createNode(parentFolderNode.getId(),
                    new NodeBodyCreate().nodeType("cm:content").name(fileName),
                    null, null, null, null, null).getBody()).getEntry();
    
            // Add the file node content
            Node updatedFileNode = Objects.requireNonNull(nodesApi.updateNodeContent(fileNode.getId(),
                    "Some text for this file...".getBytes(), true, null, null,
                    null, null).getBody()).getEntry();
    
            LOGGER.info("Created file with content: {}", updatedFileNode.toString());
        }
    }
    

    You might notice that it requires two calls to create a file with content. The ReST API does provide a way to do this with one call as can be seen in the Upload a file section in the Develop chapter of the Alfresco Content Services documentation. However, the generated Java wrapping classes does not yet provide functionality for this (it is scheduled to be supported in a future version of the SDK).

  10. Add also the final SearchCmd class as follows:
    package org.alfresco.tutorial.restapi;
    
    import org.alfresco.search.handler.SearchApi;
    import org.alfresco.search.model.RequestQuery;
    import org.alfresco.search.model.ResultSetPaging;
    import org.alfresco.search.model.SearchRequest;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.stereotype.Component;
    
    import java.io.IOException;
    
    @Component
    public class SearchCmd {
        static final Logger LOGGER = LoggerFactory.getLogger(SearchCmd.class);
    
        @Autowired
        SearchApi searchApi;
    
        public void execute(String siteId, String term) throws IOException {
            ResponseEntity<ResultSetPaging> result = searchApi.search(new SearchRequest()
                    .query(new RequestQuery()
                            .language(RequestQuery.LanguageEnum.AFTS)
                            .query("(SITE:\"" + siteId + "\" AND TEXT:\"" + term + "\" )")));
    
            LOGGER.info("Search result: {}", result.getBody().getList().getEntries());
        }
    }
    
  11. Now, stop and build it again:
    $ ^C
    ...
    $ mvn clean package -Dlicense.skip=true
    ...
    
  12. Create an Alfresco Share site with id test as follows:
    $ java -jar target/rest-api-0.0.1-SNAPSHOT.jar create-site test
    ...
    2021-04-08 13:16:49.239  INFO 62074 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[0]: create-site
    2021-04-08 13:16:49.241  INFO 62074 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[1]: test
    2021-04-08 13:16:52.989  INFO 62074 --- [           main] o.a.tutorial.restapi.CreateSiteCmd       : Created site: class Site {
        id: test
        guid: 59dc57a1-ad07-4715-8844-005cc7fc59d7
        title: title-test
        description: description-test
        visibility: PUBLIC
        preset: site-dashboard
        role: SiteManager
    }
    
  13. Then create a folder called folder1 in the site with id test:
    $ java -jar target/rest-api-0.0.1-SNAPSHOT.jar create-folder test folder1
    ...
    2021-04-08 13:19:23.264  INFO 62106 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[0]: create-folder
    2021-04-08 13:19:23.266  INFO 62106 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[1]: test
    2021-04-08 13:19:23.267  INFO 62106 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[2]: folder1
    2021-04-08 13:19:23.560  INFO 62106 --- [           main] o.a.tutorial.restapi.CreateFolderCmd     : Creating folder in site DocumentLibrary folder Node ID: aa02f5eb-f45d-4ab4-bf21-9eeb8c243d51
    2021-04-08 13:19:24.166  INFO 62106 --- [           main] o.a.tutorial.restapi.CreateFolderCmd     : Created folder: class Node {
        id: 3e16d079-2fdc-4d64-ad76-c65c233165f4
        name: folder1
        nodeType: cm:folder
        isFolder: true
        isFile: false
        isLocked: false
        modifiedAt: 2021-04-08T12:19:23.876Z
        modifiedByUser: class UserInfo {
            displayName: Administrator
            id: admin
        }
        createdAt: 2021-04-08T12:19:23.876Z
        createdByUser: class UserInfo {
            displayName: Administrator
            id: admin
        }
        parentId: aa02f5eb-f45d-4ab4-bf21-9eeb8c243d51
        isLink: null
        isFavorite: null
        content: null
        aspectNames: [cm:auditable]
        properties: null
        allowableOperations: null
        path: null
        permissions: null
        definition: null
    }
    
  14. Create a file called somefile.txt in the folder called folder1 (3e16d079-2fdc-4d64-ad76-c65c233165f4):
    $ java -jar target/rest-api-0.0.1-SNAPSHOT.jar create-file 3e16d079-2fdc-4d64-ad76-c65c233165f4 somefile.txt
    ...
    2021-04-08 13:21:55.972  INFO 62152 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[0]: create-file
    2021-04-08 13:21:55.973  INFO 62152 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[1]: 3e16d079-2fdc-4d64-ad76-c65c233165f4
    2021-04-08 13:21:55.973  INFO 62152 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[2]: somefile.txt
    2021-04-08 13:21:56.211  INFO 62152 --- [           main] o.a.tutorial.restapi.CreateFileCmd       : Got parent folder node: class Node {
        id: 3e16d079-2fdc-4d64-ad76-c65c233165f4
        name: folder1
        nodeType: cm:folder
        isFolder: true
        isFile: false
        isLocked: false
        modifiedAt: 2021-04-08T12:19:23.876Z
        modifiedByUser: class UserInfo {
            displayName: Administrator
            id: admin
        }
        createdAt: 2021-04-08T12:19:23.876Z
        createdByUser: class UserInfo {
            displayName: Administrator
            id: admin
        }
        parentId: aa02f5eb-f45d-4ab4-bf21-9eeb8c243d51
        isLink: null
        isFavorite: null
        content: null
        aspectNames: [cm:auditable]
        properties: null
        allowableOperations: null
        path: null
        permissions: null
        definition: null
    }
    2021-04-08 13:21:56.896  INFO 62152 --- [           main] o.a.tutorial.restapi.CreateFileCmd       : Created file with content: class Node {
        id: 1187b449-258e-4843-997f-991b7995b665
        name: somefile.txt
        nodeType: cm:content
        isFolder: false
        isFile: true
        isLocked: false
        modifiedAt: 2021-04-08T12:21:56.697Z
        modifiedByUser: class UserInfo {
            displayName: Administrator
            id: admin
        }
        createdAt: 2021-04-08T12:21:56.265Z
        createdByUser: class UserInfo {
            displayName: Administrator
            id: admin
        }
        parentId: 3e16d079-2fdc-4d64-ad76-c65c233165f4
        isLink: null
        isFavorite: null
        content: class ContentInfo {
            mimeType: text/plain
            mimeTypeName: Plain Text
            sizeInBytes: 26
            encoding: ISO-8859-1
        }
        aspectNames: [cm:versionable, cm:auditable]
        properties: {cm:versionLabel=1.0, cm:versionType=MAJOR}
        allowableOperations: null
        path: null
        permissions: null
        definition: null
    }
    
  15. Finally, search for content matching text file in site with id test:
    $ java -jar target/rest-api-0.0.1-SNAPSHOT.jar search test file
    ...
    2021-04-08 14:40:51.379  INFO 63261 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[0]: search
    2021-04-08 14:40:51.381  INFO 63261 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[1]: test
    2021-04-08 14:40:51.381  INFO 63261 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[2]: file
    2021-04-08 14:40:52.493  INFO 63261 --- [           main] org.alfresco.tutorial.restapi.SearchCmd  : Search result: [class ResultSetRowEntry {
        entry: class ResultNode {
            id: 1187b449-258e-4843-997f-991b7995b665
            name: somefile.txt
            nodeType: cm:content
            isFolder: false
            isFile: true
            isLocked: false
            modifiedAt: 2021-04-08T12:21:59.077Z
            modifiedByUser: class UserInfo {
                displayName: Administrator
                id: admin
            }
            createdAt: 2021-04-08T12:21:56.265Z
            createdByUser: class UserInfo {
                displayName: Administrator
                id: admin
            }
            parentId: 3e16d079-2fdc-4d64-ad76-c65c233165f4
            isLink: null
            content: class ContentInfo {
                mimeType: text/plain
                mimeTypeName: Plain Text
                sizeInBytes: 26
                encoding: ISO-8859-1
                mimeTypeGroup: null
            }
            aspectNames: null
            properties: null
            allowableOperations: null
            path: null
            search: class SearchEntry {
                score: 1.0
                highlight: null
            }
            archivedByUser: null
            archivedAt: null
            versionLabel: null
            versionComment: null
        }
    }]
    

    This sample has shown us that it’s easy to interact with the Alfresco Repository from a Java client with the help of SDK Java ReST API services.

    For more information see the ReST API Java wrapper extension point section in the Alfresco Content Services documentation.