ecd-plugin / ecd

An Eclipse Plugin to integrate different Class Decompiler seamlessly into the development workflow
Eclipse Public License 1.0
263 stars 57 forks source link

target/classes [in project-name] is not on its project's build path #21

Open nickl- opened 6 years ago

nickl- commented 6 years ago

Ok so my first instinct after installing the plugin is... lets go check out a class.

Problem/Issue

Cannot view project build class.

Where

Enhanced Class Decompiler (Core) 3.0.0.201709092115 Eclipse Version: Oxygen.1a Release (4.7.1a) Build id: 20171005-1200 Java: 1.8.0_144 OS: macOS High Sierra 10.13 Beta

Current results

When opening a project build class from the project output folder an error is displayed:

target/classes/package/name [in project-name] is not on its project's build path

Expected results

When opening any class the editor should work as advertised. Including decompiling, disassembly and byte code representations.

To reproduce

So the first thing I do after going through the settings, as explained on the web page, is to proceed to view a class in my newly installed class editor/viewer.

My first instinct, looking for a class to view is to find one in the project output folder. This folder, "Java output folders", is filtered by default so in "Project explorer" I open "Filters and Customisation" and uncheck the box next to "Java output folders". My m2e output folder target/classes becomes visible in the "Project explorer", but the default "build" folder would do the same, and I gain access to my project class files.

Double clicking on the first class I find does not however open the viewer but instead presents an error:

target/classes/package/name [in project-name] is not on its project's build path

A "Details" button reveals the following stack trace:

Java Model Exception: Java Model Status [target/classes/package/name [in project-name] is not on its project's build path]
    at org.eclipse.jdt.internal.core.JavaElement.newJavaModelException(JavaElement.java:570)
    at org.eclipse.jdt.internal.core.Openable.generateInfos(Openable.java:247)
    at org.eclipse.jdt.internal.core.Openable.openAncestors(Openable.java:505)
    at org.eclipse.jdt.internal.core.Openable.generateInfos(Openable.java:241)
    at org.eclipse.jdt.internal.core.Openable.openAncestors(Openable.java:505)
    at org.eclipse.jdt.internal.core.Openable.generateInfos(Openable.java:241)
    at org.eclipse.jdt.internal.core.SourceRefElement.generateInfos(SourceRefElement.java:107)
    at org.eclipse.jdt.internal.core.JavaElement.openWhenClosed(JavaElement.java:583)
    at org.eclipse.jdt.internal.core.BinaryType.getElementInfo(BinaryType.java:287)
    at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:306)
    at org.sf.feeling.decompiler.editor.DecompilerSourceMapper.findSource(DecompilerSourceMapper.java:67)
    at org.sf.feeling.decompiler.editor.JavaDecompilerClassFileEditor.doOpenBuffer(JavaDecompilerClassFileEditor.java:172)
    at org.sf.feeling.decompiler.editor.JavaDecompilerClassFileEditor.doOpenBuffer(JavaDecompilerClassFileEditor.java:147)
    at org.sf.feeling.decompiler.editor.JavaDecompilerClassFileEditor.doOpenBuffer(JavaDecompilerClassFileEditor.java:139)
    at org.sf.feeling.decompiler.editor.JavaDecompilerClassFileEditor.doSetInput(JavaDecompilerClassFileEditor.java:471)
    at org.eclipse.ui.texteditor.AbstractTextEditor$5.run(AbstractTextEditor.java:3154)
    at org.eclipse.jface.operation.ModalContext.runInCurrentThread(ModalContext.java:437)
    at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:353)
    at org.eclipse.ui.internal.WorkbenchWindow$14.run(WorkbenchWindow.java:2195)
    at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
    at org.eclipse.ui.internal.WorkbenchWindow.run(WorkbenchWindow.java:2191)
    at org.eclipse.ui.texteditor.AbstractTextEditor.internalInit(AbstractTextEditor.java:3172)
    at org.eclipse.ui.texteditor.AbstractTextEditor.init(AbstractTextEditor.java:3197)
    at org.eclipse.ui.internal.EditorReference.initialize(EditorReference.java:362)
    at org.eclipse.ui.internal.e4.compatibility.CompatibilityPart.create(CompatibilityPart.java:333)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:55)
    at org.eclipse.e4.core.internal.di.InjectorImpl.processAnnotated(InjectorImpl.java:990)
    at org.eclipse.e4.core.internal.di.InjectorImpl.processAnnotated(InjectorImpl.java:955)
    at org.eclipse.e4.core.internal.di.InjectorImpl.inject(InjectorImpl.java:124)
    at org.eclipse.e4.core.internal.di.InjectorImpl.internalMake(InjectorImpl.java:399)
    at org.eclipse.e4.core.internal.di.InjectorImpl.make(InjectorImpl.java:318)
    at org.eclipse.e4.core.contexts.ContextInjectionFactory.make(ContextInjectionFactory.java:162)
    at org.eclipse.e4.ui.internal.workbench.ReflectionContributionFactory.createFromBundle(ReflectionContributionFactory.java:105)
    at org.eclipse.e4.ui.internal.workbench.ReflectionContributionFactory.doCreate(ReflectionContributionFactory.java:74)
    at org.eclipse.e4.ui.internal.workbench.ReflectionContributionFactory.create(ReflectionContributionFactory.java:56)
    at org.eclipse.e4.ui.workbench.renderers.swt.ContributedPartRenderer.createWidget(ContributedPartRenderer.java:129)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.createWidget(PartRenderingEngine.java:992)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.safeCreateGui(PartRenderingEngine.java:661)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.safeCreateGui(PartRenderingEngine.java:767)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.access$0(PartRenderingEngine.java:738)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$2.run(PartRenderingEngine.java:732)
    at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.createGui(PartRenderingEngine.java:716)
    at org.eclipse.e4.ui.internal.workbench.PartServiceImpl$1.handleEvent(PartServiceImpl.java:104)
    at org.eclipse.e4.ui.services.internal.events.UIEventHandler$1.run(UIEventHandler.java:40)
    at org.eclipse.swt.widgets.Synchronizer.syncExec(Synchronizer.java:233)
    at org.eclipse.ui.internal.UISynchronizer.syncExec(UISynchronizer.java:144)
    at org.eclipse.swt.widgets.Display.syncExec(Display.java:4870)
    at org.eclipse.e4.ui.internal.workbench.swt.E4Application$1.syncExec(E4Application.java:212)
    at org.eclipse.e4.ui.services.internal.events.UIEventHandler.handleEvent(UIEventHandler.java:36)
    at org.eclipse.equinox.internal.event.EventHandlerWrapper.handleEvent(EventHandlerWrapper.java:201)
    at org.eclipse.equinox.internal.event.EventHandlerTracker.dispatchEvent(EventHandlerTracker.java:197)
    at org.eclipse.equinox.internal.event.EventHandlerTracker.dispatchEvent(EventHandlerTracker.java:1)
    at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
    at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148)
    at org.eclipse.equinox.internal.event.EventAdminImpl.dispatchEvent(EventAdminImpl.java:135)
    at org.eclipse.equinox.internal.event.EventAdminImpl.sendEvent(EventAdminImpl.java:78)
    at org.eclipse.equinox.internal.event.EventComponent.sendEvent(EventComponent.java:39)
    at org.eclipse.e4.ui.services.internal.events.EventBroker.send(EventBroker.java:52)
    at org.eclipse.e4.ui.internal.workbench.UIEventPublisher.notifyChanged(UIEventPublisher.java:60)
    at org.eclipse.emf.common.notify.impl.BasicNotifierImpl.eNotify(BasicNotifierImpl.java:374)
    at org.eclipse.e4.ui.model.application.ui.impl.ElementContainerImpl.setSelectedElement(ElementContainerImpl.java:173)
    at org.eclipse.e4.ui.internal.workbench.ModelServiceImpl.showElementInWindow(ModelServiceImpl.java:620)
    at org.eclipse.e4.ui.internal.workbench.ModelServiceImpl.bringToTop(ModelServiceImpl.java:584)
    at org.eclipse.e4.ui.internal.workbench.PartServiceImpl.delegateBringToTop(PartServiceImpl.java:769)
    at org.eclipse.e4.ui.internal.workbench.PartServiceImpl.bringToTop(PartServiceImpl.java:401)
    at org.eclipse.e4.ui.internal.workbench.PartServiceImpl.showPart(PartServiceImpl.java:1188)
    at org.eclipse.ui.internal.WorkbenchPage.busyOpenEditor(WorkbenchPage.java:3261)
    at org.eclipse.ui.internal.WorkbenchPage.access$25(WorkbenchPage.java:3176)
    at org.eclipse.ui.internal.WorkbenchPage$10.run(WorkbenchPage.java:3158)
    at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
    at org.eclipse.ui.internal.WorkbenchPage.openEditor(WorkbenchPage.java:3153)
    at org.eclipse.ui.internal.WorkbenchPage.openEditor(WorkbenchPage.java:3117)
    at org.eclipse.ui.internal.WorkbenchPage.openEditor(WorkbenchPage.java:3107)
    at org.eclipse.jdt.internal.ui.javaeditor.EditorUtility.openInEditor(EditorUtility.java:373)
    at org.eclipse.jdt.internal.ui.javaeditor.EditorUtility.openInEditor(EditorUtility.java:179)
    at org.eclipse.jdt.ui.actions.OpenAction.run(OpenAction.java:279)
    at org.eclipse.jdt.ui.actions.OpenAction.run(OpenAction.java:244)
    at org.eclipse.jdt.ui.actions.SelectionDispatchAction.dispatchRun(SelectionDispatchAction.java:271)
    at org.eclipse.jdt.ui.actions.SelectionDispatchAction.run(SelectionDispatchAction.java:249)
    at org.eclipse.jdt.internal.ui.navigator.OpenAndExpand.run(OpenAndExpand.java:50)
    at org.eclipse.ui.actions.RetargetAction.run(RetargetAction.java:216)
    at org.eclipse.ui.navigator.CommonNavigatorManager$2.open(CommonNavigatorManager.java:191)
    at org.eclipse.ui.OpenAndLinkWithEditorHelper$InternalListener.open(OpenAndLinkWithEditorHelper.java:46)
    at org.eclipse.jface.viewers.StructuredViewer$2.run(StructuredViewer.java:851)
    at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
    at org.eclipse.ui.internal.JFaceUtil.lambda$0(JFaceUtil.java:44)
    at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:173)
    at org.eclipse.jface.viewers.StructuredViewer.fireOpen(StructuredViewer.java:848)
    at org.eclipse.jface.viewers.StructuredViewer.handleOpen(StructuredViewer.java:1163)
    at org.eclipse.ui.navigator.CommonViewer.handleOpen(CommonViewer.java:451)
    at org.eclipse.jface.util.OpenStrategy.fireOpenEvent(OpenStrategy.java:273)
    at org.eclipse.jface.util.OpenStrategy.access$2(OpenStrategy.java:268)
    at org.eclipse.jface.util.OpenStrategy$1.handleEvent(OpenStrategy.java:308)
    at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:86)
    at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4257)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1502)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1525)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1510)
    at org.eclipse.swt.widgets.Widget.notifyListeners(Widget.java:1314)
    at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:4081)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3698)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1150)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:336)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1039)
    at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:153)
    at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:680)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:336)
    at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:594)
    at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:148)
    at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:151)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:134)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:388)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:243)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:653)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:590)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1499)

Result from attempting to follow instruction/information

Even though it makes no sense, if ever there was a build path for this project this is it, but none the less lets proceed to project's -> "Properties" -> "Java Build Path" and see. As expected attempting to add the target/classes folder on the "Source" tab results in an error

Source folder 'target/generated-sources/existing-import in project 'project-name' cannot output to distinct source folder 'target/classes'

Error which disables the "Apply" functionality to prevent any attempt to persist the conflict.

Conclusion

In the absence of any further instructions on the web page going to the output folder seems like the logical next step. Added to the fact that the aim of the project/plugin is to provide class viewer functionality, being unable to view my own classes is expected. I would even consider the default removal of the output folder filter to be acceptable installation configuration.

This seems like a simple enough thing to accomplish since the target is the solution to the problem, or in other words the build path which is missing is precisely what was selected. Perhaps it has to do with the output folder being prepended to the package name as in [output-folder]/[package-name] which causes the Class to be unrecognisable in the class path and maybe there could be a way to lookup this location adjust accordingly. Unfortunately I really have no idea what the impact is as I have zero eclipse plugin experience. Hope this report is informative enough for someone to find a quick solution.

More information on the web page, might also be a beneficial addition, instructing the new user on where they should go next to see the action, after browsing the settings. Also point out the additional menu items and context menu options available to assist in rapid adoption.

That said, this seems to be a very nice addition to my default Eclipse toolchain, it does seem like the decompilers are a tad dated but I notice others have commented on that already. All and all good work, well done and thank you!

RobertZenz commented 6 years ago

Mh, interesting, thanks for the detailed information. The plugin depends heavily upon the JDT infrastructure, which also includes that any class for decompilation is actually on the classpath. Requires a deeper look into it.

In the absence of any further instructions on the web page going to the output folder seems like the logical next step.

Personally, I would have accessed a referenced jar...could you please outline your use-case, I'd be very interested in hearing that one.

nickl- commented 6 years ago

Somehow this one slipped through the cracks, my bad.

Use case?

Developer uses integrated development environment for rapid application development. While developer browses code he stumbles upon dependencies for which no source code is available. Developer finds having source code, byte code even assembly preferential to none of the above. Developer sets out to fix the problem cause that's just what developers do.

How's that? =)

As mentioned I'm using m2e or eclipse for maven hmmmm not sure how they actually pronounce it but if you have any notion of maven you would know that it means you have all the jars files + source code your heart could desire and not a single jar file anywhere to be seen. In your project that is, since maven of course collects dependencies in the local repository somewhere way outside the eclipse workspace. Coming to think of it, haven't bothered with jar files much for quite some time, definitely not the first thing on my mind.

Regardless jar file presence... or lack thereof... if you say find me a class file my the first thing that comes to mind is the build output folder. A jar file is a zip file which has executable file type associations, hardly the easiest way to get your hands on a class file, in my experience. The classes folder comes to mind I mean does it get any more specific than that. classes folder = build output folder. Not sure how me telling you stories is helping finding a solution though.

Can't view classes on the classpath... the error claims it is because the file is not on the classpath. Perhaps this might help: the issue has similar characteristics to opening source files (.java files) from an additional source folder in your workspace but not one which has been added to the build path. Eclipse doesn't understand how to resolve the packages, you can't compile, code insight doesn't work, every line has at least 5 errors page painted red, a general unpleasantry and stubbornness all round. The solution is to simply add this folder to the project build path and if you listen carefully you can hear all eclipse's nut and bolts sound in unison "oooohhhhhhh we get it". Well you can't add the output folder to the build path I tried....

If there is anything I can test for you or be of some assistance feel free to shout, I hope the picture is at least clear now.

nickl- commented 6 years ago

Could it perhaps have something to do with

IJavaProject.getOutputLocation() or IJavaProject.readOutputLocation()

In order to manually force a project classpath refresh, one can simply assign the project classpath using the result of this method, as follows:

proj.setRawClasspath(proj.readRawClasspath(), proj.readOutputLocation(), monitor)

But I'm just grasping at straws, I would assume the first cause of action is to reproduce the problem. Has anyone actually tried to open a class file in the output folder.

Note:

This folder, "Java output folders", is filtered by default so in "Project explorer" I open "Filters and Customisation" and uncheck the box next to "Java output folders".

If we can reproduce the problem perhaps we can see what is missing and take it from there.

RobertZenz commented 6 years ago

Developer uses integrated development environment for rapid application development. While developer browses code he stumbles upon dependencies for which no source code is available. Developer finds having source code, byte code even assembly preferential to none of the above. Developer sets out to fix the problem cause that's just what developers do.

How's that? =)

If I understood you correctly, that is the main use-case this plugin was designed for and that works. But with the limitation that all jars you want to look at need to be on the classpath.

But I agree that the plugin should be able to decompile stand-alone class files. I've taken a deeper look into this and the plugin is dependent on the whole JDT (Java Development Tools) infrastructure, which requires that the file is actually part of the classpath. When I find the time to work on this, I will change that, but I cannot give you any timeframe for that, unfortunately.

In extension, one would assume that the plugin should be able to open/decompile whole jar files, that however is not close to easily accomplished, because the Package/Project Explorer does not access jar files, so there is no way to get the inner class files. We would have to first extend the explorer to be able to list the content of the jar file, something that I do not know if it is even possible from a third-party plugin.

nickl- commented 6 years ago

Please point me in a direction where you think we might find the class file/classpath decoupling or such joys I have some time.

Also seem to have broken ECD, can't for the life of me get the Decompiler menu to work anymore, it flashes visible when I open a class file and the resets back to default menu. I've uninstalled, removed all workspaces and eclipse folders, back down at vanilla Eclipse with nothing but ECD... sigh

Could it be oxygen:1a? I wonder...

Anyway... there are two plugins I know of that does for jar files what you require. Eclipse Zip Editor and JArchiveExplorer

Ok then lets see what this eclipse plugin fuzz is all about...

nickl- commented 6 years ago

Oh I see... it's a bit of a catch 22. Trade-off between decompiling the output class or locating the source that produced it.

Still no excuse to throw a tantrum though... still finding fix.

RobertZenz commented 6 years ago

If you want to work on this, I think a good entry point should be the org.sf.feeling.decompiler.editor.DisassemblerSourceViewer and org.sf.feeling.decompiler.editor.JavaDecompilerClassFileEditor.

As I said, the whole infrastructure is currently expecting it to be on the classpath. So when source code is displayed that is not on the classpath, various features should/will not be available, something to keep in mind.

Also seem to have broken ECD, can't for the life of me get the Decompiler menu to work anymore, it flashes visible when I open a class file and the resets back to default menu.

That is by design, the menu is only visible when decompiled source code is shown.

nickl- commented 6 years ago

Thanks for the info... I did manage to figure out those were the files of interest but how to fix it remains a mystery.

The reason why I am looking for the menu, which now seems to never appear anymore and probably due to the fact that I manage to retrieve most source files but anyway... with the menu being disabled/hidden it is not possible to view byte code anymore. =(