Skip to content

Commit 2e30239

Browse files
testforstephenJinbo Wang
andauthored
Improve the HCR workflow (#335)
* Improve the HCR workflow Signed-off-by: Jinbo Wang <[email protected]> * refine the error message Signed-off-by: Jinbo Wang <[email protected]> Co-authored-by: Jinbo Wang <[email protected]>
1 parent 8de2814 commit 2e30239

File tree

4 files changed

+44
-11
lines changed

4 files changed

+44
-11
lines changed

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ErrorCode.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ public enum ErrorCode {
3434
COMPLETIONS_FAILURE(1017),
3535
EXCEPTION_INFO_FAILURE(1018),
3636
EVALUATION_COMPILE_ERROR(2001),
37-
EVALUATE_NOT_SUSPENDED_THREAD(2002);
37+
EVALUATE_NOT_SUSPENDED_THREAD(2002),
38+
HCR_FAILURE(3001);
3839

3940
private int id;
4041

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/HotCodeReplaceHandler.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,12 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
5959

6060
IHotCodeReplaceProvider provider = context.getProvider(IHotCodeReplaceProvider.class);
6161

62-
return provider.redefineClasses().thenApply(classNames -> {
62+
return provider.redefineClasses().thenCompose(classNames -> {
6363
response.body = new Responses.RedefineClassesResponse(classNames.toArray(new String[0]));
64+
return CompletableFuture.completedFuture(response);
65+
}).exceptionally(ex -> {
66+
String errorMessage = ex.getCause() != null ? ex.getCause().getMessage() : ex.getMessage();
67+
response.body = new Responses.RedefineClassesResponse(new String[0], errorMessage);
6468
return response;
6569
});
6670
}

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Responses.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,12 +299,21 @@ public ExceptionInfoResponse(String exceptionId, String description, ExceptionBr
299299

300300
public static class RedefineClassesResponse extends ResponseBody {
301301
public String[] changedClasses = new String[0];
302+
public String errorMessage = null;
302303

303304
/**
304305
* Constructor.
305306
*/
306307
public RedefineClassesResponse(String[] changedClasses) {
308+
this(changedClasses, null);
309+
}
310+
311+
/**
312+
* Constructor.
313+
*/
314+
public RedefineClassesResponse(String[] changedClasses, String errorMessage) {
307315
this.changedClasses = changedClasses;
316+
this.errorMessage = errorMessage;
308317
}
309318
}
310319
}

com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JavaHotCodeReplaceProvider.java

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
import java.util.Collections;
2727
import java.util.HashMap;
2828
import java.util.Iterator;
29+
import java.util.LinkedHashSet;
2930
import java.util.List;
3031
import java.util.Map;
32+
import java.util.Set;
3133
import java.util.concurrent.CompletableFuture;
3234
import java.util.function.Consumer;
3335
import java.util.logging.Level;
@@ -53,13 +55,16 @@
5355
import org.eclipse.jdt.core.util.IClassFileReader;
5456
import org.eclipse.jdt.core.util.ISourceAttribute;
5557
import org.eclipse.jdt.internal.core.util.Util;
58+
import org.eclipse.jdt.ls.core.internal.JobHelpers;
5659

5760
import com.microsoft.java.debug.core.Configuration;
5861
import com.microsoft.java.debug.core.DebugException;
5962
import com.microsoft.java.debug.core.DebugSettings;
6063
import com.microsoft.java.debug.core.DebugUtility;
6164
import com.microsoft.java.debug.core.IDebugSession;
6265
import com.microsoft.java.debug.core.StackFrameUtility;
66+
import com.microsoft.java.debug.core.adapter.AdapterUtils;
67+
import com.microsoft.java.debug.core.adapter.ErrorCode;
6368
import com.microsoft.java.debug.core.adapter.HotCodeReplaceEvent;
6469
import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
6570
import com.microsoft.java.debug.core.adapter.IHotCodeReplaceProvider;
@@ -96,9 +101,9 @@ public class JavaHotCodeReplaceProvider implements IHotCodeReplaceProvider, IRes
96101

97102
private PublishSubject<HotCodeReplaceEvent> eventSubject = PublishSubject.<HotCodeReplaceEvent>create();
98103

99-
private List<IResource> deltaResources = new ArrayList<>();
104+
private Set<IResource> deltaResources = new LinkedHashSet<>();
100105

101-
private List<String> deltaClassNames = new ArrayList<>();
106+
private Set<String> deltaClassNames = new LinkedHashSet<>();
102107

103108
/**
104109
* Visitor for resource deltas.
@@ -300,14 +305,23 @@ public void onClassRedefined(Consumer<List<String>> consumer) {
300305

301306
@Override
302307
public CompletableFuture<List<String>> redefineClasses() {
308+
JobHelpers.waitForBuildJobs(10 * 1000);
303309
return CompletableFuture.supplyAsync(() -> {
304310
List<String> classNames = new ArrayList<>();
311+
List<IResource> resources = new ArrayList<>();
312+
String errorMessage = null;
305313
synchronized (this) {
306314
classNames.addAll(deltaClassNames);
307-
doHotCodeReplace(deltaResources, deltaClassNames);
315+
resources.addAll(deltaResources);
308316
deltaResources.clear();
309317
deltaClassNames.clear();
318+
errorMessage = doHotCodeReplace(resources, classNames);
310319
}
320+
321+
if (!classNames.isEmpty() && errorMessage != null) {
322+
throw AdapterUtils.createCompletionException(errorMessage, ErrorCode.HCR_FAILURE);
323+
}
324+
311325
return classNames;
312326
});
313327
}
@@ -325,27 +339,29 @@ private void publishEvent(HotCodeReplaceEvent.EventType type, String message, Ob
325339
eventSubject.onNext(new HotCodeReplaceEvent(type, message, data));
326340
}
327341

328-
private void doHotCodeReplace(List<IResource> resourcesToReplace, List<String> qualifiedNamesToReplace) {
342+
private String doHotCodeReplace(List<IResource> resourcesToReplace, List<String> qualifiedNamesToReplace) {
329343
if (context == null || currentDebugSession == null) {
330-
return;
344+
return null;
331345
}
332346

333347
if (resourcesToReplace == null || qualifiedNamesToReplace == null || qualifiedNamesToReplace.isEmpty()
334348
|| resourcesToReplace.isEmpty()) {
335-
return;
349+
return null;
336350
}
337351

338352
filterNotLoadedTypes(resourcesToReplace, qualifiedNamesToReplace);
339353
if (qualifiedNamesToReplace.isEmpty()) {
340-
return;
354+
return null;
341355
// If none of the changed types are loaded, do nothing.
342356
}
343357

344358
// Not supported scenario:
345359
if (!currentDebugSession.getVM().canRedefineClasses()) {
346-
return;
360+
publishEvent(HotCodeReplaceEvent.EventType.ERROR, "JVM doesn't support hot reload classes");
361+
return "JVM doesn't support hot reload classes";
347362
}
348363

364+
String errorMessage = null;
349365
publishEvent(HotCodeReplaceEvent.EventType.STARTING, "Start hot code replacement procedure...");
350366

351367
try {
@@ -367,6 +383,7 @@ private void doHotCodeReplace(List<IResource> resourcesToReplace, List<String> q
367383

368384
if (containsObsoleteMethods()) {
369385
publishEvent(HotCodeReplaceEvent.EventType.ERROR, "JVM contains obsolete methods");
386+
errorMessage = "JVM contains obsolete methods";
370387
}
371388

372389
if (currentDebugSession.getVM().canPopFrames() && framesPopped) {
@@ -376,11 +393,13 @@ private void doHotCodeReplace(List<IResource> resourcesToReplace, List<String> q
376393
}
377394
} catch (DebugException e) {
378395
logger.log(Level.SEVERE, "Failed to complete hot code replace: " + e.getMessage(), e);
396+
errorMessage = e.getMessage();
379397
} finally {
380398
publishEvent(HotCodeReplaceEvent.EventType.END, "Completed hot code replace", qualifiedNamesToReplace);
399+
threadFrameMap.clear();
381400
}
382401

383-
threadFrameMap.clear();
402+
return errorMessage;
384403
}
385404

386405
private void filterNotLoadedTypes(List<IResource> resources, List<String> qualifiedNames) {

0 commit comments

Comments
 (0)