37
37
public class Breakpoint implements IBreakpoint {
38
38
private VirtualMachine vm = null ;
39
39
private IEventHub eventHub = null ;
40
- private String className = null ;
41
- private int lineNumber = 0 ;
40
+ private JavaBreakpointLocation sourceLocation = null ;
42
41
private int hitCount = 0 ;
43
42
private String condition = null ;
44
43
private String logMessage = null ;
45
44
private HashMap <Object , Object > propertyMap = new HashMap <>();
46
- private String methodSignature = null ;
47
45
48
46
private boolean async = false ;
49
47
@@ -56,21 +54,37 @@ public class Breakpoint implements IBreakpoint {
56
54
}
57
55
58
56
Breakpoint (VirtualMachine vm , IEventHub eventHub , String className , int lineNumber , int hitCount , String condition ) {
57
+ this (vm , eventHub , className , lineNumber , hitCount , condition , null );
58
+ }
59
+
60
+ Breakpoint (VirtualMachine vm , IEventHub eventHub , String className , int lineNumber , int hitCount , String condition , String logMessage ) {
59
61
this .vm = vm ;
60
62
this .eventHub = eventHub ;
63
+ String contextClass = className ;
64
+ String methodName = null ;
65
+ String methodSignature = null ;
61
66
if (className != null && className .contains ("#" )) {
62
- this . className = className .substring (0 , className .indexOf ("#" ));
63
- this . methodSignature = className .substring (className .indexOf ("#" ) + 1 );
64
- } else {
65
- this . className = className ;
67
+ contextClass = className .substring (0 , className .indexOf ("#" ));
68
+ String [] methodInfo = className .substring (className .indexOf ("#" ) + 1 ). split ( "#" );
69
+ methodName = methodInfo [ 0 ];
70
+ methodSignature = methodInfo [ 1 ] ;
66
71
}
67
- this .lineNumber = lineNumber ;
72
+
73
+ this .sourceLocation = new JavaBreakpointLocation (lineNumber , -1 );
74
+ this .sourceLocation .setClassName (contextClass );
75
+ this .sourceLocation .setMethodName (methodName );
76
+ this .sourceLocation .setMethodSignature (methodSignature );
68
77
this .hitCount = hitCount ;
69
78
this .condition = condition ;
79
+ this .logMessage = logMessage ;
70
80
}
71
81
72
- Breakpoint (VirtualMachine vm , IEventHub eventHub , String className , int lineNumber , int hitCount , String condition , String logMessage ) {
73
- this (vm , eventHub , className , lineNumber , hitCount , condition );
82
+ Breakpoint (VirtualMachine vm , IEventHub eventHub , JavaBreakpointLocation sourceLocation , int hitCount , String condition , String logMessage ) {
83
+ this .vm = vm ;
84
+ this .eventHub = eventHub ;
85
+ this .sourceLocation = sourceLocation ;
86
+ this .hitCount = hitCount ;
87
+ this .condition = condition ;
74
88
this .logMessage = logMessage ;
75
89
}
76
90
@@ -104,14 +118,24 @@ public void close() throws Exception {
104
118
}
105
119
106
120
// IBreakpoint
121
+ @ Override
122
+ public JavaBreakpointLocation sourceLocation () {
123
+ return this .sourceLocation ;
124
+ }
125
+
107
126
@ Override
108
127
public String className () {
109
- return className ;
128
+ return this . sourceLocation . className () ;
110
129
}
111
130
112
131
@ Override
113
132
public int getLineNumber () {
114
- return lineNumber ;
133
+ return this .sourceLocation .lineNumber ();
134
+ }
135
+
136
+ @ Override
137
+ public int getColumnNumber () {
138
+ return this .sourceLocation .columnNumber ();
115
139
}
116
140
117
141
@ Override
@@ -120,20 +144,20 @@ public String getCondition() {
120
144
}
121
145
122
146
@ Override
123
- public boolean equals (Object obj ) {
124
- if (!(obj instanceof Breakpoint )) {
125
- return super .equals (obj );
126
- }
127
-
128
- Breakpoint breakpoint = (Breakpoint ) obj ;
129
- return Objects .equals (this .className (), breakpoint .className ())
130
- && this .getLineNumber () == breakpoint .getLineNumber ()
131
- && Objects .equals (this .methodSignature , breakpoint .methodSignature );
147
+ public int hashCode () {
148
+ return Objects .hash (sourceLocation );
132
149
}
133
150
134
151
@ Override
135
- public int hashCode () {
136
- return Objects .hash (this .className , this .lineNumber , this .methodSignature );
152
+ public boolean equals (Object obj ) {
153
+ if (this == obj ) {
154
+ return true ;
155
+ }
156
+ if (!(obj instanceof Breakpoint )) {
157
+ return false ;
158
+ }
159
+ Breakpoint other = (Breakpoint ) obj ;
160
+ return Objects .equals (sourceLocation , other .sourceLocation );
137
161
}
138
162
139
163
@ Override
@@ -149,6 +173,7 @@ public void setHitCount(int hitCount) {
149
173
.filter (request -> request instanceof BreakpointRequest )
150
174
.subscribe (request -> {
151
175
request .addCountFilter (hitCount );
176
+ request .disable ();
152
177
request .enable ();
153
178
});
154
179
}
@@ -183,13 +208,13 @@ public CompletableFuture<IBreakpoint> install() {
183
208
// It's possible that different class loaders create new class with the same name.
184
209
// Here to listen to future class prepare events to handle such case.
185
210
ClassPrepareRequest classPrepareRequest = vm .eventRequestManager ().createClassPrepareRequest ();
186
- classPrepareRequest .addClassFilter (className );
211
+ classPrepareRequest .addClassFilter (className () );
187
212
classPrepareRequest .enable ();
188
213
requests .add (classPrepareRequest );
189
214
190
215
// Local types also needs to be handled
191
216
ClassPrepareRequest localClassPrepareRequest = vm .eventRequestManager ().createClassPrepareRequest ();
192
- localClassPrepareRequest .addClassFilter (className + "$*" );
217
+ localClassPrepareRequest .addClassFilter (className () + "$*" );
193
218
localClassPrepareRequest .enable ();
194
219
requests .add (localClassPrepareRequest );
195
220
@@ -202,7 +227,7 @@ public CompletableFuture<IBreakpoint> install() {
202
227
.subscribe (debugEvent -> {
203
228
ClassPrepareEvent event = (ClassPrepareEvent ) debugEvent .event ;
204
229
List <BreakpointRequest > newRequests = AsyncJdwpUtils .await (
205
- createBreakpointRequests (event .referenceType (), lineNumber , hitCount , false )
230
+ createBreakpointRequests (event .referenceType (), getLineNumber () , hitCount , false )
206
231
);
207
232
requests .addAll (newRequests );
208
233
if (!newRequests .isEmpty () && !future .isDone ()) {
@@ -213,8 +238,8 @@ public CompletableFuture<IBreakpoint> install() {
213
238
subscriptions .add (subscription );
214
239
215
240
Runnable resolveRequestsFromExistingClasses = () -> {
216
- List <ReferenceType > refTypes = vm .classesByName (className );
217
- createBreakpointRequests (refTypes , lineNumber , hitCount , true )
241
+ List <ReferenceType > refTypes = vm .classesByName (className () );
242
+ createBreakpointRequests (refTypes , getLineNumber () , hitCount , true )
218
243
.whenComplete ((newRequests , ex ) -> {
219
244
if (ex != null ) {
220
245
return ;
@@ -281,14 +306,13 @@ private CompletableFuture<List<Location>> collectLocations(ReferenceType refType
281
306
});
282
307
}
283
308
284
- private CompletableFuture <List <Location >> collectLocations (List <ReferenceType > refTypes , String nameAndSignature ) {
285
- String [] segments = nameAndSignature .split ("#" );
309
+ private CompletableFuture <List <Location >> collectLocations (List <ReferenceType > refTypes , String methodName , String methodSiguature ) {
286
310
List <CompletableFuture <Location >> futures = new ArrayList <>();
287
311
for (ReferenceType refType : refTypes ) {
288
312
if (async ()) {
289
- futures .add (AsyncJdwpUtils .supplyAsync (() -> findMethodLocaiton (refType , segments [ 0 ], segments [ 1 ] )));
313
+ futures .add (AsyncJdwpUtils .supplyAsync (() -> findMethodLocaiton (refType , methodName , methodSiguature )));
290
314
} else {
291
- futures .add (CompletableFuture .completedFuture (findMethodLocaiton (refType , segments [ 0 ], segments [ 1 ] )));
315
+ futures .add (CompletableFuture .completedFuture (findMethodLocaiton (refType , methodName , methodSiguature )));
292
316
}
293
317
}
294
318
@@ -329,10 +353,22 @@ private CompletableFuture<List<BreakpointRequest>> createBreakpointRequests(Refe
329
353
private CompletableFuture <List <BreakpointRequest >> createBreakpointRequests (List <ReferenceType > refTypes , int lineNumber ,
330
354
int hitCount , boolean includeNestedTypes ) {
331
355
CompletableFuture <List <Location >> locationsFuture ;
332
- if (this .methodSignature != null ) {
333
- locationsFuture = collectLocations (refTypes , this .methodSignature );
356
+ if (this .sourceLocation . methodName () != null ) {
357
+ locationsFuture = collectLocations (refTypes , this .sourceLocation . methodName (), this . sourceLocation . methodSignature () );
334
358
} else {
335
- locationsFuture = collectLocations (refTypes , lineNumber , includeNestedTypes );
359
+ locationsFuture = collectLocations (refTypes , lineNumber , includeNestedTypes ).thenApply ((locations ) -> {
360
+ if (locations .isEmpty ()) {
361
+ return locations ;
362
+ }
363
+
364
+ /**
365
+ * For a line breakpoint, we default to breaking at the first location
366
+ * of the line. If you want to break at other locations on the same line,
367
+ * you can add an inline breakpoint based on the locations returned by
368
+ * the BreakpointLocation request.
369
+ */
370
+ return Arrays .asList (locations .get (0 ));
371
+ });
336
372
}
337
373
338
374
return locationsFuture .thenCompose ((locations ) -> {
@@ -389,11 +425,11 @@ private CompletableFuture<List<BreakpointRequest>> createBreakpointRequests(List
389
425
}
390
426
391
427
private Object computeRequestType () {
392
- if (this .methodSignature == null ) {
428
+ if (this .sourceLocation . methodName () == null ) {
393
429
return IBreakpoint .REQUEST_TYPE_LINE ;
394
430
}
395
431
396
- if (this .methodSignature .startsWith ("lambda$" )) {
432
+ if (this .sourceLocation . methodName () .startsWith ("lambda$" )) {
397
433
return IBreakpoint .REQUEST_TYPE_LAMBDA ;
398
434
} else {
399
435
return IBreakpoint .REQUEST_TYPE_METHOD ;
0 commit comments