How to script the java debugger command-line tool (jdb)?
You may be able to use JRuby to drive your own debugger via the JPDA API.
Where can I find the jdb (java debugger) implementation? Who develops/maintains it?
I believe Oracle develops and maintains the standalone Java debugger, jdb.
As for the jdb source code:
Download "JDK 8 Demos and Samples" from the Java SE Development Kit 8 Downloads page
Unpack the jdk file and then unpack jdk1.8.0_101/demo/jpda/examples.jar
Then navigate to jdk1.8.0_101/demo/jpda/com/sun/tools/example/debug/tty/TTY.java
Or, if you download openjdk or any other jdk implementation, there should be a zip file in its base directory: java-1.8.0-openjdk/src.zip. if you unzip this file you will find TTY.java here: java-1.8.0-openjdk/com/sun/tools/example/debug/tty/TTY.java
I believe TTY.java is what you are looking for.
What are Java command line options to set to allow JVM to be remotely debugged?
I have this article bookmarked on setting this up for Java 5 and below.
Basically run it with:
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044
For Java 5 and above, run it with:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=1044
If you want Java to wait for you to connect before executing the application, replace suspend=n
with suspend=y
.
Enable java remote debug in code
The address property specifies host (optionally) and port (only the port if host is left out). So address=5005
specifies the port 5005 in your case. If you want your program to wait until you connect your debugger, switch suspend=n
to suspend=y
.
Edit:
Maybe I misunderstood your question. In case you want to enable debugging programmatically, this won't be possible as the debugging facility JPDA is not exposing a Java API nor any other way to start and stop it programmatically.
Debugging in Maven?
Just as Brian said, you can use remote debugging:
mvn exec:exec -Dexec.executable="java" -Dexec.args="-classpath %classpath -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044 com.mycompany.app.App"
Then in your eclipse, you can use remote debugging and attach the debugger to localhost:1044.
Debugging a Java program running from Tomcat (JSP)
An alternative solution that may be easier to use than hooking a debugger to Tomcat:
First, take a look at the call stack. At the bottom, you'll see your class named org.sgrp.singer.filters.SingerLoginFilter
. The problem lies here, at line 128 of method doFilter
.
The first line says org.apache.jasper.JasperException: java.lang.NullPointerException
. That means you've used an object whose value is null at line 128 of mentioned class.
Check out that code to find out what could be wrong. Also, add some print/logging statements to your code.
Debugging should be your last resort. You can gather a lot of information just by looking at your stack trace.
Clojure and the Java Debugger
It is possible to debug Clojure bytecode with jdb
but it's not very practical (read tedious) and maybe some information is missing to map from the compiled bytecode to the original source files, but I did an small test to verify it works (at least partially, setting breakpoints when entering a method instead).
I'll create a new Clojure project with Leiningen: lein new app demo
. Now, I'll update the file src/demo/core.clj
with the following contents:
(ns demo.core
(:gen-class))
(defn x2 [n]
(println "Doubling" n)
(let [x (* n 2)]
x))
(defn -main
[& args]
(let [xs (mapv x2 (range 10))]
(doseq [x xs]
(println x))))
Now, let's run lein uberjar
to compile the sources to bytecode:
$ lein uberjar
Compiling demo.core
Created /tmp/demo/target/uberjar/demo-0.1.0-SNAPSHOT.jar
Created /tmp/demo/target/uberjar/demo-0.1.0-SNAPSHOT-standalone.jar
I'll inspect the files generated under the target
directory:
$ tree target
target
└── uberjar
├── classes
│ ├── demo
│ │ ├── core$fn__173.class
│ │ ├── core$loading__6721__auto____171.class
│ │ ├── core$_main.class
│ │ ├── core$x2.class
│ │ ├── core.class
│ │ └── core__init.class
...
We can see that the compiler uses inner classes (those with core$
in their name) and our function x2
is compiled to a class.
In order to run the Clojure in jdb
, we need to construct a classpath that contains our code, the Clojure runtime and, in Clojure 1.10+ also some dependencies of the Clojure runtime (Spec). You can borrow most of the routes by looking at the output of lein classpath
:
$ lein classpath
/tmp/demo/test:/tmp/demo/src:/tmp/demo/dev-resources:/tmp/demo/resources:/tmp/demo/target/default/classes:/home/denis/.m2/repository/org/clojure/clojure/1.10.1/clojure-1.10.1.jar:/home/denis/.m2/repository/org/clojure/spec.alpha/0.2.176/spec.alpha-0.2.176.jar:/home/denis/.m2/repository/org/clojure/core.specs.alpha/0.2.44/core.specs.alpha-0.2.44.jar:/home/denis/.m2/repository/nrepl/nrepl/0.7.0/nrepl-0.7.0.jar:/home/denis/.m2/repository/clojure-complete/clojure-complete/0.2.5/clojure-complete-0.2.5.jar
I will remove some of these JARs and build my classpath to run jdb
with the class demo.core
which I know is the entry point:
$ jdb -classpath target/uberjar/classes:/home/denis/.m2/repository/org/clojure/clojure/1.10.1/clojure-1.10.1.jar:/home/denis/.m2/repository/org/clojure/spec.alpha/0.2.176/spec.alpha-0.2.176.jar:/home/denis/.m2/repository/org/clojure/core.specs.alpha/0.2.44/core.specs.alpha-0.2.44.jar demo.core
Before running jdb
, I want to put a breakpoint somewhere to validate. The x2
function should be a good starting point, but we need to inspect the bytecode a little to understand where in the bytecode to put the breakpoint. Using javap
will give us some clues:
$ javap -l target/uberjar/classes/demo/core\$x2.class
Compiled from "core.clj"
public final class demo.core$x2 extends clojure.lang.AFunction {
public demo.core$x2();
LineNumberTable:
line 4: 0
public static java.lang.Object invokeStatic(java.lang.Object);
LineNumberTable:
line 4: 0
line 6: 26
LocalVariableTable:
Start Length Slot Name Signature
30 3 1 x Ljava/lang/Object;
0 33 0 n Ljava/lang/Object;
public java.lang.Object invoke(java.lang.Object);
LineNumberTable:
line 4: 3
public static {};
LineNumberTable:
line 4: 0
}
From the above, I'll make a note to set a breakpoint in the method demo.core$x2.invokeStatic
which is notable because it has local variables. Now we start jdb
with the line from before:
$ jdb -classpath target/uberjar/classes:/home/denis/.m2/repository/org/clojure/clojure/1.10.1/clojure-1.10.1.jar:/home/denis/.m2/repository/org/clojure/spec.alpha/0.2.176/spec.alpha-0.2.176.jar:/home/denis/.m2/repository/org/clojure/core.specs.alpha/0.2.44/core.specs.alpha-0.2.44.jar demo.core
Initializing jdb ...
>
In the prompt, I'll tell jdb
to stop in the relevant method with stop in demo.core$x2.invokeStatic
. You can use the rest of the jdb
commands to step, continue and display local values as in the following session:
> stop in demo.core$x2.invokeStatic
Deferring breakpoint demo.core$x2.invokeStatic.
It will be set after the class is loaded.
> run
run demo.core
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
>
VM Started: Set deferred breakpoint demo.core$x2.invokeStatic
Breakpoint hit: "thread=main", demo.core$x2.invokeStatic(), line=4 bci=0
main[1] locals
Method arguments:
n = instance of java.lang.Long(id=2743)
main[1] print n
n = "0"
main[1] cont
> Doubling 0
Breakpoint hit: "thread=main", demo.core$x2.invokeStatic(), line=4 bci=0
main[1] locals
Method arguments:
n = instance of java.lang.Long(id=2749)
Local variables:
main[1] print n
n = "1"
clear demo.core$x2.invokeStatic
Removed: breakpoint demo.core$x2.invokeStatic
main[1] cont
...
> Doubling 2
...
Doubling 9
0
2
4
...
16
18
The application exited
During development, this style is not comparable to the interactive experience of submitting code to a running REPL session and getting instant feedback, so it's not practical (except for very specific scenarios).
I think this is also the type of experience we had in a former team when we debugged Clojure apps vith JDWP in Eclipse, but after a while it becomes hard to track what methods in the Java bytecode map to which functions in your Java code.
How to debug a JUnit test case with jdb?
Sorry folks, I'm new to all of this and I made a silly mistake. I forgot to use the -g command when calling javac to generate my test case class file. It works now.
Related Topics
Serializing and De-Serializing Android.Graphics.Bitmap in Java
Urlconnection Getcontentlength() Is Returning a Negative Value
Efficiency of Searching Using Wherearraycontains
Why Does Bitmapfactory.Decodebytearray Return Null
How to Update One Field from All Documents Using Pojo in Firestore
I Cant See Any Firebaserecycleradapter Items on My Layout
Connectiontimeout Versus Sockettimeout
What Is the Simplest Way to Reverse an Arraylist
Android: How to Hide Actionbar on Certain Activities
Passing Function as a Parameter in Java
Curly Braces in "New" Expression? (E.G. "New Myclass() { ... }")
Java.Lang.Noclassdeffounderror: Com.Google.Ads.Adview
String-Date Conversion with Nanoseconds