Eclipse tabbing sand trap fixed


I loved using Eclipse when I was on a Java project.  I could do things so quickly with all the keyboard shortcuts.  Wow!

It was probably because of how powerful the editor is in so many ways that I found a particular scenario so annoying.  Normally, I switch between Eclipse windows (“editors” in Eclipse parlance) using Ctrl+PgUp and Ctrl+PgDn.  But when among the files you’re editing is any .xml file (common if you’re using Spring!), the XML editor gives you Design and Source sub-tabs:eclipse-evil-subtabs

Now when you are happily Ctrl+PgUp-ing along and get to this editor, Ctrl+PgUp switches you back and forth between the Design and Source sub-tabs instead of to the next editor.  You’re stuck in the Eclipse tabbing sand trap!

The XML editor does not support turning off the sub-tabs, or I probably would do that.  You can use Ctrl+F6 and Ctrl+Shift+F6 instead of Ctrl+PgUp and Ctrl+PgDn, but they pop a little selection box and take effect when you release the keys rather than when you press them.  These two aspects, plus F6 being harder for me to find, make that workaround unappealing.  It’s enough more complicated  to slow me down and make me have to think about what I’m doing.


So… I was glad to see today that Kevin McGuire just committed a fix for this.  It’s targeted for 3.5 M7 , which looks like it should be available within the next month or so if the project’s recent milestone pace continues.

Thanks, Kevin!

A regex to selectively remove package from class names

I wanted to post the call stack at which I was experiencing a problem, to a forum.  I had expanded the display in Eclipse to show fully-qualified class names:

Thread [main] (Suspended (breakpoint at line 66 in$BasicSetter))$BasicSetter.set(java.lang.Object, java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) line: 66
org.hibernate.tuple.entity.PojoEntityTuplizer(org.hibernate.tuple.entity.AbstractEntityTuplizer).setIdentifier(java.lang.Object, line: 234
org.hibernate.persister.entity.SingleTableEntityPersister(org.hibernate.persister.entity.AbstractEntityPersister).setIdentifier(java.lang.Object,, org.hibernate.EntityMode) line: 3624
org.hibernate.event.def.DefaultSaveEventListener(org.hibernate.event.def.AbstractSaveEventListener).performSave(java.lang.Object,, org.hibernate.persister.entity.EntityPersister, boolean, java.lang.Object, org.hibernate.event.EventSource, boolean) line: 194
org.hibernate.event.def.DefaultSaveEventListener(org.hibernate.event.def.AbstractSaveEventListener).saveWithGeneratedId(java.lang.Object, java.lang.String, java.lang.Object, org.hibernate.event.EventSource, boolean) line: 144
org.hibernate.event.def.DefaultSaveEventListener(org.hibernate.event.def.DefaultSaveOrUpdateEventListener).saveWithGeneratedOrRequestedId(org.hibernate.event.SaveOrUpdateEvent) line: 210
org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(org.hibernate.event.SaveOrUpdateEvent) line: 56
org.hibernate.event.def.DefaultSaveEventListener(org.hibernate.event.def.DefaultSaveOrUpdateEventListener).entityIsTransient(org.hibernate.event.SaveOrUpdateEvent) line: 195
org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(org.hibernate.event.SaveOrUpdateEvent) line: 50
org.hibernate.event.def.DefaultSaveEventListener(org.hibernate.event.def.DefaultSaveOrUpdateEventListener).onSaveOrUpdate(org.hibernate.event.SaveOrUpdateEvent) line: 93
org.hibernate.impl.SessionImpl.fireSave(org.hibernate.event.SaveOrUpdateEvent) line: 562, java.lang.Object) line: 550, java.lang.Object) line: 67
org.jboss.envers.synchronization.VersionsSync.executeInSession(org.hibernate.Session) line: 120
org.jboss.envers.synchronization.VersionsSync.beforeCompletion() line: 135 line: 366 line: 142 line: 96
org.springframework.transaction.jta.JtaTransactionManager.doCommit( line: 1028
org.springframework.transaction.jta.JtaTransactionManager( line: 732
org.springframework.transaction.jta.JtaTransactionManager( line: 701
org.springframework.transaction.interceptor.TransactionInterceptor(org.springframework.transaction.interceptor.TransactionAspectSupport).commitTransactionAfterReturning(org.springframework.transaction.interceptor.TransactionAspectSupport$TransactionInfo) line: 321
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(org.aopalliance.intercept.MethodInvocation) line: 116
org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation(org.springframework.aop.framework.ReflectiveMethodInvocation).proceed() line: 171
org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(org.aopalliance.intercept.MethodInvocation) line: 89
org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation(org.springframework.aop.framework.ReflectiveMethodInvocation).proceed() line: 171
org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], net.sf.cglib.proxy.MethodProxy) line: 635
com.ontsys.db.GreetingSetDAO$$EnhancerByCGLIB$$cd993582.create(com.ontsys.db.GreetingSetPO) line: not available
com.ontsys.db.EnversWithCollectionsTest.testComplexCreate() line: 112
sun.reflect.NativeMethodAccessorImpl.invoke0(java.lang.reflect.Method, java.lang.Object, java.lang.Object[]) line: not available [native method]
sun.reflect.NativeMethodAccessorImpl.invoke(java.lang.Object, java.lang.Object[]) line: 39
sun.reflect.DelegatingMethodAccessorImpl.invoke(java.lang.Object, java.lang.Object[]) line: 25
java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object...) line: 597
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall() line: 44
org.junit.runners.model.FrameworkMethod$1(org.junit.internal.runners.model.ReflectiveCallable).run() line: 15
org.junit.runners.model.FrameworkMethod.invokeExplosively(java.lang.Object, java.lang.Object...) line: 41
org.junit.internal.runners.statements.InvokeMethod.evaluate() line: 20
org.junit.internal.runners.statements.RunBefores.evaluate() line: 28
org.junit.internal.runners.statements.RunAfters.evaluate() line: 31
org.junit.runners.BlockJUnit4ClassRunner.runChild(org.junit.runners.model.FrameworkMethod, org.junit.runner.notification.RunNotifier) line: 73
org.junit.runners.BlockJUnit4ClassRunner.runChild(java.lang.Object, org.junit.runner.notification.RunNotifier) line: 46
org.junit.runners.BlockJUnit4ClassRunner(org.junit.runners.ParentRunner<T>).runChildren(org.junit.runner.notification.RunNotifier) line: 180
org.junit.runners.ParentRunner<T>.access$000(org.junit.runners.ParentRunner, org.junit.runner.notification.RunNotifier) line: 41
org.junit.runners.ParentRunner$1.evaluate() line: 173
org.junit.internal.runners.statements.RunBefores.evaluate() line: 28
org.junit.internal.runners.statements.RunAfters.evaluate() line: 31
org.junit.runners.BlockJUnit4ClassRunner(org.junit.runners.ParentRunner<T>).run(org.junit.runner.notification.RunNotifier) line: 220
org.eclipse.jdt.internal.junit4.runner.JUnit4TestMethodReference(org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference).run(org.eclipse.jdt.internal.junit.runner.TestExecution) line: 38[]) line: 38
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(java.lang.String[], java.lang.String, org.eclipse.jdt.internal.junit.runner.TestExecution) line: 460
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(org.eclipse.jdt.internal.junit.runner.TestExecution) line: 673 line: 386
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(java.lang.String[]) line: 196

This made it easy to see when the thread of control was in JUnit, Spring, Bitronix, Envers, Hibernate, etc…

But it was way too busy.  I decided that I wanted to keep the fully qualified method names but drop the package names off the method parameter class names.

Eclipse (3.3.2 anyway, which I’m using)’s Show Qualified Names option either shows ’em all or hides ’em all — there doesn’t seem to be a directly supported way to get the view I want there.

I decided to try crafting a regular expression to do the replacement, and came up with this:

   (?<=\(|, )&#91;a-z0-9.$&#93;+(&#91;A-Z&#93;\w+)

I used <a href="">Sergey's regular expression tester Eclipse plug-in</a> to try out my regular expression and visually see if it was matching what I expected (actually I used it to come up with the above regex):

<a href=""><img class="alignnone size-full wp-image-1434" title="regular-expression-tester" src="" alt="regular-expression-tester" width="680" height="181" /></a>

Here's what the regex does, bit by bit:

   (?<=\(|, )

This part uses lookbehind <em>(?&lt;=)</em> to say "match if just before the current position is a left-parenthesis or a comma+space."


This section matches the package part of a fully-qualified class name: one or more alphanumeric, periods, or dollar signs.


This final section matches only a capital letter, followed by one or more “word”-constitutin’ characters.  This matches the class name without the package.  We enclose this section in capturing parentheses, allowing us to replace the matched text with simply…


Performing the replacement yields this still-thick-but-not-quite-as-bad version of the call stack:

Thread [main] (Suspended (breakpoint at line 66 in$BasicSetter))$BasicSetter.set(Object, Object, SessionFactoryImplementor) line: 66
org.hibernate.tuple.entity.PojoEntityTuplizer(AbstractEntityTuplizer).setIdentifier(Object, Serializable) line: 234
org.hibernate.persister.entity.SingleTableEntityPersister(AbstractEntityPersister).setIdentifier(Object, Serializable, EntityMode) line: 3624
org.hibernate.event.def.DefaultSaveEventListener(AbstractSaveEventListener).performSave(Object, Serializable, EntityPersister, boolean, Object, EventSource, boolean) line: 194
org.hibernate.event.def.DefaultSaveEventListener(AbstractSaveEventListener).saveWithGeneratedId(Object, String, Object, EventSource, boolean) line: 144
org.hibernate.event.def.DefaultSaveEventListener(DefaultSaveOrUpdateEventListener).saveWithGeneratedOrRequestedId(SaveOrUpdateEvent) line: 210
org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(SaveOrUpdateEvent) line: 56
org.hibernate.event.def.DefaultSaveEventListener(DefaultSaveOrUpdateEventListener).entityIsTransient(SaveOrUpdateEvent) line: 195
org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(SaveOrUpdateEvent) line: 50
org.hibernate.event.def.DefaultSaveEventListener(DefaultSaveOrUpdateEventListener).onSaveOrUpdate(SaveOrUpdateEvent) line: 93
org.hibernate.impl.SessionImpl.fireSave(SaveOrUpdateEvent) line: 562, Object) line: 550, Object) line: 67
org.jboss.envers.synchronization.VersionsSync.executeInSession(Session) line: 120
org.jboss.envers.synchronization.VersionsSync.beforeCompletion() line: 135 line: 366 line: 142 line: 96
org.springframework.transaction.jta.JtaTransactionManager.doCommit(DefaultTransactionStatus) line: 1028
org.springframework.transaction.jta.JtaTransactionManager(AbstractPlatformTransactionManager).processCommit(DefaultTransactionStatus) line: 732
org.springframework.transaction.jta.JtaTransactionManager(AbstractPlatformTransactionManager).commit(TransactionStatus) line: 701
org.springframework.transaction.interceptor.TransactionInterceptor(TransactionAspectSupport).commitTransactionAfterReturning(TransactionAspectSupport$TransactionInfo) line: 321
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(MethodInvocation) line: 116
org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 171
org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(MethodInvocation) line: 89
org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 171
org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 635
com.ontsys.db.GreetingSetDAO$$EnhancerByCGLIB$$cd993582.create(GreetingSetPO) line: not available
com.ontsys.db.EnversWithCollectionsTest.testComplexCreate() line: 112
sun.reflect.NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
sun.reflect.NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
sun.reflect.DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
java.lang.reflect.Method.invoke(Object, Object...) line: 597
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall() line: 44
org.junit.runners.model.FrameworkMethod$1(ReflectiveCallable).run() line: 15
org.junit.runners.model.FrameworkMethod.invokeExplosively(Object, Object...) line: 41
org.junit.internal.runners.statements.InvokeMethod.evaluate() line: 20
org.junit.internal.runners.statements.RunBefores.evaluate() line: 28
org.junit.internal.runners.statements.RunAfters.evaluate() line: 31
org.junit.runners.BlockJUnit4ClassRunner.runChild(FrameworkMethod, RunNotifier) line: 73
org.junit.runners.BlockJUnit4ClassRunner.runChild(Object, RunNotifier) line: 46
org.junit.runners.BlockJUnit4ClassRunner(ParentRunner<T>).runChildren(RunNotifier) line: 180
org.junit.runners.ParentRunner<T>.access$000(ParentRunner, RunNotifier) line: 41
org.junit.runners.ParentRunner$1.evaluate() line: 173
org.junit.internal.runners.statements.RunBefores.evaluate() line: 28
org.junit.internal.runners.statements.RunAfters.evaluate() line: 31
org.junit.runners.BlockJUnit4ClassRunner(ParentRunner<T>).run(RunNotifier) line: 220
org.eclipse.jdt.internal.junit4.runner.JUnit4TestMethodReference(JUnit4TestReference).run(TestExecution) line: 38[]) line: 38
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(String[], String, TestExecution) line: 460
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(TestExecution) line: 673 line: 386
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(String[]) line: 196

(Can’t) automatically show the return value in the Eclipse debugger

When I’m using the Eclipse debugger, I’d sometimes like to see the return value of a method, or the contents of a thrown exception.  I can do this by selecting the expression that is about to be returned and pressing Ctrl+Shift+D (“Display”), which evaluates the expression… but this is difficult with exceptions and sometimes there are side-effects that make you not want to cause the code to be evaluated an extra time.

I wish there were a way to configure the Eclipse debugger to automatically show the return value (perhaps in the Expressions view, or maybe in the Variables view).  This appears to be a missing feature at the moment.

Here’s someone asking the same question on… and someone else asking on the old Sun Debugging Tools and Techniques forum in 2006.

Eclipse bug #40912 has been logged for this issue, but it seems to be languishing with a resolution of “LATER” since 2007 (I just added my vote, though!)

I remember this functionality being helpful when I was using Visual Studio (VS 2002, maybe?)  a few years ago.

Superpowers (and how I lost them)


Why One Might Consider Putting the Source Code Inside One’s Eclipse Workspace

In the course of debugging my transaction manager issues, I wanted to step through the JBoss UserTransaction code; so I downloaded the JBoss source and plopped it off under c:\src, then attached source in Eclipse.

But… nooooooo! (said with the anguish of Superman in the presence of Kryptonite) — while I could step into the code, Copy Qualified Name (which I was doing all the time while documenting my research) was unavailable… I could not set a breakpoint… even my beloved F3 was ineffectual at going to the declaration of an element.  It was as if Eclipse had suddenly devolved into — (gasp!) a giant… Text Editor!

(Plopped the code into a subdirectory of the Eclipse workspace, and everything’s fine now.   :)

Sometimes there’s an easier way

I was working to get snapshots of the Hibernate AnnotationConfiguration properties in effect when Hibernate local transactions are in use versus when a JTA transaction manager is in use, and halfway through I found there was a much easier way to capture my data.

What I did First

  1. While a debugging session was stopped at a breakpoint at line 732 of org.springframework.orm.hibernate3.LocalSessionFactoryBean (In buildSessionFactory() where the AnnotationConfiguration is done being built), I went to the Expressions view and selected the AnnotationConfiguration named “config”;
  2. Opened config’s properties field and manually expanded all 116 nodes, exposing their key/value pairs;
  3. Selected the 116 nodes-with-key/value-pairs and chose Copy Expressions from the context menu;
  4. Pasted into Notepad and manually removed the “[0…99]” and “[100…116]” lines;
  5. Saved the modified file as hibernate-annotation-config-jta.txt
  6. Ran the following commands:
    egrep --invert-match "\[" hibernate-annotation-config-jta.txt > keys-values.txt
    egrep key= keys-values.txt | sed 's/[ \t]*key= \"\(.*\)\".*$/\1/' > keys.txt
    egrep value= keys-values.txt | sed 's/[ \t]*value= \"\(.*\)\".*$/\1/' > values.txt
    paste --delimiter== keys.txt values.txt > keys-values-jta.txt

This worked — it got all 116 entries into key=value format, one key/value pair per line — and I prepared to do it again while running my test in Hibernate mode.

Then I noticed…

Then I saw another pane in the Expressions view I hadn’t really noticed before, on the right hand side.  When I clicked on one of the AnnotationConfig’s properties in the Expressions window (even without expanding that entry to show the key and value), I saw the entry in key=value format over in that right hand pane.  And… if I selected all 116 nodes in the left pane of the Expressions view, all 116 key=value pairs showed up in the right pane, ready for me to select and copy!

My new workflow, then, is:

  1. While a debugging session is stopped at a breakpoint at line 732 of org.springframework.orm.hibernate3.LocalSessionFactoryBean (In buildSessionFactory() where the AnnotationConfiguration is done being built), go to the Expressions view, select the AnnotationConfiguration named “config”, and within that select the properties field;
  2. Make sure the “Show Logical Structure” button is pressed;
  3. Expand the properties field so that you can see the individual [0], [1] [2]… entries
  4. Select all these entries:
  5. In the Expressions view’s right hand pane, Select All and copy.

Those are nicer steps than what I did first!  Eclipse comes through again!

Remote debugging in JBoss

Have you ever wished you could debug your war project in Eclipse while it was deployed and running on JBoss? This is called remote debugging, and here’s how you set up to do it (on JBoss 4.2.2.GA running on Java 5, anyway):

  1. Make a backup copy of your current JBoss run.bat
  2. Open run.bat and find the lines that look like this:
    rem JPDA options. Uncomment and modify as appropriate to enable remote debugging.
    rem set JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y %JAVA_OPTS%
  3. Uncomment the second line, and save.
  4. Start Jboss. (It won’t do much until you connect a debugger to it.)
  5. In Eclipse, open your project, and on the toolbar click on the debugger bug arrow, then Open Debug Dialog.
  6. Choose Remote Java Application, right-click, New… and update the port to the address in the line you uncommented (possibly 8787).
  7. Click Debug
  8. Set a breakpoint somewhere in your code or a library that has source attached
  9. Exercise your project (via a web service, for instance) and when it hits one of your breakpoints, it will break in Eclipse.

Note to self: Avoid remote debugging for my own code — I should be adding log messages instead!

Ultimate power!

I use Eclipse’s External Tools feature to run a lot of Maven goals: clean install, eclipse:clean eclipse:eclipse, etc.  I have an external tool configuration set up for each of these common commands.

Sometimes, though, I want to try out a goal I don’t as often use.  Maven dependency:tree and dependency:list I use almost enough to have a special external tool configuration for each… but from time to time I find out about other Maven plugins that I want to try out but would rather not have to clutter up the external tools list with special entries for each one.

As an alternative, sometimes I try out these goals from the Windows command prompt, but it’s a pain to navigate to my project’s working directory each time before executing the command.  I probably experiment less with such commands than I would otherwise because of the effort to prepare to run them — I just get by without their output, without really thinking about it.

Yesterday, though, Keith was helping me get set up to do JBoss remote debugging in Eclipse (a whole ‘nother topic), and in the process of setting it up, one of us wondered if you could set up an external tool that just dropped you to a Windows command prompt so you could type whatever command you want.

You can!  Here’s my configuration, which I call Ultimate Power:


When I run this, it puts a Windows command prompt sitting in my project directory in a Console window, and now I can type my command:



Amazinger and amazinger

I keep having pleasant surprises at new ways the Eclipse IDE can help my productivity.  I wrote about Quick Fixes before; here’s today’s:

Did you know that you can type just the capital letters of a class, and then when you hit Ctrl+Space, Content Assist shows what names have those capitals?

For instance, suppose I want to add a Spring DefaultMessageListenerContainer reference to my class (admittedly odd, but it’s a big long name I don’t want to have to type):

  1. I type DMLC, …
  2. …hit Ctrl+Space…
  3. …and Enter…
  4. “DefaultMessageListener” appears, and I go on to type a field name:

(The title references Alice…)

Caught in an XML design trap!

When I have multiple files open in Eclipse, I often use Ctrl+PgUp/Ctrl+PgDn to cycle through them.  But the thing that always makes me lapse into pirate-speak is when one of the files in the middle is an XML file.

The Eclipse XML editor has two sub-tabs of its own: a Design view and a Source view.  When the current editor is an XML editor and I Ctrl+PgDn, instead of going to the next editor, I now go back and forth between the Design and Source views of the XML file.  Arrrh!

Since I never use the XML Design view (I wish I could hide that tab), I also generally press Ctrl+PgDn one more time to get it back to the Source view first.  Then, to go on to the next editor, I have to either reach over and click with the mouse or press Ctrl+F6 instead. Either of these alternatives results in a break of flow, but Ctrl+F6 is the worse one: where Ctrl+PgDn moves to the next editor as soon as PgDn is pressed, Ctrl+F6 (and its twin, Ctrl+Shift+F6) pops up a list of editors when the F6 is pressed and then only goes to the selected editor when Ctrl is released.  These differences can be enough to break the flow of thought so that I forget what I was doing and have to stop and regain that focus.

It turns out that this issue was discussed on the eclipse IRC on February 15, 2008 (follow the conversation starting with eidolon at [16:13:25]), and that Eclipse Bug 199499, Switching tabs by Ctrl+PageUp/PageDown must not be caught on the inner tab set, has been logged for this issue.  I added my vote!

It wasn’t JBoss’s fault

I saved my changes to jboss-log4j.xml and waited for JBoss to notice the new file… but it never seemed to notice it, and my advice.log kept not showing up in the log directory.  I immediately suspected JBoss.  “Why isn’t it watching server/default/conf/jboss-log4j.xml like it’s supposed to be?”

Then I remembered that I was editing a copy of jboss-log4j.xml in my Eclipse workspace, so I’d have the benefit of Eclipse’s local history feature.  Oops!

I copied jboss-log4j.xml from my Eclipse workspace out to JBoss’s server/default/conf directory, and sure enough… JBoss noticed the changes.  : )