diff --git a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/ShortenedStrings.java b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/ShortenedStrings.java index 85558c67168f..9231be6678d5 100644 --- a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/ShortenedStrings.java +++ b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/ShortenedStrings.java @@ -43,6 +43,7 @@ import java.lang.ref.WeakReference; import java.text.MessageFormat; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -73,7 +74,18 @@ */ public final class ShortenedStrings { - private static final Map infoStrings = new WeakHashMap(); + /** + * Shortened display text → full remote content helper. + *

+ * Must be a strong map for the duration of a debugger session. A + * {@link WeakHashMap} drops the entry as soon as nothing holds the exact + * key {@link String} instance. The UI / property editor often holds an + * equal but different instance (or a quoted form from + * {@code Variable.getValue()}), so lookup fails while the truncated + * preview is still shown and "Save Value to File" only writes that + * preview. Cleared when the last debugger session ends. + */ + private static final Map infoStrings = new HashMap(); private static final Map stringsCache = new WeakHashMap(); private static final Set retrievingStrings = new HashSet(); private static final Map isLittleEndianCache = @@ -85,7 +97,7 @@ public final class ShortenedStrings { @Override public void sessionRemoved(Session session) { - // Clean up. WeakHashMap does not clean up if not touched. :-( + // Strong infoStrings map is session-scoped; clear when idle. int n = DebuggerManager.getDebuggerManager().getSessions().length; if (n == 0) { synchronized (infoStrings) { @@ -107,8 +119,19 @@ public void sessionRemoved(Session session) { private ShortenedStrings() {} public static StringInfo getShortenedInfo(String s) { + if (s == null) { + return null; + } synchronized (infoStrings) { - return infoStrings.get(s); + StringInfo info = infoStrings.get(s); + if (info != null) { + return info; + } + // Variable.getValue() wraps Strings in quotes: "content..." + if (s.length() >= 2 && s.charAt(0) == '"' && s.charAt(s.length() - 1) == '"') { + return infoStrings.get(s.substring(1, s.length() - 1)); + } + return null; } }