2525import org .apache .commons .lang3 .StringUtils ;
2626
2727import com .sun .jdi .Location ;
28+ import com .sun .jdi .Method ;
2829import com .sun .jdi .ObjectCollectedException ;
2930import com .sun .jdi .ThreadReference ;
3031import com .sun .jdi .VMDisconnectedException ;
3536import com .sun .jdi .connect .IllegalConnectorArgumentsException ;
3637import com .sun .jdi .connect .LaunchingConnector ;
3738import com .sun .jdi .connect .VMStartException ;
39+ import com .sun .jdi .event .MethodEntryEvent ;
3840import com .sun .jdi .event .StepEvent ;
3941import com .sun .jdi .request .EventRequest ;
42+ import com .sun .jdi .request .EventRequestManager ;
43+ import com .sun .jdi .request .MethodEntryRequest ;
4044import com .sun .jdi .request .StepRequest ;
4145
4246public class DebugUtility {
@@ -240,7 +244,7 @@ private static CompletableFuture<Location> step(ThreadReference thread, IEventHu
240244 .subscribe (debugEvent -> {
241245 StepEvent event = (StepEvent ) debugEvent .event ;
242246 future .complete (event .location ());
243- thread .virtualMachine ().eventRequestManager (). deleteEventRequest ( request );
247+ deleteEventRequestSafely ( thread .virtualMachine ().eventRequestManager (), request );
244248 });
245249 request .setSuspendPolicy (EventRequest .SUSPEND_EVENT_THREAD );
246250 request .addCountFilter (1 );
@@ -251,6 +255,40 @@ private static CompletableFuture<Location> step(ThreadReference thread, IEventHu
251255 return future ;
252256 }
253257
258+ /**
259+ * Suspend the main thread when the program enters the main method of the specified main class.
260+ * @param debugSession
261+ * the debug session.
262+ * @param mainClass
263+ * the fully qualified name of the main class.
264+ * @return
265+ * a {@link CompletableFuture} that contains the suspended main thread id.
266+ */
267+ public static CompletableFuture <Long > stopOnEntry (IDebugSession debugSession , String mainClass ) {
268+ CompletableFuture <Long > future = new CompletableFuture <>();
269+
270+ EventRequestManager manager = debugSession .getVM ().eventRequestManager ();
271+ MethodEntryRequest request = manager .createMethodEntryRequest ();
272+ request .addClassFilter (mainClass );
273+ request .setSuspendPolicy (EventRequest .SUSPEND_EVENT_THREAD );
274+
275+ debugSession .getEventHub ().events ().filter (debugEvent -> {
276+ return debugEvent .event instanceof MethodEntryEvent && request .equals (debugEvent .event .request ());
277+ }).subscribe (debugEvent -> {
278+ Method method = ((MethodEntryEvent ) debugEvent .event ).method ();
279+ if (method .isPublic () && method .isStatic () && method .name ().equals ("main" )
280+ && method .signature ().equals ("([Ljava/lang/String;)V" )) {
281+ deleteEventRequestSafely (debugSession .getVM ().eventRequestManager (), request );
282+ debugEvent .shouldResume = false ;
283+ ThreadReference bpThread = ((MethodEntryEvent ) debugEvent .event ).thread ();
284+ future .complete (bpThread .uniqueID ());
285+ }
286+ });
287+ request .enable ();
288+
289+ return future ;
290+ }
291+
254292 /**
255293 * Get the ThreadReference instance by the thread id.
256294 * @param debugSession
@@ -312,6 +350,36 @@ public static void resumeThread(ThreadReference thread) {
312350 }
313351 }
314352
353+ /**
354+ * Remove the event request from the vm. If the vm has terminated, do nothing.
355+ * @param eventManager
356+ * The event request manager.
357+ * @param request
358+ * The target event request.
359+ */
360+ public static void deleteEventRequestSafely (EventRequestManager eventManager , EventRequest request ) {
361+ try {
362+ eventManager .deleteEventRequest (request );
363+ } catch (VMDisconnectedException ex ) {
364+ // ignore.
365+ }
366+ }
367+
368+ /**
369+ * Remove the event request list from the vm. If the vm has terminated, do nothing.
370+ * @param eventManager
371+ * The event request manager.
372+ * @param requests
373+ * The target event request list.
374+ */
375+ public static void deleteEventRequestSafely (EventRequestManager eventManager , List <EventRequest > requests ) {
376+ try {
377+ eventManager .deleteEventRequests (requests );
378+ } catch (VMDisconnectedException ex ) {
379+ // ignore.
380+ }
381+ }
382+
315383 /**
316384 * Encode an string array to a string as the follows.
317385 *
0 commit comments