Discussion about NoClassDefFoundError: org/eclipse/jdt/internal/corext/refactoring/rename/RenamePackageProcessor

This is related to Remove usage of internal class RenamePackageProcessor by chrisrueger · Pull Request #5892 · bndtools/bnd · GitHub and I thought it might be an idea to discuss it here.

Although I fixed the problem, by removing the code which referenced the class, I don’t fully understand why we get this Exception in the first place.
Maybe I am missing something really obvious…

here are some findings for a discussion:

  1. I found this comment which sounds as if there was something done for specifically this package:

  2. Package org.eclipse.jdt.internal.corext.refactoring.rename is exported by the bundle org.eclipse.jdt.ui

(although it has .internal in its package name and the x-internal=true, but from an OSGI perspective it is exported.)

  1. org.eclipse.jdt.ui is ACTIVE

  1. bndtools.core also imports org.eclipse.jdt.internal.corext.refactoring.rename

Question:
Why does the exception (NoClassDefFoundError: org/eclipse/jdt/internal/corext/refactoring/rename/RenamePackageProcessor) happen?

@pkriens @kriegfrj maybe?

1 Like

Could it be because one of the packages from one of the classes that RenamePackageProcessor imports is not being imported?
https://github.com/eclipse-jdt/eclipse.jdt.ui/blob/master/org.eclipse.jdt.core.manipulation/refactoring/org/eclipse/jdt/internal/corext/refactoring/rename/RenamePackageProcessor.java#L26-L113

2 Likes

The reason is that we compile against Eclipse-4.25/org.eclipse.jdt.ui-3.27.0.v20220824-0714.jar. In this version the package org.eclipse.jdt.internal.corext.refactoring.rename is present.

However, when we run we are linked to org.eclipse.jdt.core.manipulation_1.16.200.v20220824-0551 for this package. Both the bundle org.eclipse.jdt.ui and org.eclipse.jdt.core.manipulation export the same package org.eclipse.jdt.internal.corext.refactoring.rename. However, they have different contents.

org.eclipse.jdt.ui org.eclipse.jdt.core.manipulation
GenericRefactoringHandleTransplanter.class RefactoringAnalyzeUtil.class
JavaRenameProcessor.class RenameAnalyzeUtil.class
MethodChecks.class RenamingNameSuggestor.class
MethodOccurenceCollector.class TempDeclarationFinder.class
RefactoringHandleTransplanter.class TempOccurrenceAnalyzer.class
RefactoringScanner.class
RenameCompilationUnitProcessor.class
RenameEnumConstProcessor.class
RenameFieldProcessor.class
RenameJavaProjectProcessor.class
RenameLocalVariableProcessor.class
RenameMethodProcessor.class
RenameModifications.class
RenameModuleProcessor.class
RenameNonVirtualMethodProcessor.class
RenamePackageProcessor.class
RenameSourceFolderProcessor.class
RenameTypeParameterProcessor.class
RenameTypeProcessor.class
RenameVirtualMethodProcessor.class
RippleMethodFinder2.class
TextMatchUpdater.class
TypeOccurrenceCollector.class
todo.txt

They have been happily inventing some additional modularity stuff on top of OSGi. When you look at the export of org.eclipse.jdt.core.manipulation, you see:

     org.eclipse.jdt.internal.corext.refactoring.rename;x-friends:="org.eclipse.jdt.ui"

There seems to be some Eclipse C++‘s and JPMS’ friend function envy? This seems a backdoor to get split packages? Tom Watson can probably tells us how this works.

In the OSGi, we spend countless hours discussing friend bundles. We decided after very ample deliberations to not do this. The key concept in OSGi is service based design, where your service has a clear distinction between API and implementation, modeled through a set of interfaces in a package. Libraries, bundles where API + implementation is together, is ok but it is never ok to splat a library over multiple bundles. The whole idea of modules is that you keep your implementations in your pants. Any implementation wandering in the public space is wrong, it is like you cannot be a little bit pregnant. You play by the rules, you get the benefits. Do this nice looking hack, you just pay a shitload of money for OSGi + Java complexity and all benefits just just dumped while adding another shitload of complexity on your users.

The thing is modularity is hard. Modularity in Java is surprisingly hard.

It is a tad frustrating, been here for 20 years, and it feels like a Sisyphus task. Maybe it is time to shut up :frowning:

2 Likes

Thanks @gamerson and @pkriens . Wow, I would not have found that out.

EDIT:

Ah, Ok this can be seen in the Repo-Browser with filtering by package. I noticed this earlier, but did not pay attention to it.

Peter, could you share your way how you found that out?

Peter, could you share your way how you found that out?

Nope trade secret :slight_smile:

I just ran the code in the debugger. Had a breakpoint on the place where we do the cast. Then used the incredible Debug Shell

This turned out to be org.eclipse.osgi.internal.loader.EquinoxClassLoader@3f5dfe69[org.eclipse.jdt.ui:3.27.0.v20220824-0714(id=190)]

Then I set a break point on the Class Not Found Exception. This broke here:

image

Using he Debug Shell again on the Bundle Loader, I looked at this.importedSources.get("org.eclipse.jdt.internal.corext.refactoring.rename") which is the import table (I guessed). This was org.eclipse.jdt.internal.corext.refactoring.rename -> [org.eclipse.jdt.core.manipulation_1.16.200.v20220824-0551]

Elementary, my dear Watson :sunglasses:

1 Like

:joy: :exploding_head:

Wow thanks.

I wonder is there any (theoretical) chance or way to make this visible in bndtools / bnd?
Maybe a gogo shell command? Which part of the tooling would be able to get this? Only the running framework right?

There might be an equinox Gogo command., I recall.

There is also OSGi bnd Snapshot Viewer that probably provides this information. If not, it should be easy to add this to the JSON and visualize it.

There is also https://github.com/aQute-os/biz.aQute.osgi.util/tree/master/biz.aQute.gogo.commands.provider.test/readme.md that very likely has a command to diagnose this, or it should be trivial to add.

Both bundles are on Maven Central.

Problem is that this problem only occurs when you have no idea what you’re doing. If you get this problem, it is highly likely there are myriad of class loader and timing problems hidden in the code. Of course they will tell you: “but it works?” Yup, most of the time.

Ah sure, I worked with it in the past. I will have a look. Thanks.

I guess you mean https://github.com/aQute-os/biz.aQute.osgi.util/tree/master/biz.aQute.gogo.commands.provider/src/main/java/biz/aQute/gogo/commands/provider (without .test)

Agree. But since we had this problem specifically in bndtools I just thought if there was a way that tool itself could help you analyse this problem. You are probably the only person on earth able to analyse and find this problem :slight_smile: Since bndtools is supposed to support you in writing good OSGi programs, I think it would be great if the tool could slap this kind of issue in your face (a warning, red light…something)
From a marketing perspective it is this sentence on the bndtools website which crossed my mind:

And this problem here seems to be “hard to debug”.

Ok I will check out your tips and see what I can find. I try follow up here.

You are probably the only person on earth able to analyse and find this problem

No, BJ is Yoda here :slight_smile: And Tom Watson is close.

And this problem here seems to be “hard to debug”.

Well, bnd goes out of its and and more to prevent these problems. In this case, it is a runtime problem in Eclipse. It would be interesting to hear Tom Watson about the x-friend attribute. Note that this seems self inflicted pain. We might run into it because we use package imports and not Require-Bundle.

I do not think Bndtools should try to alleviate these problems, only prevent them!

Agree. Exactly that was my thinking. Anyway thanks, I apreaciate the input and the discussions.

I just did a search for other uses where we use .internal packages. Do you think those are also potential candidates for future headaches / breaking stuff?

I just did a search for other uses where we use .internal packages. Do you think those are also potential candidates for future headaches / breaking stuff?

I’ve always seen the internal package as ‘plausible deniability’. I did some of the JUnit OSGi stuff and it was impossible as far as I could see to extend or even use the UI without touching internal classes.

I really don’t know. I haven’t got a lot of experience with Eclipse. Neil Bartlett set it all up and BJ maintained it, I just wrestled and muddled in that environment.

Are there alternatives for all these packages? Some of the class names suggest pretty general functionality.

This said, we could look into using bndtools now. I think I added all support for this in bnd about 2 years ago.

I shouldn’t let my frustration get the better of me … :persevere: