This seems problematic to me, because it breaks the expectation that the most 
important part of the stack trace can be found at the bottom of the it. In this 
case, if someone subsequently wraps the original exception in their own 
Exception the causal chain then gets jumbled. I actually wish printStackTrace 
processed the exceptions in the main trace  in reverse compared to how it is 
now. If, rather than finding this at the end of a stack trace:

Caused by: org.osgi.framework.BundleException: Error starting module.
        at org.eclipse.osgi.container.Module.doStart(Module.java:580)
        at org.eclipse.osgi.container.Module.start(Module.java:439)
        at 
org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:454)
        at 
org.eclipse.osgi.internal.hooks.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:107)
        ... 57 more
Caused by: java.lang.NoClassDefFoundError: 
org/eclipse/jdt/debug/core/IJavaHotCodeReplaceListener
        at java.lang.Class.getDeclaredConstructors0(Native Method)
        at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
        [snip]
        at 
org.eclipse.osgi.internal.framework.EquinoxBundle$EquinoxModule.startWorker(EquinoxBundle.java:318)
        at org.eclipse.osgi.container.Module.doStart(Module.java:571)
        ... 60 more
Caused by: java.lang.ClassNotFoundException: 
org.eclipse.jdt.debug.core.IJavaHotCodeReplaceListener cannot be found by 
org.eclipse.jdt.debug.ui_3.6.400.qualifier
        at 
org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:432)
        at 
org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:345)
        at 
org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:337)
        at 
org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:160)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 69 more

You would instead see it like this at the beginning of the stack trace:

java.lang.ClassNotFoundException: 
org.eclipse.jdt.debug.core.IJavaHotCodeReplaceListener cannot be found by 
org.eclipse.jdt.debug.ui_3.6.400.qualifier
        at 
org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:432)
        at 
org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:345)
        at 
org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:337)
        at 
org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:160)
        at java.lang.ClassLoader.loadClass(Unknown Source)
Causing: java.lang.NoClassDefFoundError: 
org/eclipse/jdt/debug/core/IJavaHotCodeReplaceListener
        at java.lang.Class.getDeclaredConstructors0(Native Method)
        at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
        [snip]
        at 
org.eclipse.osgi.internal.framework.EquinoxBundle$EquinoxModule.startWorker(EquinoxBundle.java:318)
        at org.eclipse.osgi.container.Module.doStart(Module.java:571)
Causing: org.osgi.framework.BundleException: Error starting module.
        at org.eclipse.osgi.container.Module.doStart(Module.java:580)
        at org.eclipse.osgi.container.Module.start(Module.java:439)
        at 
org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:454)
        at 
org.eclipse.osgi.internal.hooks.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:107)
Causing: java.lang.ClassNotFoundException: An error occurred while 
automatically activating bundle org.eclipse.jdt.debug.ui (186).
        at 
org.eclipse.osgi.internal.hooks.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:116)
        at 
org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalClass(ClasspathManager.java:531)

See how even the handoff from one handler to another is now readily apparent? 
The right place where the next part of the trace should appear is quite 
obvious. 





-- 
Have a nice day, 
Timo

Sent from Mail for Windows 10



From: Peter Levart
Sent: Thursday, December 10, 2015 09:04
To: Martin Buchholz;Jason Mehrens;Doug Lea
Cc: core-libs-dev
Subject: Re: RFR: jsr166 jdk9 integration wave 2


Hi Martin,

On 12/10/2015 12:18 AM, Martin Buchholz wrote:
> I finally studied ForkJoinTask.getThrowableException - I was not aware
> that we were doing reflection based exception cloning.  In practice it
> probably muddles through, but it just seems too hacky to use in a java
> core library.  We're relying on common conventions, but in principle
> we are invoking random code with an unknown spec.  The stack traces
> created are fake in the sense that they are not created naturally, and
> the thrown exception may differ from the original in significant ways,
> most notably missing the message string.  With heroic efforts we can
> make it safer, e.g. examine the bytecode for the constructors we are
> invoking, and check whether they call the super constructors in the
> right way, but that will be a major engineering project by itself.

I assume the aim of exception cloning in 
ForkJoinTask.getThrowableException is to provide the user with a 
stack-trace that originates in its own thread. This helps trace the 
origin of the exception in case it's handled way up in the call stack. 
In addition, the original stack trace is also preserved (original 
exception is added as a cause).

This case does not suffer from the visibility of original exception 
before ForkJoinTask.getThrowableException is called, so perhaps the aim 
could be achieved in a slightly different manner: just return the 
original exception, but add a newly constructed 
CrossThreadPropagationException as a suppressed exception to it. 
Printing such augmented original exception would then reveal both stack 
traces. What do you think?

>
> For CompletableFuture.whenComplete: I also keep moving in the
> direction of less magic.  It is perfectly possible for a well-written
> whenComplete action to catch all Throwables, add the source exception
> as a suppressed exception, and rethrow.  In fact, perhaps people have
> already tried this and discovered we incorrectly throw the source
> exception.  I think we should really accept our mistake and switch to
> throwing the action exception rather than the source exception.
> Perhaps we should only call addSuppressed if the source exception is
> not already in the list of suppressed exceptions.

Less is more. I would even not bother with the additional logic of 
conditionally adding source exception to the list of suppressed 
exceptions. I doubt many codes out there do that in the whenComplete 
handler since such exception was ignored up until now. And if anybody 
does that, she will get the source exception listed twice - not a big 
deal. If javadoc describes the behavior, this will not happen frequently.

Regards, Peter

>
>
> On Thu, Dec 3, 2015 at 9:54 AM, Jason Mehrens <jason_mehr...@hotmail.com> 
> wrote:
>> Hi Peter,
>>
>> I've done this trick before to perform Throwable cloning.  You have to hunt 
>> for the constructors in this order:
>> 1. Walk the type of the cause and super types by calling 
>> getConstructor(String, type of cause). (java.io.WriteAbortedException and 
>> javax.mail.MessagingException)
>> 2. Walk the type of the cause and super types by calling getConstructor(type 
>> of cause, String)  (I've seen this but, I can't seem to find an example)
>> 3. getConstructor(String) + initCause (java.io.InvalidObjectException)
>> 4. Walk the type of the cause and super types by calling getConstructor(type 
>> of cause). (java.awt.print.PrinterIOException)
>> 5. getConstructor() + initCause.  (java.nio.BufferOverflowException)
>> 6. Look at the return type of methods declared in the cause type and assume 
>> there is a constructor matching the type or no repeating types. 
>> (java.nio.charset.MalformedInputException, 
>> java.lang.EnumConstantNotPresentException, 
>> java.util.regex.PatternSyntaxException)
>>
>> In the end all of that can still fail.  Exceptions can be private subclasses 
>> of public classes so that gets interesting with reflection too.
>>
>> Jason
>>
>>
>> ===========
>> What about the 4th option (keep current behavior, but try the
>> best-effort with reflection to make new exception of the same type):
>>
>> ...
>>               } catch (Throwable ex) {
>>                   if (x == null) {
>>                       x = ex;
>>                   } else {
>>                       // try to create new exception with same:
>>                       // type, cause, suppressed exceptions and
>> stack-trace...
>>                       Throwable nx;
>>                       Class<?> xClass = x.getClass();
>>                       try {
>>                           Constructor<?> xConstr =
>> xClass.getConstructor(Throwable.class);
>>                           nx = (Throwable) xConstr.newInstance(x.getCause());
>>                       } catch (Exception e1) {
>>                           try {
>>                               nx = (Throwable) xClass.newInstance();
>>                               nx.initCause(x.getCause());
>>                           } catch (Exception e2) {
>>                               // no luck
>>                               nx = null;
>>                           }
>>                       }
>>                       if (nx != null) {
>>                           // inherit stack-trace of original exception
>>                           nx.setStackTrace(x.getStackTrace());
>>                           // inherit suppressed exceptions
>>                           for (Throwable sx : x.getSuppressed()) {
>>                               nx.addSuppressed(sx);
>>                           }
>>                           // add 'ex' as a final suppressed exception
>>                           nx.addSuppressed(ex);
>>                           x = nx;
>>                       }
>>                   }
>>               }
>>               completeThrowable(x, r);
>>
>> ...
>>
>>
>>
>> Note that such code and similar code in
>> ForkJoinTask.getThrowableException will probably have to be modified for
>> jigsaw to include dynamic addition of read-edge to the module of
>> exception class...
>>
>> Regards, Peter
>>



Reply via email to