IntelliJ IDEA breakpoints do not hit in dynamically loaded anonymous inner class - java

This is not your usual "my breakpoints don't work" question.
Consider the following code:
Runnable runnable = new Runnable()
{
#Override public void run()
{
Log.debug( "in run()" ); // <-- place one breakpoint here
}
};
#Test public void test()
{
Log.debug( "in test()" ); // <-- place another breakpoint here
runnable.run();
}
If you were to run this test from within IntellijIdea, using IntellijIdea's built-in JUnit support, the following things would happen:
Both logging statements produce output.
Both breakpoints hit.
However:
If you were to run this test from within some other framework, (e.g. Testana) which discovers the test class at runtime, loads it dynamically, and executes each test method in it, then the following happens:
Both logging statements produce output.
The breakpoint in the test() method hits.
The breakpoint in the run() method does not hit.
As a matter of fact, when the breakpoint in the test() method hits, you can see that the breakpoint in the run() method remains a red circle without a checkmark, which means that IntellijIdea does not recognize it as being on executable code.
Just in case it matters, I am currently using macOS, in a few days I am hoping to be able to try under Windows.
There were a couple of similar issues in IntellijIdea reported and fixed a long time ago:
https://youtrack.jetbrains.com/issue/IDEA-79268 (10 years ago)
https://youtrack.jetbrains.com/issue/IDEA-133881 (7 years ago)
Judging by a comment by CrazyCoder (a well known JetBrainiac on Stackoverflow) from May 29 '13 at 13:11 on this question Line breakpoints don't work in some classes which mentions some "debug scope" I suspect that the problem is something along these lines:
The testing framework is launched with its own classpath which does not include the test class.
The testing framework discovers the module containing the test class, creates a new ClassLoader with the class path of the module, uses that ClassLoader to load the test class, and runs the test methods in it.
The IntellijIdea debugger somehow detects that the test class was dynamically loaded, and includes it in whatever that "debug scope" is, so the breakpoint in the test() method hits.
The IntellijIdea debugger fails to detect that the anonymous inner class is also loaded, so it fails to include it in the "debug scope", so the breakpoint in the run() method does not hit.
And now the question:
Is there any workaround that would make the IntellijIdea debugger hit the breakpoint in the anonymous inner class?
Ideally, the workaround would be a general-purpose solution that can be implemented in the testing framework to take care of any similar situation.
A workaround that would make breakpoints work in anonymous inner classes by extra bureaucracy on the side of the test class would also be (barely) acceptable.
(But if you were going to suggest that I convert my anonymous inner class to a separate top-level class, please don't.)
EDIT
Behavior is same on Windows.
Steps to reproduce:
Check out this project: https://github.com/mikenakis/Public
Go to class T01_CompilingIntertwine
Place a breakpoint on line 57 (first line of function run())
Hit your Debug key to bring up the run configurations dialog
There will be a run configuration called Testana - All; launch it.
The breakpoint will not hit.
Make a minor modification to the file and save it (because testana does not run tests that have not changed.)
Place a breakpoint on line 53 (new Runnable())
Relaunch (Debug) Testana - All.
The breakpoint on line 53 will hit. If you resume, then the breakpoint on line 57 will also hit.

So, Konstantin Annikov from JetBrains found this worthy of creating an new issue for it on the IntelliJ IDEA issue tracker, see https://youtrack.jetbrains.com/issue/IDEA-287858
Then, Egor Ushakov from JetBrains looked into it, and found that this is happening because the testing framework is loading the classes in a non-standard order, while IntelliJ IDEA contains some logic that relies on the assumption that the classes will be loaded in the standard order.
The standard order of loading classes (when classes are being loaded by their classloader as they are being executed) is to have the outermost class loaded first, and the inner classes loaded afterwards.
Testana was loading the classes in the order in which the class files are yielded by java.nio.file.Files.walkFileTree(), which is apparently alphabetic, and it just so happens that $ sorts before ., so Testana was loading the inner classes first, and the outermost class last.
I fixed the problem in Testana, and Egor expressed the intention to try and implement a workaround for this case in IntelliJ IDEA. (This is such an edge case that I am not sure it is worth fixing, but anyway, it is his call.)

Related

Is it possible to compile a block of code only for a certain target (Android app)?

I'd like to understand what is the best approach to execute a block of code that it is only necessary on Debug target, on a certain activity, without being dependent on 'if' statements. Also, if it's possible to exclude the block of code from compilation when compiling the same app for another target.
Honestly, the best and easiest approach would be to do the following which will only execute in debuggable apps:
if(BuildConfig.DEBUG) {
// run your piece of code
}
If you use proguard on your release it will be stripped along with any other dead code from your app as it will evaluate to "false" for release builds. This is the easy way.
without being dependent on 'if' statements
In this case you need to create 2 versions of your class, one in your app/src/release and one in your app/src/debug folder. This makes use of resource merging offered by gradle, where you combine multiple source sets into one. If you were to put one in /main and one in /debug it wouldn't compile as you'd have a duplicate class, so be sure to define one class per build type (or go even further and add your own folders to certain build types if some reuse the same code...)
// in /release
class MyThing() {
void doStuff() { /* nothing */ }
}
// in /debug
class MyThing() {
void doStuff() {
actual();
code();
}
}
Now you can call new MyThing().doStuff() from your Activity and it will a) do nothing in release and b) do something in debug. I have shown an example where you would put solely the logic inside a duplicated class, but it would also be possible to just duplicate the whole activity that should execute the code...leading to...
The biggest problem with this approach is the duplication of code. Android Studio does not support refactoring with multiple source sets, so you would be switching between build types a lot. There will be build errors every once in a while because you forgot to fix something in one of the sources, and it's just a real pain.
You will effectively have to maintain all the code you duplicate in this fashion twice and you should keep the files affected to a bare minimum (for your own sake).
I would strongly recommend to use BuildConfig.DEBUG and not worry too much about it.
Yes, with flavors, in the same level as the folder 'main' create a folder called 'debug' and add a '/java' in that, create your debug only file classes here, but to use those files within main without release erros you will need to create the same structure calling release/java and add a blank implementation of some class.

How to debug a class loaded by a custom classloader in JDI

Using arguments -Xdebug, -agentlib:jdwp=transport=dt_socket, server=y, suspend=n, address=4404
Start target program.
Debug the target program using the com.sun.jdi related class. The classesByName method of the VirtualMachine class. The class that is loaded by the custom class loader is not available.
in target i can get class by
Class.forName("Script1", false, clazz.getClassLoader())
in VirtualMachine class , only has method :
List<ReferenceType> classesByName(String var1);
How should i do?
Monitoring classloading in JDI
For the last few weeks, I have been building a Java process monitoring tool based on the Java Debug Interface. Although I've done much of this work before, it has been a few years, and so now I'm retracing my steps. As I remember the details and pitfalls, I've been posting my notes in the hope that you'll find them useful.
Today I'm going to talk about ClassPrepareEvents, after a little background. As you probably already know, you can attach a debugger to an already-running Java process, or launch the target process itself from your debugger (using various command-line switches). In my project, I'm always going to be attaching to a running process, as the point is to collect process data on an as-needed basis. The reason JDI's ClassPrepareEvent is interesting is that, when you launch a debug target process, or even when you attach to an already-running process, it's likely that some of your desired breakpoints lie in classes which have not yet been loaded.
In my usual scenario, I call the com.sun.jdi.VirtualMachine's allClasses() method to get a list of all loaded ReferenceTypes. One way to think of a ReferenceType is as a chunk of a Java class definition. If your Java class has inner classes, then they will be broken out by JDI into separate ReferenceTypes. Each ReferenceType contains a collection of line locations; these correspond to lines of code on which breakpoints can be set and are identified by (among other things) the source-code line number. If a line of source code cannot be the target of a breakpoint, then there will not be a line location for it in the ReferenceType. In my debugger-based applications, I step through the line locations of all the ReferenceTypes, matching up line locations with breakpoint specifications, and then register my breakpoint requests.
As you can guess, I have a potential problem: what should I do if a class I need has not yet been loaded at the time I'm constructing my breakpoint requests? The answer is: JDI's ClassPrepareEvent. The entry point for using this part of the API is the EventRequestManager's createClassPrepareRequest() method. Having made our request, the same event-listener loop we use to wait for breakpoint events can also be used to wait for class prepare events (see the JVM specification for a definition of class preparation).
One thing I remember from my previous development on this API is that there is a timing risk here. You probably want to create the class prepare request before you iterate over the list of currently-loaded classes. The reason is that you don't want to fall into this trap:
Iterate over a set of the currently-loaded classes, processing and making breakpoint requests.
Suddenly, a class you need is loaded!
You register your class-prepare event and start getting events as classes are loaded, but you miss the class that loaded in between step #1 and step #3.
Here's another possible trap:
Register for class-prepare events so you don't get caught by the above issue.
Iterate over the currently-loaded classes, requesting breakpoints as necessary.
Process newly-loaded classes, requesting breakpoints as necessary.
The problem with this second approach is that you may process the same breakpoint twice. Why? By the time you iterate over the currently-loaded classes, some of the classes in that list are very likely going to be classes which have shown up in your class-prepare listener. Neither of these problems can be fixed by slapping a synchronized keyword somewhere.
Whether you launch your target application from your debugger or attach to it after the fact, you will have to deal with some variation of this issue. The way I deal with it is to add some state to the class I use to define each breakpoint specification. As each corresponding loaded class is found and the breakpoint request is made, I set a flag on the specification so that I know the request was registered. Further, I follow the second approach outlined above (better to have duplicates than to miss one). If I see a class-prepare event for a class I've already processed from the VM's ReferenceType list, then I simply skip over it. I do the same for the reverse situation, in which my list of ReferenceTypes contains ReferenceTypes which I have just processed in my ClassPrepareEvent listener.
Finally, one issue I have not looked at before (either for this development effort, or in my previous development in this area) -- what happens when a class is unloaded, especially a class on which you have registered breakpoint requests. For example, will a registered breakpoint request prevent a class from being unloaded? Do you care about a stranded breakpoint request if the class isn't even loaded? (Answer: yes, I suppose, if it gets reloaded and you no longer have a valid breakpoint request for it). JDI does have a ClassUnloadEvent, for which you can also register a listener. As I said, I have not dealt with this (possible) issue, having never seen a target class get unloaded before, but it's good to know "there's an API for that".
Follow link for more details

Hotswap/DCEVM doesn't work in Intellij IDEA (Community Version)

I have troubles in making use of the hotswap function in Intellij IDEA Community Version. Mine is v 14.1.4.
Each time after I fired off debugging and change the java code, I have already click rebuild project and press "Yes" on confirming reload classes. Intellij reports that changed classes are reloaded, but the application outcome is the same as before. I'm just trying the simplest Java application (i.e. not in scenarios like Tomcat, applet etc) with stuffs simply like System.out.println, string concats etc. What I've changed during debug mode is just method body codes, but not the method signature/name. I can't get it.
In Eclipse I just directly change the code and press save, then it just works.
What went wrong?
(Remarks:
In fact I'm attempting to use DCEVM which makes structure change possible (e.g. change class name, method name, add methods etc), thought that it would solve the problem of the hotswap problem found in Intellij. Needless to say, it didn't work.
In eclipse, I succeed in using DCEVM and can change the method names during debugging.
I further try hotswap-agent and it still didn't work; I've come across an article saying that the IDE must JDPA-connect to the JVM thru port 5000, but no matter how I tried, Intellij console shows that it is still connecting thru a random port (51018 below):
"C:\Program Files\Java\jdk1.8.0_60\bin\java" -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:51018...."
Connected to the target VM, address: '127.0.0.1:51018', transport: 'socket'
Is it possible to force it to connect thru one specific port?
Adding the DEBUG_OPT environment variable in the Run/Debug Config doesn't work)
Found out that it is Intellij's by-design behaviour after finding one feedback from Jetbrains to an issue request:
In other words, the problem is related to how I test out the hotswapping:
public class Main {
// /*
public static String getName() {
return "James"; // <=== (2)
}
//*/
public static void main(String[] args) {
System.out.println("Hello " + getName()); // <=== (1)
}
}
As Intellij's behaviour is that "the old code is still used until the VM exits the obsolete stack frame" (a different behaviour comparing to Eclipse), if you change "Hello" to "Bye" at (1), the new code will never be executed - the new code can be executed again only when main() is called the second time, which is impossible as the application is terminated already
If it is (2) that is changed (say, replacing "James" w/ "Sean") instead of (1), during the time when the execution cursor is being stopped by a breakpoint placed at (1) (therefore haven't entered to getName() yet), and you reload the class, you will get the new code being run (printing "Sean")
DCEVM worked perfectly too, using the same way to test the hotswapping
You can also use "drop frame" in the stack trace window to make the current statement roll back to the method's beginning (except main()) - in fact it's the same behaviour in Eclipse.

slow (JavaFX) code even after reseting the repository

I just faced a strange behavior and I can't even say if it is a JavaFX specific problem, Eclipse problem or even where to start fixing first.
But first things first: I'm writing a JavaFX application (Eclipse Kepler/ Java 1.7), containing some extended ListViews. The program takes about 1sec to load.
The extended ListViews look something like that:
public class NewList<T extends Obj> extends ListView<T>{
public NewList(){
// addEventHandler(KeyEvent.KEY_RELEASED, new EventHandler<KeyEvent>(){
//
// #Override
// public void handle(KeyEvent arg0) {
// if(arg0.getText().equals(KeyCode.DELETE)){
// getItems().remove(getSelectionModel().getSelectedItem());
// }
// }
// });
}
}
There are also some MouseEvents (like drag and drop) inside the same constructor, and they are working as expected.
Now I want to add an EventHandler to my extended ListView (see commend in the code above).
The code takes now about 8sec to start aka 8 times longer as normal. To my surprise 90% of the loading time the program is inside the .show() method of my primaryStage (there is just one). After the loading time, the GUI is extreme slow and the cpu usage is on 100%.
Maybe the Handler is implemented wrongly and is doing some strange stuff during the whole time.
I can't find any solution or even comparable problem on the internet....but now the real problem just begun:
When I delete the Handler and run the program again, it will stay slow! So the program is in the same state as before - just still broken! That makes me crazy, because I can't see any logical explanation for that behavior.
What I have already tried:
delete the bin folder inside the repository and build the code again (+reboot)
reset the repository via git
throw half of the code away and started again. At any point it worked again, unfortunately I was not able to reproduce the effect. Then I implemented the Handler again and the problems started from the beginning...
edit: it looks like there goes something wrong during the building process/updating the binarys. I deleted 99% of the code (>5k LOC), then it worked. I copy/pasted the original project back into my workspace and the hole code worked smoothly - even with the Handler on. So I can't imagine a way to produce a minimalistic setup. btw: I'm not allowed to release the complete project folder (university stuff...)
edit2: I' using win7 64bit with java64. other javaFX programs are working (even then grafic intensive oracle samples). I'm not using any JavaFX specific repository setup or builder
Okay, I faced the same problem a few minutes ago and I think I found the source this time.
I'm running my code ALWAYS in debugging mode. To check the EventHandlers condition, I created some breakpoints in Eclipse. I also created a breakpoint at the following line of code (see above for more code)
public void handle(KeyEvent arg0) {
A mouseover over the breakpoint provides the following information:
Multiple markers at this line
Method breakpoint:NewList [Entry] - handle(KeyEvent)
implements:javafx.event.EventHandler .handle
I don't know what is happening here exactly but I think its something like this:
I'm overriding a JavaFX EventHandler Method and the debugger has to check the breakpoint on every single JavaFX interaction/EventHandler call. So Eclipse cant handle the flood of checks in a propper time and all seems to be very slow.
To clear that out: the breakpoint itself does not have to be called at any time, just the existing of it is enough to cause the problems.
Deactivating the breakpoint or running the application in a non-debugging mode will fix all problems. I think it should be a good idea to avoid all entry-breakpoints in any kind of Listener/EventHandler :)

Hotfixing Code running inside Web Container with Groovy

I have a webapp running that has a bug. I know how to fix it in the sources. However I cannot redeploy the app as I would have to take it offline to do so. (At least not right now).
I now want to fix the code "at runtime". Surgery on the living object, so to speak.
The app is implemented in Java and is build on top of Seam. I have added a Groovy Console to the app previous to the last release. (A way to run arbitrary code at runtime)
The normal way of adding behaviour to a class with Groovy would be similar to this:
String.metaClass.foo= { x -> x * x }
println "anything".foo(3)
This code added the method foo to java.lang.String and prints 9. I can do the same thing with classes running inside my webapp container. New instances will thereafter show the same behaviour:
com.my.package.SomeService.metaClass.foo= { x -> x * x }
def someService = new com.my.package.SomeService()
println someService.foo(3)
Works as excpected. All good so far.
My problem is now that the container, the web framework, Seam in this case, has already instantiated and cached the classes that I would like to manipulate (that is change their behaviour to reflect my bug fix).
Ideally this code would work:
com.my.package.SomeService.metaClass.foo= { x -> x * x }
def x = org.jboss.seam.Component.getInstance(com.my.package.SomeService)
println x.foo(3)
However the instantiation of SomeService has already happened and there is no effect.
Thus I need a way to make my changes "sticky". Has the groovy magic gone after my script has been run? Well, after logging out and in again, I can run this piece of code and get the expected result:
def someService = new com.my.package.SomeService()
println someService.foo(3)
So the foo method is still around and it looks like my change has been permanent...
So I guess the question that remains is how to force Seam to re-instantiate all its components and/or how to permanently make the change on all living instances...?
The hotfix is not persistent because the calling code is pure Java, not Groovy.
The Groovy magic in fact stays. But only when called from the groovy environment, that is through other groovy code.
Turns out that in a Java environment, the "Keyhole Surgery Pattern", as coined by Dierk König is only usable to change data at runtime, not code. The full power of the pattern is only accessible in a pure Groovy environment.
Not Groovy, but an alternative approach that works - as long as you don't change / add / remove and method signatures - is to set the Server in debug mode and use Java Hot Code Replacement functionality. Most IDE's support this. The changes are permanent and applied to instantiated components as well.
Requires of course that the app server is already configured with the a debug console or allows to enable it after the start.

Categories