Posts Tagged Eclipse

Eclipse tabbing sand trap fixed

Background

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.

News

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!

,

Leave a comment

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 org.hibernate.property.BasicPropertyAccessor$BasicSetter))
org.hibernate.property.BasicPropertyAccessor$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, java.io.Serializable) line: 234
org.hibernate.persister.entity.SingleTableEntityPersister(org.hibernate.persister.entity.AbstractEntityPersister).setIdentifier(java.lang.Object, java.io.Serializable, org.hibernate.EntityMode) line: 3624
org.hibernate.event.def.DefaultSaveEventListener(org.hibernate.event.def.AbstractSaveEventListener).performSave(java.lang.Object, java.io.Serializable, 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
org.hibernate.impl.SessionImpl.save(java.lang.String, java.lang.Object) line: 550
org.jboss.envers.synchronization.work.PersistentCollectionChangeWorkUnit.perform(org.hibernate.Session, java.lang.Object) line: 67
org.jboss.envers.synchronization.VersionsSync.executeInSession(org.hibernate.Session) line: 120
org.jboss.envers.synchronization.VersionsSync.beforeCompletion() line: 135
bitronix.tm.BitronixTransaction.fireBeforeCompletionEvent() line: 366
bitronix.tm.BitronixTransaction.commit() line: 142
bitronix.tm.BitronixTransactionManager.commit() line: 96
org.springframework.transaction.jta.JtaTransactionManager.doCommit(org.springframework.transaction.support.DefaultTransactionStatus) line: 1028
org.springframework.transaction.jta.JtaTransactionManager(org.springframework.transaction.support.AbstractPlatformTransactionManager).processCommit(org.springframework.transaction.support.DefaultTransactionStatus) line: 732
org.springframework.transaction.jta.JtaTransactionManager(org.springframework.transaction.support.AbstractPlatformTransactionManager).commit(org.springframework.transaction.TransactionStatus) 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
org.eclipse.jdt.internal.junit.runner.TestExecution.run(org.eclipse.jdt.internal.junit.runner.ITestReference[]) 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
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run() 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+)
&#91;/sourcecode&#93;

I used <a href="http://myregexp.com/eclipsePlugin.html">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="https://ourcraft.files.wordpress.com/2009/01/regular-expression-tester.png"><img class="alignnone size-full wp-image-1434" title="regular-expression-tester" src="https://ourcraft.files.wordpress.com/2009/01/regular-expression-tester.png" alt="regular-expression-tester" width="680" height="181" /></a>

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


   (?<=\(|, )
&#91;/sourcecode&#93;

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


   [a-z0-9.$]+

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

   ([A-Z]\w+)

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…

   $1

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 org.hibernate.property.BasicPropertyAccessor$BasicSetter))
org.hibernate.property.BasicPropertyAccessor$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
org.hibernate.impl.SessionImpl.save(String, Object) line: 550
org.jboss.envers.synchronization.work.PersistentCollectionChangeWorkUnit.perform(Session, Object) line: 67
org.jboss.envers.synchronization.VersionsSync.executeInSession(Session) line: 120
org.jboss.envers.synchronization.VersionsSync.beforeCompletion() line: 135
bitronix.tm.BitronixTransaction.fireBeforeCompletionEvent() line: 366
bitronix.tm.BitronixTransaction.commit() line: 142
bitronix.tm.BitronixTransactionManager.commit() 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
org.eclipse.jdt.internal.junit.runner.TestExecution.run(ITestReference[]) 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
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run() line: 386
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(String[]) line: 196

,

Leave a comment

(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 stackoverflow.com… 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.

,

Leave a comment

Superpowers (and how I lost them)

Or,

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

Leave a comment

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:
    eclipse-expressions-view-goodness
  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!

, , ,

1 Comment

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!

, ,

1 Comment

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:

ultimate-power-eclipse-external-tool-configuration

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:

ultimate-power-in-action

Coo-hoo-hool!

, ,

Leave a comment