microsoft / vscode-java-debug

Java Debugger for Visual Studio Code.
Other
530 stars 340 forks source link

toString() Object View should catch exceptions, or default to false #1297

Open jfrantzius opened 1 year ago

jfrantzius commented 1 year ago

When using the vscode java debugger, the experience can be really bad because some variables cannot be inspected seemingly for no reason. This gives the impression that the extension is still very buggy. It took me a long time to find out that disabling the toString() Object View solves that problem.

Likely there are exceptions thrown during toString() execution for those variables. These should either be caught, or the default for "Enable toString() Object View" should be false.

Environment
Steps To Reproduce
  1. set a breakpoint and look at Variables View, where some variables cannot be inspected image
  2. set "Enable toString() Object View" to false image
  3. Now the variables can be expanded: image
Current Result

Some variables cannot be inspected

Expected Result

It should be possible to inspect all variables, regardless of whether their toString() method throws an exception

testforstephen commented 1 year ago

Thanks for reaching out. Could you share the logs via command below?

F1 -> Java: Open Java Language Server Log File

jfrantzius commented 1 year ago

This is what it contains when I changed to "Enable toString() Object View":


!ENTRY org.eclipse.jdt.ls.core 1 0 2023-02-15 15:42:40.427
!MESSAGE >> workspace/didChangeConfiguration

!ENTRY org.eclipse.jdt.ls.core 1 0 2023-02-15 15:42:40.431
!MESSAGE >> New configuration: {java={home=/opt/homebrew/Cellar/openjdk@17/17.0.6/libexec/openjdk.jdk/Contents/Home, jdt={ls={java={home=null}, vmargs=-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx1G -Xms100m -javaagent:"/Users/joerg.frantzius/.vscode/extensions/gabrielbb.vscode-lombok-1.0.1/server/lombok.jar", lombokSupport={enabled=true}, protobufSupport={enabled=true}, androidSupport={enabled=false}}}, errors={incompleteClasspath={severity=warning}}, configuration={checkProjectSettingsExclusions=false, updateBuildConfiguration=interactive, maven={userSettings=, globalSettings=null, notCoveredPluginExecutionSeverity=warning}, workspaceCacheLimit=90.0, runtimes=[]}, trace={server=off}, import={maven={enabled=true, offline={enabled=false}}, gradle={enabled=true, wrapper={enabled=true}, version=null, home=null, java={home=null}, offline={enabled=false}, arguments=null, jvmArguments=null, user={home=null}, annotationProcessing={enabled=true}}, exclusions=[**/node_modules/**, **/.metadata/**, **/archetype-resources/**, **/META-INF/maven/**], generatesMetadataFilesAtProjectRoot=false}, maven={downloadSources=false, updateSnapshots=true}, eclipse={downloadSources=false}, referencesCodeLens={enabled=false}, signatureHelp={enabled=true, description={enabled=false}}, implementationsCodeLens={enabled=false}, format={enabled=true, settings={url=null, profile=null}, comments={enabled=true}, onType={enabled=true}, insertSpaces=true, tabSize=4.0}, saveActions={organizeImports=false}, project={referencedLibraries=[lib/**/*.jar], importOnFirstTimeStartup=automatic, importHint=true, resourceFilters=[node_modules, \.git], encoding=ignore, exportJar={targetPath=${workspaceFolder}/${workspaceFolderBasename}.jar}}, contentProvider={preferred=null}, autobuild={enabled=true}, maxConcurrentBuilds=1.0, recommendations={dependency={analytics={show=true}}}, completion={maxResults=0.0, enabled=true, guessMethodArguments=true, favoriteStaticMembers=[org.junit.Assert.*, org.junit.Assume.*, org.junit.jupiter.api.Assertions.*, org.junit.jupiter.api.Assumptions.*, org.junit.jupiter.api.DynamicContainer.*, org.junit.jupiter.api.DynamicTest.*, org.mockito.Mockito.*, org.mockito.ArgumentMatchers.*, org.mockito.Answers.*], filteredTypes=[java.awt.*, com.sun.*, sun.*, jdk.*, org.graalvm.*, io.micrometer.shaded.*], importOrder=[#, java, javax, org, com, ], postfix={enabled=true}, matchCase=off}, foldingRange={enabled=true}, progressReports={enabled=true}, codeGeneration={hashCodeEquals={useJava7Objects=false, useInstanceof=false}, useBlocks=false, generateComments=false, toString={template=${object.className} [${member.name()}=${member.value}, ${otherMembers}], codeStyle=STRING_CONCATENATION, skipNullValues=false, listArrayContents=true, limitElements=0.0}, insertionLocation=afterCursor}, selectionRange={enabled=true}, showBuildStatusOnStart={enabled=notification}, server={launchMode=Hybrid}, sources={organizeImports={starThreshold=99.0, staticStarThreshold=99.0}}, imports={gradle={wrapper={checksums=[]}}}, templates={fileHeader=[], typeComment=[]}, references={includeAccessors=true, includeDecompiledSources=true}, typeHierarchy={lazyLoad=false}, settings={url=null}, symbols={includeSourceMethodDeclarations=false}, quickfix={showAt=line}, inlayHints={parameterNames={enabled=literals, exclusions=[]}}, codeAction={sortMembers={avoidVolatileChanges=true}}, compile={nullAnalysis={nonnull=[javax.annotation.Nonnull, org.eclipse.jdt.annotation.NonNull, org.springframework.lang.NonNull], nullable=[javax.annotation.Nullable, org.eclipse.jdt.annotation.Nullable, org.springframework.lang.Nullable], mode=interactive}}, cleanup={actionsOnSave=[]}, sharedIndexes={enabled=auto, location=}, checkstyle={configuration=, properties={}, version=8.18, modules=[], autocheck=true}, debug={logLevel=warn, settings={showHex=false, showStaticVariables=false, showQualifiedNames=false, showLogicalStructure=true, showToString=true, maxStringLength=0.0, numericPrecision=0.0, hotCodeReplace=manual, enableRunDebugCodeLens=true, forceBuildBeforeLaunch=true, onBuildFailureProceed=false, console=integratedTerminal, exceptionBreakpoint={skipClasses=[]}, stepping={skipClasses=[], skipSynthetics=false, skipStaticInitializers=false, skipConstructors=false}, jdwp={limitOfVariablesPerJdwpRequest=100.0, requestTimeout=3000.0, async=auto}, vmArgs=}}, silentNotification=false, dependency={showMembers=false, syncWithFolderExplorer=true, autoRefresh=true, refreshDelay=2000.0, packagePresentation=flat}, help={firstView=auto, showReleaseNotes=true, collectErrorLog=false}, test={defaultConfig=, config={}}}}

!ENTRY org.eclipse.jdt.ls.core 1 0 2023-02-15 15:42:40.431
!MESSAGE >> workspace/executeCommand vscode.java.updateDebugSettings
testforstephen commented 1 year ago

set a breakpoint and look at Variables View, where some variables cannot be inspected image

I don't get what's the problem here. You can click the eye icon to expand the target variable. Also you can turn on the setting debug.autoExpandLazyVariables if you don't like the lazy variable resolve capability.

jfrantzius commented 1 year ago

Thx @testforstephen, I had no clue about lazy variables, and maybe the problem then is a UX problem - I guess many other people don't have a clue about this neither, and I'd say: they shouldn't have to have it.

The question maybe is: why does the Java debug extension report those variables as lazy in the first place? The only seemingly related issue I could find is this: https://github.com/Microsoft/vscode-java-debug/issues/311

testforstephen commented 1 year ago

The question maybe is: why does the Java debug extension report those variables as lazy in the first place? The only seemingly related issue I could find is this: #311

See https://github.com/microsoft/java-debug/pull/401, evaluating the toString value of an object is not a cheap operation. If the variable list is large, computing all toString details in advance would slow down the rendering of variable view. The lazy behavior will delay the resolving on demand.

jfrantzius commented 1 year ago

thx @testforstephen , but I wonder what evidence there is that evaluating toString() lazily results in better UX than displaying it immediately?

I guess that the point of evaluating it lazily is based on the assumption that display could be sluggish otherwise, i.e. it exists to prevent bad a UX?

Combined with the given defaults, though, this seems to mean that for most people no values will be displayed at all, which is much of a worse UX IMHO ....

testforstephen commented 1 year ago

this is just personal opinion. The problem for you is that the eye icon is not intuitive as a clickable link. That has room to improve.

Something I'm thinking is that we can expose a context menu as shortcut to enable/disable "Auto expand lazy variables".

jfrantzius commented 1 year ago

Hm, as a developer, I'd like to immediately see values of variables, instead of having to either click small icons, or having to know which option to set in in a context menu?

If the option "Auto expand lazy variables" was true by default, and can be switched to false by the developer once he/she notices lags, then IMHO that would be a good solution.