Adding source roots to SDKs

Hi,

I'm trying to attach a source root to the project SDK with the following code:

ApplicationManager.getApplication().runWriteAction(new Runnable()
{
public void run()
{
SdkModificator sdkModificator = (SdkModificator)ProjectRootManager.getInstance(project).getProjectJdk();
if (sdkModificator != null)
{
MemoryVirtualFileSystem vfs = (MemoryVirtualFileSystem) VirtualFileManager.getInstance().getFileSystem(IntelliJadConstants.INTELLIJAD_PROTOCOL);
VirtualFile root = vfs.findFileByPath(IntelliJadConstants.INTELLIJAD_ROOT);
sdkModificator.addRoot(root,
ProjectRootType.SOURCE);
sdkModificator.commitChanges();
}
}
});

The root gets attached correctly, but results in the following stack trace:
java.lang.Throwable
at com.intellij.openapi.diagnostic.Logger.assertTrue(Logger.java:89)
at com.intellij.openapi.diagnostic.Logger.assertTrue(Logger.java:96)
at com.intellij.openapi.projectRoots.impl.ProjectRootContainerImpl.addRoot(ProjectRootContainerImpl.java:16)
at com.intellij.openapi.projectRoots.impl.ProjectJdkImpl.addRoot(ProjectJdkImpl.java:109)
at net.stevechaloner.intellijad.IntelliJad$2.run(IntelliJad.java:276)
at com.intellij.openapi.application.impl.ApplicationImpl$13.compute(ApplicationImpl.java:3)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.postponeFormattingInside(PostprocessReformattingAspect.java:109)
at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:214)
at net.stevechaloner.intellijad.IntelliJad.checkSDKRoot(IntelliJad.java:256)
at net.stevechaloner.intellijad.IntelliJad.decompile(IntelliJad.java:185)
at net.stevechaloner.intellijad.actions.NavigationListener$1$1.execute(NavigationListener.java:70)
at net.stevechaloner.intellijad.actions.NavigationListener.fileOpened(NavigationListener.java:154)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.util.messages.impl.MessageBusConnectionImpl.deliverMessage(MessageBusConnectionImpl.java:101)
at com.intellij.util.messages.impl.MessageBusImpl.pumpMessages(MessageBusImpl.java:170)
at com.intellij.util.messages.impl.MessageBusImpl.sendMessage(MessageBusImpl.java:162)
at com.intellij.util.messages.impl.MessageBusImpl.access$000(MessageBusImpl.java:36)
at com.intellij.util.messages.impl.MessageBusImpl$2.invoke(MessageBusImpl.java:102)
at $Proxy53.fileOpened(Unknown Source)
at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl.openFileImpl3(FileEditorManagerImpl.java:439)
at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl$4.run(FileEditorManagerImpl.java:2)
at com.intellij.openapi.command.impl.CommandProcessorImpl.executeCommand(CommandProcessorImpl.java:94)
at com.intellij.openapi.command.impl.CommandProcessorImpl.executeCommand(CommandProcessorImpl.java:68)
at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl.openFileImpl2(FileEditorManagerImpl.java:198)
at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl.a(FileEditorManagerImpl.java:425)
at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl.openFileWithProviders(FileEditorManagerImpl.java:420)
at com.intellij.openapi.fileEditor.ex.FileEditorManagerEx.openFile(FileEditorManagerEx.java:2)
at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl$5.run(FileEditorManagerImpl.java:9)
at com.intellij.openapi.command.impl.CommandProcessorImpl.executeCommand(CommandProcessorImpl.java:67)
at com.intellij.openapi.command.impl.CommandProcessorImpl.executeCommand(CommandProcessorImpl.java:68)
at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl.openEditor(FileEditorManagerImpl.java:415)
at com.intellij.openapi.fileEditor.OpenFileDescriptor.navigateInAnyFileEditor(OpenFileDescriptor.java:148)
at com.intellij.openapi.fileEditor.OpenFileDescriptor.navigateInEditor(OpenFileDescriptor.java:132)
at com.intellij.openapi.fileEditor.OpenFileDescriptor.navigate(OpenFileDescriptor.java:111)
at com.intellij.psi.impl.PsiElementBase.navigate(PsiElementBase.java:2)
at com.intellij.ide.projectView.impl.nodes.BasePsiNode.navigate(BasePsiNode.java:21)
at com.intellij.util.OpenSourceUtil.navigate(OpenSourceUtil.java:45)
at com.intellij.util.OpenSourceUtil.openSourcesFrom(OpenSourceUtil.java:34)
at com.intellij.util.EditSourceOnDoubleClickHandler$1.mouseClicked(EditSourceOnDoubleClickHandler.java:49)
at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:252)
at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:252)
at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:252)
at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:252)
at java.awt.Component.processMouseEvent(Component.java:6041)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
at com.intellij.util.ui.Tree.processMouseEvent(Tree.java:71)
at com.intellij.ide.dnd.aware.DnDAwareTree.processMouseEvent(DnDAwareTree.java:13)
at java.awt.Component.processEvent(Component.java:5803)
at java.awt.Container.processEvent(Container.java:2058)
at java.awt.Component.dispatchEventImpl(Component.java:4410)
at java.awt.Container.dispatchEventImpl(Container.java:2116)
at java.awt.Component.dispatchEvent(Component.java:4240)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4322)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3995)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3916)
at java.awt.Container.dispatchEventImpl(Container.java:2102)
at java.awt.Window.dispatchEventImpl(Window.java:2429)
at java.awt.Component.dispatchEvent(Component.java:4240)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at com.intellij.ide.IdeEventQueue.c(IdeEventQueue.java:111)
at com.intellij.ide.IdeEventQueue.b(IdeEventQueue.java:203)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:92)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)
ERROR - .impl.ProjectRootContainerImpl - Assertion failed:


Similarly, something happens when I try to detach the source root. In this case, the detachment is not successful.

In both cases, exceptions are thrown on adding/removing the root, and then again on committing the changes.

Can anyone give me a pointer on this?

Thanks,
Steve

7 comments
Comment actions Permalink

Hello Steve,

> In both cases, exceptions are thrown on adding/removing the root, and then again on
committing the changes.
>
> Can anyone give me a pointer on this?

Well, it looks like you need to call ProjectRootContainer#startChange/finishChange()
before/after adding the root.


PS: Does the on-the-fly attaching of source roots properly deal with cases where IDEA
doesn't exit normally? Will there be any zombie roots left and accumulate over the time?


Sascha

0
Comment actions Permalink

Hi Sascha,

thanks - I'll give this a try.

IRT abnormal exits - I did actually snip out a bit of code to keep the above post succint that checks if a root is already attached, so multiple identical roots are not attached. However, if Idea exits without first shutting down correctly it is possible that clean-up won't happen. Any suggestions for how to deal with this?

Thanks,
Steve

0
Comment actions Permalink

Stupid question time - ProjectRootContainer doesn't seem to exist any more in the openapi, and there doesn't appear to be anything with analogous startChange()/finishChange() methods. Do you know what this has become?

Thanks,
Steve

0
Comment actions Permalink

Oops... I didn't realize that you call add/remove on the ProjectJdk, not some
ProjectRootConainer. Sorry.

You shouldn't cast the ProjectJdk into an SdkModificator but instead obtain one by calling
com.intellij.openapi.projectRoots.Sdk#getSdkModificator() - this ensures you get a
version that's correctly initialized for modifications. Be sure to call commit() when
you're done with it.

Sascha

0
Comment actions Permalink

Hello Steve,

IRT abnormal exits - I did actually snip out a bit of code to keep the above post succint that checks if a root is already attached, so multiple identical roots are not attached. However, if Idea exits without first shutting down correctly it is possible that clean-up won't happen. Any suggestions for how to deal with this?


Well, avoiding duplicates is a good start and probably even good enough. But I think you
could try to clean up any zombie roots each time IDEA is started - as far as I understand,
after the startup there won't be any files in the memory file system anyway, right?

Sascha

0
Comment actions Permalink

Works like a dream.

Thanks!
Steve

0
Comment actions Permalink

In the case of the memory vfs root, at most one will be attached to the SDK and on normal project closing (even following an earlier abnormal exit) it will be removed.

But, in the case where classes are decompiled to the local file system then one (or more, if you change the output location at some point) root will point to a location on disk. However, it's always possible to manually remove them through the JDK manager (messy...).

Need to have a ponder over the weekend on the best approach to this.

Thanks,
Steve

0

Please sign in to leave a comment.