Search code examples
javaselenide

Getting error when using LogEventListener


I am getting an error when using a LogEventListener.

When I just print something, for example in the beforeEvent method, everything is fine, but when I set any action in any method, I get this error:

java.lang.StackOverflowError
    at java.base/java.lang.String.replace(String.java:2173)
    at com.codeborne.selenide.impl.SelenideElementDescriber.selector(SelenideElementDescriber.java:67)
    at com.codeborne.selenide.impl.ElementFinder.elementCriteria(ElementFinder.java:137)
    at com.codeborne.selenide.impl.ElementFinder.getSearchCriteria(ElementFinder.java:130)
    at com.codeborne.selenide.impl.Alias$NoneAlias.getOrElse(Alias.java:43)
    at com.codeborne.selenide.impl.WebElementSource.description(WebElementSource.java:60)
    at com.codeborne.selenide.impl.SelenideElementProxy.invoke(SelenideElementProxy.java:81)
    at jdk.proxy2/jdk.proxy2.$Proxy17.is(Unknown Source)
    at com.bme.listeners.EventLogger.beforeEvent(EventLogger.java:16)
    at com.codeborne.selenide.logevents.SelenideLogger.beginStep(SelenideLogger.java:121)
    at com.codeborne.selenide.logevents.SelenideLogger.beginStep(SelenideLogger.java:57)
    at com.codeborne.selenide.impl.SelenideElementProxy.invoke(SelenideElementProxy.java:81)**

Code:

public class EventLogger implements LogEventListener {

@Override
public void beforeEvent(LogEvent log) {

    if(Selenide.$("path").is(visible)) {
        System.out.println("Before Event");
    }

}

@Override
public void afterEvent(LogEvent log) {
}

}

Can anyone help me understand?


Solution

  • My best guess as to the cause of this problem is that calling Selenide.$("path").is(visible) causes a log event to be generated. This would cause your listener gets called again, so Selenide.$("path").is(visible) gets called again, which causes another log event, so your listener gets called again, and so on and so on until the stack overflows. However, I don't have enough of your stacktrace to be sure. I would be more sure of this problem if you could include the stacktrace down as far as the second line in which com.bme.listeners.EventLogger.beforeEvent appears.

    What might help is adding a boolean field to your listener that records whether it is currently logging an event, and does nothing if beforeEvent is called and this field is true:

    public class EventLogger implements LogEventListener {
    
        private boolean isCurrentlyLoggingAnEvent = false;
    
        @Override
        public void beforeEvent(LogEvent log) {
            if (isCurrentlyLoggingAnEvent) {
                // Prevent recursive call.
                return;
            }
        
            isCurrentlyLoggingAnEvent = true;
            try {
                if(Selenide.$("path").is(visible)) {
                    System.out.println("Before Event");
                }
            }
            finally {
                isCurrentlyLoggingAnEvent = false;
            }
        }
    
        @Override
        public void afterEvent(LogEvent log) {
        }
    }
    

    I've used a try-finally block to ensure that the field isCurrentlyLoggingAnEvent is always set back to false, even when an exception is thrown from within the try block.

    If you plan to put any logic in afterEvent, you may want to consider doing something similar there.