javaautomationsikuli

How to fix the missing ActionLogger bean error in Brobot?


I'm working on a Spring Boot application that uses Brobot. After updating the library, I started encountering an error indicating that a bean of type ActionLogger is required but could not be found. I'm struggling to understand what I should implement to fix this issue.

Error message:

2024-09-17T12:26:53.922+02:00  WARN 2816 --- [tw-check] [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'twCheckTestApplication': Unsatisfied dependency expressed through field 'actionLogger': No qualifying bean of type 'io.github.jspinak.brobot.logging.ActionLogger' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}


***************************
APPLICATION FAILED TO START
***************************

Description:

Field actionLogger in com.example.tw.TwCheckTestApplication required a bean of type 'io.github.jspinak.brobot.logging.ActionLogger' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'io.github.jspinak.brobot.logging.ActionLogger' in your configuration.

Here is my main class:

package com.example.tw;

import com.example.tw.controller.DatabaseController.DatabaseController;
import com.example.tw.utils.RobotCommands;
import io.github.jspinak.brobot.logging.ActionLogger;
import org.sikuli.script.ImagePath;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.ComponentScan;

import java.sql.Connection;

/**
 * The TwCheckTestApplication class is the main class of the project. This is where the database and brobot are configured.
 */
@SpringBootApplication
@ComponentScan(basePackages = {"io.github.jspinak.brobot", "com.example.tw"})
public class TwCheckTestApplication {

    public static void main(String[] args) {
        Connection dataTable = DatabaseController.connect();
        if (dataTable != null) {
            ImagePath.setBundlePath("images");

            // Add image path for other folders
            ImagePath.add("images/guestMode");
            ImagePath.add("images/chooseEngine");
            ImagePath.add("images/allMovement");
            ImagePath.add("images/connectionAndLinkMovement");
            ImagePath.add("images/Initiate");
            ImagePath.add("images/EditJSON");
            ImagePath.add("images/ImportImg");
            ImagePath.add("images/Branding");
            ImagePath.add("images/addVirtualStaging");
            ImagePath.add("images/addOverlays");
            ImagePath.add("images/itemVisibility");
            ImagePath.add("images/addAudio");
            ImagePath.add("images/allAnimations");
            ImagePath.add("images/checkTeleport");
            ImagePath.add("images/checkTags");
            ImagePath.add("images/addImagesAndTexts");
            ImagePath.add("images/checkMoveToLink");


            SpringApplicationBuilder builder = new SpringApplicationBuilder(TwCheckTestApplication.class);
            builder.headless(false);
            builder.run(args);

            RobotCommands.openChrome();
            RobotCommands.enterURL("http://localhost:8080/test-interface");
        } else {
            System.exit(0);
        }
    }
}

Solution

  • ActionLogger is one of the interfaces added in a recent update that provides the Brobot library with logging capabilities. By implementing these interfaces, you can collect information about your states, transitions, and actions during GUI automation and send them to another application. I've now added default implementations for the logging interfaces, so if you don't want to use logging, you don't need to implement them and can ignore them.

    If you wish to use logging, you can see implementations of these interfaces in the app module. For example, the class HttpActionLogger implements ActionLogger and TestSessionLogger. HttpActionLogger's dependencies include LogSender, in charge of sending the log data to another application, LogEntryService, the service class used to save log data to a repository, VideoRecorderService, for recording video of GUI automation, and LogEntryStateImageMapper, which translates StateImage objects to the datatype expected by LogEntry. In your implementation, you control the data you collect from automation and how you send it to the receiving application.

    @Component
    public class HttpActionLogger implements ActionLogger, TestSessionLogger {
    
        private final LogSender logSender;
        private final LogEntryService logEntryService;
        private final VideoRecorderService videoRecorderService;
        private final LogEntryStateImageMapper logEntryStateImageMapper;
    
        public HttpActionLogger(LogSender logSender, LogEntryService logEntryService,
                                VideoRecorderService videoRecorderService, LogEntryStateImageMapper logEntryStateImageMapper) {
            this.logSender = logSender;
            this.logEntryService = logEntryService;
            this.videoRecorderService = videoRecorderService;
            this.logEntryStateImageMapper = logEntryStateImageMapper;
        }
    
        private Long getCurrentProjectId() {
            return BrobotSettings.getCurrentProjectId();
        }
    
        @Override
        public LogEntry logAction(String sessionId, Matches matches, ObjectCollection objectCollection) {
            LogEntry logEntry = new LogEntry();
            logEntry.setProjectId(getCurrentProjectId());
            logEntry.setSessionId(sessionId);
            logEntry.setType(matches.getActionOptions().getAction().toString());
            logEntry.setDescription(getStateImageDescription(objectCollection, matches)); //matches.getActionDescription());
            logEntry.setTimestamp(Instant.now());
            logEntry.setActionPerformed(matches.getActionOptions().getAction().toString());
            logEntry.setDuration(matches.getDuration().toMillis());
            logEntry.setPassed(matches.isSuccess());
            logEntry.setCurrentStateName(getStateInFocus(objectCollection));
            objectCollection.getStateImages().forEach(
                    sI -> logEntry.addStateImageLog(logEntryStateImageMapper.toLog(sI, matches)));
            return logEntryService.saveLog(logEntry);
        }
    
        // ... other method implementations