ContextFromThreadLocal proposes a pattern to access context information from a ThreadLocal? in a clearly defined way.
ContextObjectsAreEvil because they usually are too big and can cause lots of dependencies. That page also proposes, that
You can also get rid of those dependencies by using a "hidden" variable to pass the ContextObject around, such that only users of the ContextObject are even aware that it exists. Example hidden variables include SpecialVariables and ThreadLocalStorage; more generally, ExplicitManagementOfImplicitContext describes many such tactics. [...]
There are at least two general approaches to context information: Singletons and dependency injection. But if you write a library or framework and don't know your clients beforehand or really have different clients, then you run into trouble with both.
Instead I use the ThreadLocal? pattern to define context values. My code looks like this
class SomeObjectUsedInForeignCode? { Context<Log> LOG = Context.of(new DefaultLog?(), Log.class); void someMethodCalledDeeplyInForeignCode() { LOG.get().log("doing it"); doWhatIsNecessary(); } }This library code can safely log output using the default Log and still be configured to use a different logging method should the client wish so:
Context.runWith(new CustomLog?(), Log.class, new Runnable() { void run() { doSomeVeryComplicatedTasksWhichUltimatelyCallMyAboveMethod(); }});During the whole execution of the Runnable will the LOG Context provide the CustomLog?().
Caveat: Every call LOG.get() variable will access a ThreadLocal? and thus this approach has a certain performance penalty.
Using DependencyInjection and setting a Log variable is faster, but to be able to use it you must inject essentially all variables - otherwise you are unable to later inject a variable in a sub sub sub object. Thats why DependencyInjectionIsaVirus?: You can use it all or nothing. In a library I cannot use it.
The preferred solution to this problem is of course the following functional pearl: http://www.cs.rutgers.edu/~ccshan/prepose/prepose.pdf Sadly this cannot be done in Java; the nearest one could get would be to let a ClassLoader distinguish context instances.