Proposed API for JEP 259: Stack-Walking API

Paul Sandoz paul.sandoz at oracle.com
Wed Nov 4 08:46:16 UTC 2015


> On 4 Nov 2015, at 04:50, Mandy Chung <mandy.chung at oracle.com> wrote:
> 
> 
>> On Nov 3, 2015, at 3:28 AM, Paul Sandoz <paul.sandoz at oracle.com> wrote:
>> 
>> Hi Mandy,
>> 
>> This is very nice work.
>> 
>> Comments below, mostly minor stuff.
>> 
> 
> Thanks for the review.
> 
> I fixed most of the comments below.   One question:
> 
> Is the name “StackStream" inappropriate and its subtypes?  I prefer StackStream to StackTraverser.
> 

I think using Stream in the name gives the wrong impression. It’s not a subtype of j.u.Stream, it’s the thing that is used as a source for a Stream, in some cases.

IIUC it’s really two things, a form of Spliterator that supports sequential traversal of stack elements via tryAdvanced/forEachRemaining, and a thing to directly query stack elements.


> 
>> 
>> StackStream
>>>> 
>> Suggest using something other than Stream in the name is this is really about Spliterator and traversal e.g. perhaps StackTraverser. Same for sub-types of StackStream.
>> 
>> 494     @Override
>> 495     public void forEachRemaining(Consumer<? super StackFrame> action) {
>> 496         throw new UnsupportedOperationException("Specialized StackWalker");
>> 497     }
>> 498
>> 499     @Override
>> 500     public boolean tryAdvance(Consumer<? super StackFrame> action) {
>> 501         throw new UnsupportedOperationException("Specialized StackWalker");
>> 502     }
>> 
>> Is this required?
>> 
> 
> CallerClassStream and StackTrace don’t support to use with Stream API for performance.

Then perhaps those classes should implement those methods to throw USO? or there should be a sub-type which indicates Spliterator traversal is not supported? Then i think it becomes much clearer on what sub-types support what contract.

Or maybe the Spliterator can be pushed down to sub-types that are used as the source for a Stream? (I have not re-looked into the details to how awkward this might become.)


> 
>> 
>> 238     private final List<? extends WalkerOption> options;
>> 
>> Do you require the bound here?
>> 
> 
> Sorry WalkerOption has been removed.  I only updated the API but not webrev.00.
> 

Ok, thats good!


>> 
>> 241     /**
>> 242      * Gets a {@code StackWalker} instance.
>> 243      *
>> 244      * <p> This {@code StackWalker} obtains the method name and the class name
>> 245      * with all {@linkplain StackWalker.Option#SHOW_HIDDEN_FRAMES hidden frames}
>> 246      * skipped.
>> 247      */
>> 248     public StackWalker() {
>> 
>> s/Gets/Creates
>> 
>> Same for other constructor methods.
>> 
>> 
>> 252     /**
>> 253      * Gets a {@code StackWalker} instance with the given options specifying
>> 254      * the stack frame information it can access.  If no option is specified, this
>> 255      * {@code StackWalker} obtains the method name and the class name
>> 256      * with all {@linkplain StackWalker.Option#SHOW_HIDDEN_FRAMES hidden frames}
>> 257      * skipped.
>> 
>> If no options are given…
>> 
>> It might be easier to state as if the options were {CLASS_REFERENCE, SHOW_REFLECT_FRAMES}, perhaps it depends if the default is someone under specified i.e. is it guaranteed that the option set will be the complement of the single set SHOW_HIDDEN_FRAMES?
> 
> In fact the default can’t be expressed with the current options.  This is a good point though and I have been considering adding SHOW_METHOD_INFO which will be the default.   I’ll update the API.
> 

Ok.


>> 
>> I guess any unrecognized options are ignored?
>> 
> 
> Now it takes only Option enums.
> 

That’s better.


> 
>> 
>> 430     /**
>> 431      * Gets the {@code Class} object of the caller invoking the method
>> 432      * that calls this {@code getCallerClass} method.
>> 433      *
>> 434      * <p>This is equivalent to calling
>> 435      * <blockquote>
>> 436      * <pre>{@code walk((s) ->}
>> 
>> } -> {
>> 
>> 437      *     s.map(StackFrame::getDeclaringClass)
>> 438      *      .skip(2)
>> 439      *      .findFirst()).orElse(Thread.currentThread().getClass());
>> 440      * </pre></blockquote>
>> 
>> 
>> 441      *
>> 442      * <p>For example, {@code Util::getResourceBundle} loads a resource bundle on behalf
>> 443      * of the caller.  It calls this {@code getCallerClass} method to find the method
>> 444      * calling {@code Util::getResourceBundle} and use the caller's class loader to
>> 445      * load the resource bundle. The caller class in this example is the {@code Foo} class.
>> 
>> 
>> use @apiNote
>> 
>> 
>> BatchSizeMapper
>>>> 
>> As usual i always advice using testng and data providers, up to you.
> 
> I started this one with TestNG but this data provider requires the method to return Object[][].  I automatically resorted to old-school test :)
> 

:-) it’s more of an annoyance, i often compose using a list then convert. I can help out if you like.

IIRC it may also possible to return Iterable<Object[]> or Iterator<Object[]> i cannot remember, but don’t expect the TestNG documentation to tell you that!, you need to look into the source code to work that out.

Paul.



More information about the core-libs-dev mailing list