vscode-java-debug icon indicating copy to clipboard operation
vscode-java-debug copied to clipboard

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

Open jfrantzius opened this issue 2 years ago • 8 comments
trafficstars

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
  • Operating System: MacOS Ventura 13.2
  • JDK version: debugee is OpenJDK Runtime Environment Homebrew (build 11.0.18+0)
  • Visual Studio Code version: 1.75.1 (Universal) Commit: 441438abd1ac652551dbe4d408dfcec8a499b8bf
  • Java extension version: v1.14.0
  • Java Debugger extension version: 0.48.0 - 2023-02-01
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

jfrantzius avatar Feb 14 '23 10:02 jfrantzius

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

F1 -> Java: Open Java Language Server Log File

testforstephen avatar Feb 15 '23 09:02 testforstephen

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

jfrantzius avatar Feb 15 '23 14:02 jfrantzius

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.

testforstephen avatar Feb 17 '23 03:02 testforstephen

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

jfrantzius avatar Feb 18 '23 14:02 jfrantzius

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.

testforstephen avatar Feb 20 '23 03:02 testforstephen

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 ....

jfrantzius avatar Feb 20 '23 10:02 jfrantzius

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".

testforstephen avatar Feb 23 '23 01:02 testforstephen

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.

jfrantzius avatar Feb 23 '23 08:02 jfrantzius