JConsole and Java VisualVM Problems on Windows

I ran in to this problem again today, only I forgot that I had blogged about it in the past, so I had to research and find the solution a second time.

In summary, if JConsole or Java VisualVM aren’t able to connect to local processes, your %TMP%\hsperfdata_[username] directory needs to match the capitalization of your Windows username. In my case, I renamed hsperfdata_eburke to hsperfdata_EBurke, solving the problem.

The First 10 Seconds is the Most Important

I really enjoyed 10 Second Code Review.

If you fail to hold code reviews, the crappy code that works its way into your production code base really is riddled with obvious bugs.

A full review definitely takes more than ten seconds, but maybe the first ten seconds are the most important. If you don’t have time for a complete review, at least ask a peer to drop by and give your code a quick look.

Wolfram|Alpha – Flummoxed by an Apostrophe

Wolfram Alpha is the hot new search engine. Of course I searched for “Eric Burke” first, and found nothing.

Next, I searched for my city and state (O’Fallon, MO) as shown here:

OK, that didn’t work. Let’s try removing the apostrophe:

As you can see, it worked. Oddly, their own “Input Interpretation” displayed the city name with the apostrophe. They just won’t let you search that way.

See also: Apostrophe Abuse.

Nimbus ToolTip Bug

I just submitted a bug report to Sun for this bug. With Nimbus on Java6u11, tool tips for disabled components have no border, and the tool tip background exactly matches the panel background color. Here is a sample program with the workaround commented out.

public class TooltipBug extends JFrame {     public static void main(String[] args) {         SwingUtilities.invokeLater(new Runnable() {             public void run() {                 try {                     UIManager.setLookAndFeel(                       "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");                 } catch (Exception e) {                     e.printStackTrace();                 }                 new TooltipBug().setVisible(true);             }         });     }      public TooltipBug() {         // un-comment these lines for the workaround         //UIManager.put("ToolTip[Disabled].backgroundPainter",         //        UIManager.get("ToolTip[Enabled].backgroundPainter"));          JButton b1 = new JButton("One");         b1.setToolTipText("Button 1");          JButton b2 = new JButton("One");         b2.setEnabled(false);         b2.setToolTipText("Button 2");          Container c = getContentPane();         c.setLayout(new FlowLayout());         c.add(b1);         c.add(b2);          pack();         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     } }

*** UPDATE: They accepted my bug report. It is Bug ID 6789983.

Nimbus JToolBar Bug

I just submitted a workaround for this Nimbus bug: 6780500. I am unable to watch or vote for bugs…the bug tracking tool seems to have a bug.

The problem is, disabled items in JToolBar use a black font and don’t look any different than enabled items.

This example requires Java6u10 or later, and demonstrates the bug:

public class ToolbarBug extends JFrame {   public static void main(String[] args) {     SwingUtilities.invokeLater(new Runnable() {       public void run() {         try {           UIManager.setLookAndFeel(                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");         } catch (Exception e) {           throw new RuntimeException(e);         }         new ToolbarBug().setVisible(true);       }     });   }    public ToolbarBug() {     /*     // un-comment these lines for the workaround     UIManager.put("ToolBar:Button[Disabled].textForeground",             UIManager.getColor("nimbusDisabledText"));     UIManager.put("ToolBar:ToggleButton[Disabled].textForeground",             UIManager.getColor("nimbusDisabledText"));     */      JToolBar tb = new JToolBar();     tb.add(new JButton("Enabled"));     JButton disabled = new JButton("Disabled");     disabled.setEnabled(false);     tb.add(disabled);      add(tb, BorderLayout.NORTH);      pack();     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   } }

With the fix, the example looks right:

The Problem with Dell

At work, I have a brand new quad core Dell running Vista. The machine is super fast and rock solid…except for the video card and driver.

Dell sells this computer with a defective video driver. Icons sometimes vanish until you move your mouse over them, at which time they eventually paint. The screen shows frequent painting artifacts — sometimes the entire login screen is blank, but you can still type. Software updates from ATI crash and burn.

This is true for other people’s PCs as well, so I know it is not a fluke with my machine. I have first hand experience with Vista at home, and I know that some video cards work fine with Vista. This particular configuration — the one Dell chooses to sell — does not work properly.

Yes, Vista has a lot of problems. I get it.

In this case, however, Dell is the problem. They knowingly sell this particular video card with their own PCs. 20 minutes of basic usage reveals painting artifacts and bugs. If Dell cared about customers, they would reject shitty hardware like this. Dell is huge. They can very easily tell ATI: “Sorry, not good enough. We refuse to cheapen our PCs with your flaky hardware and drivers.”

Is This a Nimbus Bug?

This code uses Java 6u11 with the Nimbus Look and Feel. I know how to create and apply custom Painters, but I’d rather avoid any com.sun.* dependencies. Those package names will change in Java 7, so I’d rather keep my code “clean”.

Case 1: JButton Background Color

This works:

JButton btn = new JButton("red"); btn.setBackground(Color.RED);

As expected, the button paints with a red background. That’s because deep inside com.sun.java.swing.plaf.nimbus.ButtonPainter, they override getExtendedCacheKeys(JComponent c). In that method, the painter asks the component for its background, on line 398:

if ("background".equals(property)) {     color = c.getBackground(); }

Case 2: JButtons in a JToolBar

When you put buttons into a JToolBar, setBackground() no longer has any effect. That’s because ToolBarButtonPainter fails to override getExtendedCacheKeys(). ToolBarButtonPainter also has a private array named componentColors like ButtonPainter, but the array is not used.

As I see it, there is no way to set the background color on buttons in a JToolBar without introducing com.sun.* dependencies in our code.

Is this a bug, or a feature? It seems awfully convenient to simply call setBackground(...), even if we’re using Nimbus painters behind the scenes.

VisualVM on Vista

I wanted to use VisualVM to track down a problem in a Java application running under Java 6u11, but it would not work. In the VisualVM local process list, all I could see was “<Unknown Application> (pid ###)”. When trying to connect, I’d see “not supported by this JVM”. This is on a Vista machine.

My domain username is “EBurke”, and Sun creates this directory:

%temp%\hsperfdata_eburke

In this directory, you’ll find one file for each Java process. The filenames are the PIDs.

The Fix

  1. Exit all Java apps
  2. Erase the hsperfdata_xxxx directory
  3. Create a new one, with correct capitalization.

In my case, the correct directory is:

%temp%\hsperfdata_EBurke

You can determine your username by typing “set” at the command prompt, and then finding the USERNAME setting.

Now when I run visualvm, I see the processes and I can connect to local Java apps successfully.

I submitted bug 236 for this issue.

Nimbus JTable Checkbox Rendering Bug

I ran across a Nimbus Look and Feel bug that affects the GUIs I work on. This is a known issue: see Bug ID 6723524 on the Bug Parade. It is marked Low priority, so I hope it is fixed before the Java 6u10 release. (unlike Bug 4795987, for example, which has been open since 2002 and is also affecting my GUIs).

Here is a standard JTable with Boolean values in the third column. Notice how the standard checkbox renderer fails to properly paint alternate row colors: (this is very subtle on some displays)

In this next picture, I clicked on “Jones” to demonstrate the standard Nimbus focus border:

In this next picture, I clicked on the checkbox. Notice how the border is not painted on the checkbox renderer:

Sample Code

Here is the demonstration program, it requires JDK 1.6u10 to run.

import javax.swing.*; import static javax.swing.UIManager.*; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableModel; import java.awt.*;  /**  * Demonstrates bug 6723524, checkboxes do not render properly in JTable.  *  * @author Eric M. Burke  */ public class NimbusDemo extends JFrame {     public static void main(String... args) {         SwingUtilities.invokeLater(new Runnable() {             public void run() {                 setNimbusLaf();                 new NimbusDemo().setVisible(true);             }         });     }      private static void setNimbusLaf() {         try {             for (LookAndFeelInfo lafInfo : getInstalledLookAndFeels()) {                 if ("Nimbus".equals(lafInfo.getName())) {                     setLookAndFeel(lafInfo.getClassName());                     return;                 }             }         } catch (Exception e) {             throw new RuntimeException(e);         }         throw new RuntimeException("Unable to find Nimbus LAF.");     }      public NimbusDemo() {         super("Bug 6723524");         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);          Object[] columnNames = {                 "First Name", "Last Name", "Married"         };         Object[][] data = {                 {"Harry", "Smith", true},                 {"Sally", "Jones", false},                 {"Bob", "Clark", true},                 {"Eric", "Burke", true}         };          TableModel tm = new DefaultTableModel(data, columnNames) {             public Class getColumnClass(int columnIndex) {                 return (columnIndex == 2) ? Boolean.class : String.class;             }              public boolean isCellEditable(int row, int column) {                 return false;             }         };         add(new JScrollPane(new JTable(tm)), BorderLayout.CENTER);         pack();     } }