Using org.openide.util.Lookup on Android

DZone 's Guide to

Using org.openide.util.Lookup on Android

· Java Zone ·
Free Resource

blueBill Mobile for Android is almost ready for primetime - apart from the quality stuff. As an exception to my common practices, I didn't go with TDD since learning Android and tuning my personal coding style is already a demanding task (I also have still to learn how to run Android specific tests that, if I understand well, can be executed on the device).


Today I ran a fundamental round of refactorings trying to apply the best solution for the problem described by a specific question on the Android FAQ: "How do I pass data between Activities/Services within a single application?". For the most generic case (share any kind of Java object) there is no specific infrastructure in Android. The official FAQ answer is:

There are advantages to using a static Singleton, such as you can refer to them without casting getApplication() to an application-specific class, or going to the trouble of hanging an interface on all your Application subclasses so that your various modules can refer to that interface instead.

The predefined Application class, that can be subclassed and provide a custom context for my appplication, would introduce a dependency on Android on virtually each class of my project - no good. On the other hand, the singleton intended in strict sense has got a lot of well known troubles, as introducing unneeded couplings and making tests hard to write and maintain. A "good" context object is one that can be mocked and provide mocked services when needed. It's not hard to do, but... wait a minute. Isn't org.openide.util.Lookup exactly this kind of stuff?

It is of course! And since it's one of my common tools, it would fit nicely with the rest of my code that is already using it. Furthermore, I have got my tiny but functional dependency injection library based on the annotations of JSR-330, that perhaps could be used on Android too (to be checked against the performance warnings that people gave me when using reflection).

In the end, there's a good bunch of reasons for using Lookup in blueBill Mobile for Android, and in fact I can proudly say that I'm using it since a few hours.

Unfortunately, things weren't easy as Lookup doesn't work out-of-the-box; also when using it at its minimum capabilities (in an Android application you don't usually have modules that come and go as in a regular desktop application, so I basically don't need - at least at the moment - its dynamic capabilities).

The problems are with the Android classloaders and the .dex bytecode. I presumed I had understood all the implications, but I have to go back to the drawing board, as all my tryings ended up in ClassNotFoundExceptions or ClassCastExceptions. Furthermore, it sounds as it's impossible to load resources embedded in the application with ClassLoader.getResources() - the facility which Lookup relies on for retrieving information stored in META-INF/services. Last but not least, I would like to have also some standard Android resources, such as Context, AssetManager and SharedPreferences, to be available in the default Lookup. These classes can't be found by Lookup in the regular way, but must be forced into it in some way.

So, my solution for today is first to subclass Lookup:

package it.tidalwave.bluebill.mobile.android;

import android.content.Context;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import org.openide.util.Lookup;
import org.openide.util.lookup.Lookups;
import android.preference.PreferenceManager;
import it.tidalwave.bluebill.observation.ObservationManager;
import it.tidalwave.mobile.LazyLookup;
import it.tidalwave.mobile.FileSystem;
import it.tidalwave.mobile.LocationFinder;
import it.tidalwave.mobile.android.AndroidFileSystem;
import it.tidalwave.mobile.android.AndroidLocationFinder;
import it.tidalwave.bluebill.mobile.observation.ObservationClipboard;
import it.tidalwave.bluebill.mobile.observation.BlueBillObservationManager;
import it.tidalwave.bluebill.mobile.observation.DefaultObservationPreferences;
import it.tidalwave.bluebill.mobile.observation.ObservationPreferences;
import it.tidalwave.bluebill.mobile.taxonomy.TaxonomyPreferences;
import it.tidalwave.bluebill.mobile.android.location.AndroidLocationPreferences;
import it.tidalwave.bluebill.mobile.location.LocationPreferences;
import it.tidalwave.bluebill.mobile.android.taxonomy.AndroidTaxonomyPreferences;

public class BlueBillLookup extends Lookup
private final LazyLookup lookup = new LazyLookup();

private Lookup extraLookup = Lookup.EMPTY;

public BlueBillLookup()

public <T> T lookup (final @Nonnull Class<T> clazz)
final T r = extraLookup.lookup(clazz);
return (r != null) ? r : lookup.lookup(clazz);

@Override @Nonnull
public <T> Result<T> lookup (final @Nonnull Template<T> template)
final Result<T> r = extraLookup.lookup(template);
return (r != null) ? r : lookup.lookup(template);

public void setContext (final @Nonnull Context context)
extraLookup = Lookups.fixed(context,

As you can see, the implementation is a proxy that searches for objects in two delegates. The former is initialized in the constructor and explicitly filled with all my service classes; the latter is created in a second time, after setContext() is called. This approach is required since apparently there's no static factory method for getting a Context, so it must be provided after the BlueBillLookup has been created. LazyLookup is a simple implementation that registers the class and postpones the actual instantiation of the required service as late as possible - this is consistent with the standard behaviour of Lookup implementations.

The standard Lookup class has got a number of ways for the programmer to provide his own implementation behind the scenes of Lookup.getDefault(): a class name in a system property, or a Lookup or Lookup.Provider class registered in META-INF/services. Unfortunately, as I said before, I wasn't able to make any of those work because of issues with the classloader. I think that these issues can be solved (after all, OSGi can run on Android and it's heavily classloader-based), but need to learn more stuff. So, I resorted to an old trick of NetBeans developers that relies on reflection:

package it.tidalwave.bluebill.mobile.android;

import java.lang.reflect.Field;
import org.openide.util.Lookup;
import android.app.Application;

public class BlueBillApplication extends Application
public void onCreate()

final Field defaultLookup = Lookup.class.getDeclaredField("defaultLookup");
final BlueBillLookup blueBillLookup = new BlueBillLookup();
defaultLookup.set(null, blueBillLookup);
catch (Exception e)
throw new RuntimeException(e);

Properly configured in the Android manifest, BlueBillApplication gets notified of the fundamental life-cycle events of the application and is able to initialize the global Lookup before any other part of the application kicks in.


What's ahead? I need to better understand the part about how Android does (not) manage resources embedded in jar files. If it's an unworkable limitation, one alternative could be to use the Maven Shade plugin that is able to transform and relocate files in a jar; it could copy the content of the META-INF/services/* directory in a properly Android-style resource under 'res' or 'assets'. In the same way, I could replace the code inside org-openide-util.jar that scans META-INF/services with a proper alternate implementation.

Also, I've also run into some incompatibilities between Lookup and the Android runtime. For instance, an internal implementation class had to be patched, as it raised an exception that doesn't occur with the Sun JDK; and there's an internal dependency on a simple event-related class of Swing, that is not available in Android. The Maven Shade plugin, that is able to replace single pieces in JAR contents and even renaming all the references to a given class, proved to be ok to deal with this kind of problems, as it allowed me to provide a patched for the broken class and the missing class without having to fork the original sources. I'm not going into details about this stuff, since in the end these fixes aren't needed in my current trunk - maybe I'll be back with this topic in a new post.


Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}