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?
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.
Related
So I just started playing around with JDA API trying to create a little /info command which looked like shown below.
Issue: Unfortunately the bot does not react when I type /info.
While I was debugging, I found out, that the Info command never get's called and I will explain why later, after showing you the 3 classes that are involved in this problem.
public class InfoCommand extends Command {
public InfoCommand(String name) {
super(name);
}
#Override
public void handle(MessageReceivedEvent event, String... params) {
EmbedBuilder builder = new EmbedBuilder();
builder.setTitle("Test Title");
builder.setDescription("Test Description" );
builder.setFooter("Created by t0gepi");
builder.setColor(0xf45642);
event.getChannel().sendTyping().queue();
event.getChannel().sendMessageEmbeds(builder.build()).queue();
}
}
It has a method handle which will be called by a CommandManager, whenever /info is typed in the discord server.
So far so good.
Now the Main method is also quite simple. It just starts the bot and adds the CommandManager as a Listener to JDA:
public class Main {
public static JDA jda;
public static void main(String[] args) throws LoginException {
ResourceManager.init();
jda = JDABuilder.createDefault(ResourceManager.getProperty("discord.bottoken")).build();
jda.getPresence().setStatus(OnlineStatus.IDLE);
jda.getPresence().setActivity(Activity.playing("Sleeping"));
try {
jda.awaitReady();
} catch (InterruptedException e) {
e.printStackTrace();
}
CommandManager commandManager = new CommandManager();
commandManager.addCommand(new InfoCommand("info"));
jda.addEventListener(new CommandManager());
}
}
Lastly, let's get to the CommandManager:
public class CommandManager extends ListenerAdapter {
private Set<Command> commands;
public CommandManager(){
this.commands = new HashSet<>();
}
public void addCommand(Command command){
commands.add(command);
}
#Override
public void onMessageReceived(#NotNull MessageReceivedEvent event) {
String[] msg = event.getMessage().getContentRaw().split(" ");
String prefix = ResourceManager.getProperty("command.prefix");
String[] params = null;
if(!msg[0].startsWith(prefix)){
return;
}
if(msg.length > 1){
params = Arrays.copyOfRange(msg,1,msg.length);
}
Iterator<Command> iterator = commands.iterator();
Command command;
while(iterator.hasNext()){
command = iterator.next();
if(command.getAliases().stream().anyMatch(alias -> msg[0].equalsIgnoreCase(prefix + alias))){
command.handle(event, params);
return;
}
}
// Do nothing here if command wasn't found.
}
}
Now let's get to the actual issue, why does the InfoCommands handle method not get called? Keep in mind that
InfoCommand has bin initialized and added to the CommandManager
The CommandManagers onMessageReceived method is in fact being called when a message is typed
As I was debugging, I found out why but could not find an explanation to it.
The reason why the handle method of InfoCommand does not get called, is because as to the time when onMessageReceived gets called, the CommandManagers set of commands is empty.
Why is that? I added the InfoCommand in the beginning right?
When I added the InfoCommand in the beginning, the set of commands had a size of 1. All good. But when onMessageReceived got called, the set of Commands suddenly had a size of 0, which means that the Iterator doesn't have anything to iterate over.
Why is that? I furthermore found out the following:
As to the time where I initialized the CommandManager, the CommandManager had a different memory adress than when it's onMessageReceived method got called.
So somehow, JDA must have created another new instance of CommandManager and used that, instead of my instance, right?
I hope someone understands this and let me know if you have any questions :)
Thanks for reading that far and if you'd like, you can take a better look at all the files in this Project here. There really aren't much more.
You are creating a new instance of your command manager when you register it:
jda.addEventListener(new CommandManager());
Instead, you should just pass in the instance you previously created:
CommandManager commandManager = new CommandManager();
commandManager.addCommand(new InfoCommand("info"));
jda.addEventListener(commandManager);
I am looking at a code that I have to work on. And basically I have to add a validation to a listener of a button.
The code has already multiple validations. They are kind of set in a cascade.
The listener of the buttons calls an asyncCallBack method that if everything is ok, on the onsuccess part of the method calls for the next one, an that one on the next one, until it reaches the end and goes to the next page. I am not a fan of this approach because it is kind of messy. What would the best way to do that using best practices.
An example of the code:
Button btnOK = new Button("Aceptar");
btnOK.addListener(Events.Select, new Listener<ButtonEvent>() {
public void handleEvent(ButtonEvent e) {
myService.getInfo1(1, txt, "N",
new AsyncCallback<List<InfoService>>() {
public void onFailure(Throwable caught) {
// goes back
return
}
public void onSuccess(
List<Object> result) {
// do some validation with the result
validation2();
}
}
}
}
public void validation2(){
myService.getDireccionCanalesElectronicos(id, new AsyncCallback<MyResult>() {
public void onSuccess(MyResult result) {
// do some validation with the result
validation3();
}
...
}
}
public void validation3(){
myService.getDireccionCanalesElectronicos(id, new AsyncCallback<MyResult>() {
public void onSuccess(MyResult result) {
// do some validation with the result
validation4();
}
...
}
}
Is there a better way of doing this, it seems messy and hard to follow. Adding another validation is complicated. It doesnt seem like a good practice.
Create 1 method in the servlet that calls all the validation methods and do just one call in the client ?
public void validation()
{
boolean ok = validation1();
if (ok) ok = validation2();
return validation;
}
Using mirco services is sometimes hard to deal with. As #Knarf mentioned, this is a way to go. But sometime you may want to handle the calls on the client side. Another one will be using this tiny framework: sema4g. It will help you to solve your problem.
A solution might look like that:
First create the sem4g commands:
private SeMa4gCommand createGetInfoCommand() {
return new AsyncCommand() {
// create callback
MethodCallbackProxy<List<InfoService>> proxy = new MethodCallbackProxy<List<InfoService>>(this) {
#Override
protected void onProxyFailure(Method method,
Throwable caught) {
// Enter here the code, that will
// be executed in case of failure
}
#Override
protected void onProxySuccess(Method method,
List<InfoService> response) {
// Enter here the code, that will
// be executed in case of success
}
};
#Override
public void execute() {
// That's the place for the server call ...
myService.getInfo1(1, txt, "N", proxy);
}
};
}
do that for all your calls;
private SeMa4gCommand createCommandGetDireccionCanalesElectronicos() {
return new AsyncCommand() {
// create callback
MethodCallbackProxy<MyResult> proxy = new MethodCallbackProxy<MyResult>(this) {
#Override
protected void onProxyFailure(Method method,
Throwable caught) {
// Enter here the code, that will
// be executed in case of failure
}
#Override
protected void onProxySuccess(Method method,
List<MyResult> response) {
// Enter here the code, that will
// be executed in case of success
}
};
#Override
public void execute() {
// That's the place for the server call ...
myService. getDireccionCanalesElectronicos(id, proxy);
}
};
}
Once you have done this for all your calls, create a sema4g context and run it:
try {
SeMa4g.builder()
.addInitCommand(new InitCommand() {
#Override
public void onStart() {
// Enter here your code, that
// should be executed when
// the context is started
})
.addFinalCommand(new FinalCommand() {
#Override
public void onSuccess() {
// Enter here the code, that will
// be executed in case the context
// ended without error
}
#Override
public void onFailure() {
// Enter here the code, that will
// be executed in case the context
// ended with an error
})
.add(createGetInfoCommand())
.add(createCommandGetDireccionCanalesElectronicos())
.build()
.run();
} catch (SeMa4gException e) {
// Ups, something wrong with the context ...
}
For more informations, read the documentation. If you have questions, feel free to ask: SeMa4g Gitter room.
Hope that helps.
so, here is my today problem:
First of all, please note that I do NOT have the Matlab parallel toolbox available.
I am running java code witch interact with Matlab. Sometime Matlab directly call some java functions, sometimes it is the opposite. In this case, we use a notification system which comes from here:
http://undocumentedmatlab.com/blog/matlab-callbacks-for-java-events
We then address the notification in proper callbacks.
Here is a simple use case:
My user select a configuration file using the java interface, loaded into Matlab.
Using an interface listener, we notify Matlab that the configuration file has been selected, it then run a certain number of functions that will analyzes the file
Once the analysis is done, it is pushed into the java runtime, which will populate interface tables with the result. This step involve that matlab will call a java function.
Finally, java request the interface to be switched to an arbitrary decided tab.
This is the order of which things would happen in an ideal world, however, here is the code of the listener actionPerformed method:
#Override
public void actionPerformed(ActionEvent arg0) {
Model wModel = controller.getModel();
Window wWindow = controller.getWindow();
MatlabStructure wStructure = new MatlabStructure();
if(null != wModel) {
wModel.readMatlabData(wStructure);
wModel.notifyMatlab(wStructure, MatlabAction.UpdateCircuit);
}
if(null != wWindow) {
wWindow.getTabContainer().setSelectedComponent(wWindow.getInfosPannel());
}
}
What happen here, is that, when the notifyMatlab method is called, the code does not wait for it to be completed before it continues. So what happen is that the method complete and switch to an empty interface page (setSelectedComponent), and then the component is filled with values.
What I would like to, is for java to wait that my notifyMatlab returns a "I have completed !!" signal, and then pursue. Which involves asynchrounous code since Matlab will code java methods during its execution too ...
So far here is what I tried:
In the MatlabEventObject class, I added an isAcknowledge member, so now the class (which I originaly found in the above link), look like this (I removed all unchanged code from the original class):
public class MatlabEventObject extends java.util.EventObject {
private static final long serialVersionUID = 1L;
private boolean isAcknowledged = false;
public void onNotificationReceived() {
if (source instanceof MatlabEvent) {
System.out.println("Catched a MatlabEvent Pokemon !");
MatlabEvent wSource = (MatlabEvent) source;
wSource.onNotificationReceived();
}
}
public boolean isAcknowledged() {
return isAcknowledged;
}
public void acknowledge() {
isAcknowledged = true;
}
}
In the MatlabEvent class, I have added a future task which goal is to wait for acknowledgement, the methods now look like this:
public class MatlabEvent {
private Vector<IMatlabListener> data = new Vector<IMatlabListener>();
private Vector<MatlabEventObject> matlabEvents = new Vector<MatlabEventObject>();
public void notifyMatlab(final Object obj, final MatlabAction action) {
final Vector<IMatlabListener> dataCopy;
matlabEvents.clear();
synchronized (this) {
dataCopy = new Vector<IMatlabListener>(data);
}
for (int i = 0; i < dataCopy.size(); i++) {
matlabEvents.add(new MatlabEventObject(this, obj, action));
((IMatlabListener) dataCopy.elementAt(i)).testEvent(matlabEvents.get(i));
}
}
public void onNotificationReceived() {
ExecutorService service = Executors.newSingleThreadExecutor();
long timeout = 15;
System.out.println("Executing runnable.");
Runnable r = new Runnable() {
#Override
public void run() {
waitForAcknowledgement(matlabEvents);
}
};
try {
Future<?> task = service.submit(r);
task.get(timeout, TimeUnit.SECONDS);
System.out.println("Notification acknowledged.");
} catch (Exception e) {
e.printStackTrace();
}
}
private void waitForAcknowledgement(final Vector<MatlabEventObject> matlabEvents) {
boolean allEventsAcknowledged = false;
while(!allEventsAcknowledged) {
allEventsAcknowledged = true;
for(MatlabEventObject eventObject : matlabEvents) {
if(!eventObject.isAcknowledged()) {
allEventsAcknowledged = false;
}
break;
}
}
}
}
What happen is that I discover that Matlab actually WAIT for the java code to be completed. So my waitForAcknowledgement method always wait until it timeouts.
In addition, I must say that I have very little knowledge in parallel computing, but I think our java is single thread, so having java waiting for matlab code to complete while matlab is issuing calls to java functions may be an issue. But I can't be sure : ]
If you have any idea on how to solve this issue in a robust way, it will be much much appreciated.
I am trying to check to see if a view is displayed with Espresso. Here is some pseudo code to show what I am trying:
if (!Espresso.onView(withId(R.id.someID)).check(doesNotExist()){
// then do something
} else {
// do nothing, or what have you
}
But my problem is .check(doesNotExist()) does not return boolean. It is just an assertion. With UiAutomator I was able to just do something like so:
if (UiAutomator.getbyId(SomeId).exists()){
.....
}
Conditional logic in tests is undesirable. With that in mind, Espresso's API was designed to guide the test author away from it (by being explicit with test actions and assertions).
Having said that, you can still achieve the above by implementing your own ViewAction and capturing the isDisplayed check (inside the perform method) into an AtomicBoolean.
Another less elegant option - catch the exception that gets thrown by failed check:
try {
onView(withText("my button")).check(matches(isDisplayed()));
//view is displayed logic
} catch (NoMatchingViewException e) {
//view not displayed logic
}
Kotlin version with an extension function:
fun ViewInteraction.isDisplayed(): Boolean {
try {
check(matches(ViewMatchers.isDisplayed()))
return true
} catch (e: NoMatchingViewException) {
return false
}
}
if(onView(withText("my button")).isDisplayed()) {
//view is displayed logic
} else {
//view not displayed logic
}
I think to mimic UIAutomator you can do this:
(Though, I suggest rethinking your approach to have no conditions.)
ViewInteraction view = onView(withBlah(...)); // supports .inRoot(...) as well
if (exists(view)) {
view.perform(...);
}
#CheckResult
public static boolean exists(ViewInteraction interaction) {
try {
interaction.perform(new ViewAction() {
#Override public Matcher<View> getConstraints() {
return any(View.class);
}
#Override public String getDescription() {
return "check for existence";
}
#Override public void perform(UiController uiController, View view) {
// no op, if this is run, then the execution will continue after .perform(...)
}
});
return true;
} catch (AmbiguousViewMatcherException ex) {
// if there's any interaction later with the same matcher, that'll fail anyway
return true; // we found more than one
} catch (NoMatchingViewException ex) {
return false;
} catch (NoMatchingRootException ex) {
// optional depending on what you think "exists" means
return false;
}
}
Also exists without branching can be implemented really simple:
onView(withBlah()).check(exists()); // the opposite of doesNotExist()
public static ViewAssertion exists() {
return matches(anything());
}
Though most of the time it's worth checking for matches(isDisplayed()) anyway.
We need that functionality and I ended up implementing it below:
https://github.com/marcosdiez/espresso_clone
if(onView(withText("click OK to Continue")).exists()){
doSomething();
} else {
doSomethingElse();
}
I hope it is useful for you.
You check with the below code also. If view is displayed it will click else it will pass on.
onView(withText("OK")).withFailureHandler(new FailureHandler() {
#Override
public void handle(Throwable error, Matcher<View> viewMatcher){
}
}).check(matches(isDisplayed())).perform(customClick());
Why no one mentioned:
onView(withId(R.id.some_view_id)).check(matches(not(doesNotExist())))
just add not before doesNotExist. But if you use this logic a lot it's better to use a custom matcher.
Based on the answer by Dhiren Mudgil, I ended up writing the following method:
public static boolean viewIsDisplayed(int viewId)
{
final boolean[] isDisplayed = {true};
onView(withId(viewId)).withFailureHandler(new FailureHandler()
{
#Override
public void handle(Throwable error, Matcher<View> viewMatcher)
{
isDisplayed[0] = false;
}
}).check(matches(isDisplayed()));
return isDisplayed[0];
}
I'm using this to help determine which View in a ViewFlipper is currently displayed.
I think that what Espresso wants you to do is to change your logic to use doesNotExist()
I have for example
onView(snackBarMatcher).check(doesNotExist())
onView(withId(R.id.button)).perform(click())
onView(snackBarMatcher).check(matches(isDisplayed()))
It's been some time since this issue was stated, but as it is one of the top hit on Google when searching for ways to make sure a view is present, before doing any actions on it in Espresso, I would like to share my very basic way of handling this.
1: Start out by writing an extension to ViewInteraction:
fun ViewInteraction.exists(): Boolean {
val viewExists = AtomicReference<Boolean>()
this.perform(object : ViewAction {
override fun perform(uiController: UiController?, view: View?) {
viewExists.set(view != null)
}
override fun getConstraints(): Matcher<View>? {
return Matchers.allOf(ViewMatchers.withEffectiveVisibility(
ViewMatchers.Visibility.VISIBLE),
ViewMatchers.isAssignableFrom(View::class.java))
}
override fun getDescription(): String {
return "check if view exists"
}
})
return viewExists.get()
}
2: Create a simple help method in your base class (to be used in all test classes):
fun viewExists(id: Int): Boolean {
return try {
onView(withId(id)).exists()
} catch (e: RuntimeException) {
false
}
}
With this you either get true or false from onView(withId(id)).exists(), or safely catch the RuntimeException and return false.
Normally a simple check to .exists() would be sufficient, but in some cases, like when you are deleting ListView items until non is left -> when the last item is deleted, the ListView might no longer be present, then an Exception is thrown when trying to check if it exists.
3: With the above implementation, it is safe to check if any view exists, since the RuntimeException is handled nicely behind the scene:
if(viewExists(R.id.something)) {
//do something
}
//do something else
I got Activity, in onCreate() I try to fetch data:
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
...............
fillUI();
}
public void getDetailedItem(){
FeedParser parser=new FeedParser();
try{
mItem=parser.parseDetailed();
}catch(Exception e){
closeAndShowError();
}
}
public void fillUI(){
getDetailedItem();
if(mItem!=null){
...............
}else{
closeAndShowError();
}
}
private void closeAndShowError(){
Context context = getApplicationContext();
CharSequence text = getResources().getString(R.string.toast_error);
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
finish();
}
Them problem is, when Exception occures, it is caught, and I expect my activity to finish itself, but I still get code inside fillUI() executed, so I had to put if statement after getDetailedItem();
How do I solve it?
You can do something like this:
public void getDetailedItem(){
FeedParser parser=new FeedParser();
try{
mItem=parser.parseDetailed();
}catch(Exception e){
mItem = null;
}
}
Then in fillUI() if mItem is null you show's error;
You could pass the exception that might get thrown in parseDetailed to the fillUI method:
public void getDetailedItem() throws Exception {
FeedParser parser=new FeedParser();
mItem=parser.parseDetailed();
}
public void fillUI(){
try {
getDetailedItem();
// rest of your code..
} catch(Exception e) {
closeAndShowError();
}
}
The finish() statement is not an immediate return, your code continues to run until it decides it's completed. You need to leave yourself an indicator of the exception, and return up through your call chain when it happens, instead of continuing to run.
Since you are catching the Exception; the fillUI() function is never notified of any error.
Your codepath is as following:
fillUI -> getDetailedItem -> exception caught -> closeAndShowError -> finish() -> return to closeAndShowError -> return to getDetailedItem after caught block -> return back to fillUI.
So basically, the code after getDetailedItem in fillUI is called because you caught the exception and didn't let the other function know. Either by return value, or by throwing (and maybe catching) a new exception.
finish() does cause the Activity to stop as the next step in its lifecycle. But at the point you call it, it's still in the process of another lifecycle step: onCreate(). It will not exit, somehow, immediately in the middle of a method.
That's the answer, but, better would be to redesign your code a bit. This is probably not the cleanest way to handle it if you're dealing with questions like this.