DRAFT PROPOSAL - Pot Pourri - Augmented Stack Traces, ServiceProvider annotation and processor, Enhanced For Loop utility class
Bruce Chapman & Barbara Carey
cadenza at paradise.net.nz
Sat Mar 1 14:41:17 PST 2008
DRAFT PROPOSAL pot Pourri #1
Bruce Colin Chapman
cadenza at paradise.net.nz
I propose three independant additions to the JDK APIs.
o Augmented Stack traces
o ServiceProvider Annotation and Processor
o Enhanced For loop Utility Class
Augmented Stack Trace
=====================
Exceptions allows contextual information to be added at the point they
are thrown (actually
the point they are created but its generally the same location) via
Throwable's message
mechanism. Additional context may be added further up the stack if the
exception is caught
and wrapped in another exception containing the origibal as a cause and
a new message with
the aditional context information. Contextual information is useful and
often critical to
resolving faults.
I propose a mechanism to add contextual information (a short String) to
an Exception's
stack trace at the StackTraceElement corresponding to where the
mechanism is invoked from.
This will be particularly useful when traversing composite pattern data
structures as each
Node can catch any exceptions, augment them with its identity in some
form, and rethrow the
exception.
Also in Java Server Faces, exceptions thrown from managed beans invoked
from EL expressions
in a page can be hard to track down because neither the component
containing the EL
expression or the expression text itself is shown in the stack trace.
This mechanism provides a relatively easy way for key contextual
information to be added to
an exception's stacktrace the exception passes through a method.
StackTraceElement will be extended so that a StackTraceElement will have
a private String
field to contain the augmented context. This will default to null.
Throwable.printStackTrace() will be modified to print the augmented
context String field
(but only the first (say) 60 characters if it is longer) when it is a
available. The
context information will be printed on a line below the ret of the
StackTraceElement.
StackTraceElement will have a static method which will take a Throwable,
and a String. The
string will be added to the Throwable's StackTraceElement which
corresponds to the caller
of the static method.
Assistance From Sun
-------------------
Obtaining the current stack trace depth can be done by getting a current
stack trace and
looking at its length. However experiments show this to be ineffient
from a performance
persepctive. Although the proposal can be implemented with existing JVM
code, a method
similar to Throwable.fillinStackTrace() which merely returned the length
that the stack
trace would if it were to be filled in would improve performance. Such a
method is not part
of this proposal but would aid performance of it.
Service Provider Annotation and Processor
=========================================
Java 6 introduced java.util.ServiceLoader class to perform service
loading as previously
specified in the jar spec (IIRC) but whose implementation was in a sun.*
package.
One of the difficulties of using this mechanism is correctly generating the
/META-INF/services/ file. Although not difficult there is no
verification that the file is
correctly placed and named. Errors in the file's path cause the feature
to appear to
silently fail. Managing the content of the file can be tedious.
I propose a new Annotation with a corresponding AnnotationProcessor
which will create and
maintain the META-INF/services files for any classes that declare
themselves as being
service providers.
There are two approaches to be investigated.
Approach 1.
The annotation will have a single value member to specify the class of
the Service, it is
for this service that the file will be managed.
Approach 2.
The Service provider annotation will be a marker annotation. Another
marker annotation will
be used to identify abstract classes and interfaces which are services
(designed to have
providers loaded by ServiceLoader). In this approach a service
provider's corresponding
service will be discovered by looking for a supertype annotated as a
service.
The Annotation processor will manage the META-INF/services/* files. It
will behave
correctly in the face of incremental compiles. Specifically
Given two classes A and B each annotated as service providers of C then
o IF A and B are compiled together META-INF/services/C will contain A
and B.
o After a clean, if only A is compiled, META-INF/services/C will contain A
o IF B is then compiled, META-INF/services/C will contain both A and B
o If the annotation is removed from A, and A is recompiled,
META-INF/services/C will
contain B.
IF A and B are compiled together META-INF/services/C will contain A and B.
Assistance from Sun
--------------------
None.
Enhanced For loop Utility Class
===============================
I propose a new utility class in java.util with static methods for
creating Iterables from
various types that are not Iterables so that they may be looped over
using JDK5's enhanced
for loop.
The class will be called "In".
It will contain (at least) the following methods
to loop over an Enumeration
static <T> Iterable<T> each(Enumeration<T> enumeration)
To loop (with a single loop) over a number of separate Iterables in sequence
static <T> Iterable<T> sequence(Iterable<? super T>... subsequences)
to Loop (with a single loop) over two Iterables at the same time
static <T,U> Iterable<Pair<T,U>> tandem(Iterable<T> left, Iterable<U> right)
(This would also involve creating java.util.Pair to model a 2 tuple)
I propose to look for other cases where such a helper method would be
valuable, and
implement those. Some ideas are SQL RowSets, parts of DOM with indexed
access and possibly
looping over the lines in a BufferedReader. Inter package dependencies
need to be managed
correctly for these, and also it needs to be done in such a way as to
manage checked
exceptions that may be thrown in the process of implementing next().
The Iterables returned may possibly also be the implementations of
Iterator (for
lightweightness) in which the Iterables will only be able to have their
iterator() method
called once, otherwise an IllegalStateException will be thrown. When
used only in enhanced
for loops this restriction will have no effect. For further investigation.
More information about the challenge-discuss
mailing list