'. '


From APIDesign

Jump to: navigation, search

Concept of friends is almost essential for modularity. Not all exported APIs are stable enough, not all of them are ready for public consumption. In such case one needs to create a module, define its API, but restrict list of friends that may access it.


NetBeans Friends Support

The NetBeans Runtime Container has first class support for friends concept. Every module can, inside its manifest, enumerate the programatic names of modules that may access given API. Surprisingly, this list of friends is an API of the module itself. In case you change the list, you are changing the module API and you need to properly version such change.

No Class Error!?

Recently we had to deal with a bug 201021 - suddenly one module was getting NoClassDefFoundError when trying to access a LexerUtils class from another module. The LexerUtils class existed since the creation of its module, so it was a mystery for all of us. How could a class not be found, if it exists for ages?

Is the installation corrupted? was our first question. No, it was not. We received the same report from multiple users. Thus we could rule out random corruption error. Something in our shared infrastructure must have been broken.

Is there a problem in an initializer? is a second question to ask. Sometimes, when a class throws an exception from one of its static initializers, it becomes unavailable to the JVM. Later, if any other class references the broken one, a NoClassDefFoundError is generated at very unexpected places. However this was not the problem either. There was no other exception in the log files!

A complete mystery.

Friends are API!

It turned out that one new module (let's call it uses.lexer.utils) needed to access this friend API and his developer just added it to the list of friends:

OpenIDE-Module-Module: provides.lexer.utils
OpenIDE-Module-SpecificationVersion: 1.1
OpenIDE-Module-Friends: old.friend.one, old.friend.two, '''uses.lexer.utils'''

Everything used to work in a local instalation, but in a highly Incremental deployment environment, we soon received bug reports.

The problem is that some users managed to update only the uses.lexer.utils module but still kept the old version of provides.lexer.utils. The result? A code from uses.lexer.utils tried to access LexerUtils class, but the access to that class was rejected as the old version of provides.lexer.utils did not know that uses.lexer.utils is a friend!

Version Friends List

Remember, when you expand the list of friends, that you are changing the API of the module and you need to release new version of it:

OpenIDE-Module-Module: provides.lexer.utils
OpenIDE-Module-SpecificationVersion: '''1.2'''
OpenIDE-Module-Friends: old.friend.one, old.friend.two, uses.lexer.utils

The uses.lexer.utils then needs to requests provides.lexer.utils in version 1.2. List of friends is your API!


Btw. removing someone from list of friends is basically incompatible change in your API and you should produce incompatible version of your module.

Can this happen in OSGi? Well, OSGi by itself does not have support for friends now, so no. But Equinox provides an extended functionality to support this concept and yes, you'd run into same issues there.

Personal tools