1616import java .util .ArrayList ;
1717import java .util .List ;
1818
19+ import org .apache .commons .lang3 .StringUtils ;
20+
1921import com .sun .jdi .ObjectCollectedException ;
22+ import com .sun .jdi .ReferenceType ;
2023import com .sun .jdi .ThreadReference ;
24+ import com .sun .jdi .VMDisconnectedException ;
2125import com .sun .jdi .VirtualMachine ;
26+ import com .sun .jdi .event .ClassPrepareEvent ;
27+ import com .sun .jdi .request .ClassPrepareRequest ;
2228import com .sun .jdi .request .EventRequest ;
2329import com .sun .jdi .request .EventRequestManager ;
2430import com .sun .jdi .request .ExceptionRequest ;
2531
32+ import io .reactivex .disposables .Disposable ;
33+
2634public class DebugSession implements IDebugSession {
2735 private VirtualMachine vm ;
2836 private EventHub eventHub = new EventHub ();
37+ private List <EventRequest > eventRequests = new ArrayList <>();
38+ private List <Disposable > subscriptions = new ArrayList <>();
2939
3040 public DebugSession (VirtualMachine virtualMachine ) {
3141 vm = virtualMachine ;
@@ -136,9 +146,27 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught
136146
137147 @ Override
138148 public void setExceptionBreakpoints (boolean notifyCaught , boolean notifyUncaught , String [] classFilters , String [] classExclusionFilters ) {
149+ setExceptionBreakpoints (notifyCaught , notifyUncaught , null , classFilters , classExclusionFilters );
150+ }
151+
152+ @ Override
153+ public void setExceptionBreakpoints (boolean notifyCaught , boolean notifyUncaught , String [] exceptionTypes ,
154+ String [] classFilters , String [] classExclusionFilters ) {
139155 EventRequestManager manager = vm .eventRequestManager ();
140- ArrayList <ExceptionRequest > legacy = new ArrayList <>(manager .exceptionRequests ());
141- manager .deleteEventRequests (legacy );
156+
157+ try {
158+ ArrayList <ExceptionRequest > legacy = new ArrayList <>(manager .exceptionRequests ());
159+ manager .deleteEventRequests (legacy );
160+ manager .deleteEventRequests (eventRequests );
161+ } catch (VMDisconnectedException ex ) {
162+ // ignore since removing breakpoints is meaningless when JVM is terminated.
163+ }
164+ subscriptions .forEach (subscription -> {
165+ subscription .dispose ();
166+ });
167+ subscriptions .clear ();
168+ eventRequests .clear ();
169+
142170 // When no exception breakpoints are requested, no need to create an empty exception request.
143171 if (notifyCaught || notifyUncaught ) {
144172 // from: https://www.javatips.net/api/REPLmode-master/src/jm/mode/replmode/REPLRunner.java
@@ -153,20 +181,48 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught
153181 // a thread to be available, and queries it by calling allThreads().
154182 // See org.eclipse.debug.jdi.tests.AbstractJDITest for the example.
155183
156- // get only the uncaught exceptions
157- ExceptionRequest request = manager .createExceptionRequest (null , notifyCaught , notifyUncaught );
158- request .setSuspendPolicy (EventRequest .SUSPEND_EVENT_THREAD );
159- if (classFilters != null ) {
160- for (String classFilter : classFilters ) {
161- request .addClassFilter (classFilter );
184+ if (exceptionTypes == null || exceptionTypes .length == 0 ) {
185+ ExceptionRequest request = manager .createExceptionRequest (null , notifyCaught , notifyUncaught );
186+ request .setSuspendPolicy (EventRequest .SUSPEND_EVENT_THREAD );
187+ if (classFilters != null ) {
188+ for (String classFilter : classFilters ) {
189+ request .addClassFilter (classFilter );
190+ }
162191 }
192+ if (classExclusionFilters != null ) {
193+ for (String exclusionFilter : classExclusionFilters ) {
194+ request .addClassExclusionFilter (exclusionFilter );
195+ }
196+ }
197+ request .enable ();
198+ return ;
163199 }
164- if (classExclusionFilters != null ) {
165- for (String exclusionFilter : classExclusionFilters ) {
166- request .addClassExclusionFilter (exclusionFilter );
200+
201+ for (String exceptionType : exceptionTypes ) {
202+ if (StringUtils .isBlank (exceptionType )) {
203+ continue ;
204+ }
205+
206+ // register exception breakpoint in the future loaded classes.
207+ ClassPrepareRequest classPrepareRequest = manager .createClassPrepareRequest ();
208+ classPrepareRequest .addClassFilter (exceptionType );
209+ classPrepareRequest .enable ();
210+ eventRequests .add (classPrepareRequest );
211+
212+ Disposable subscription = eventHub .events ()
213+ .filter (debugEvent -> debugEvent .event instanceof ClassPrepareEvent
214+ && eventRequests .contains (debugEvent .event .request ()))
215+ .subscribe (debugEvent -> {
216+ ClassPrepareEvent event = (ClassPrepareEvent ) debugEvent .event ;
217+ createExceptionBreakpoint (event .referenceType (), notifyCaught , notifyUncaught , classFilters , classExclusionFilters );
218+ });
219+ subscriptions .add (subscription );
220+
221+ // register exception breakpoint in the loaded classes.
222+ for (ReferenceType refType : vm .classesByName (exceptionType )) {
223+ createExceptionBreakpoint (refType , notifyCaught , notifyUncaught , classFilters , classExclusionFilters );
167224 }
168225 }
169- request .enable ();
170226 }
171227 }
172228
@@ -195,4 +251,22 @@ public IMethodBreakpoint createFunctionBreakpoint(String className, String funct
195251 int hitCount ) {
196252 return new MethodBreakpoint (vm , this .getEventHub (), className , functionName , condition , hitCount );
197253 }
254+
255+ private void createExceptionBreakpoint (ReferenceType refType , boolean notifyCaught , boolean notifyUncaught ,
256+ String [] classFilters , String [] classExclusionFilters ) {
257+ EventRequestManager manager = vm .eventRequestManager ();
258+ ExceptionRequest request = manager .createExceptionRequest (refType , notifyCaught , notifyUncaught );
259+ request .setSuspendPolicy (EventRequest .SUSPEND_EVENT_THREAD );
260+ if (classFilters != null ) {
261+ for (String classFilter : classFilters ) {
262+ request .addClassFilter (classFilter );
263+ }
264+ }
265+ if (classExclusionFilters != null ) {
266+ for (String exclusionFilter : classExclusionFilters ) {
267+ request .addClassExclusionFilter (exclusionFilter );
268+ }
269+ }
270+ request .enable ();
271+ }
198272}
0 commit comments