From 5b35ba8cc0a94f744fd5feaf325aa33222b5b676 Mon Sep 17 00:00:00 2001 From: Zac Sweers Date: Tue, 31 Oct 2017 01:27:29 +0300 Subject: [PATCH] Plugin for controlling whether or not to fill in stacktraces (#124) * Implement fillInOutsideLifecycleExceptionStacktraces plugin This implements support for controlling whether or not `OutsideLifecycleException`s fill in their stacktraces. This is a potentially expensive operation that is often used just for signaling, so we can save a little perf here. * Add tests --- .../uber/autodispose/AutoDisposePlugins.java | 24 +++++++- .../OutsideLifecycleException.java | 8 +++ .../autodispose/AutoDisposePluginsTest.java | 60 +++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 autodispose/src/test/java/com/uber/autodispose/AutoDisposePluginsTest.java diff --git a/autodispose/src/main/java/com/uber/autodispose/AutoDisposePlugins.java b/autodispose/src/main/java/com/uber/autodispose/AutoDisposePlugins.java index 8cb95e98d..6353a509f 100644 --- a/autodispose/src/main/java/com/uber/autodispose/AutoDisposePlugins.java +++ b/autodispose/src/main/java/com/uber/autodispose/AutoDisposePlugins.java @@ -28,6 +28,7 @@ private AutoDisposePlugins() { } @Nullable private static volatile Consumer outsideLifecycleHandler; + private static volatile boolean fillInOutsideLifecycleExceptionStacktraces; /** * Prevents changing the plugins. @@ -53,7 +54,15 @@ public static boolean isLockdown() { } /** - * @return the consumer for handling {@link OutsideLifecycleException}. + * @return the value indicating whether or not to fill in stacktraces in + * {@link OutsideLifecycleException}. + */ + public static boolean getFillInOutsideLifecycleExceptionStacktraces() { + return fillInOutsideLifecycleExceptionStacktraces; + } + + /** + * @return the value for handling {@link OutsideLifecycleException}. */ @Nullable public static Consumer getOutsideLifecycleHandler() { @@ -71,6 +80,19 @@ public static void setOutsideLifecycleHandler( outsideLifecycleHandler = handler; } + /** + * @param fillInStacktrace {@code true} to fill in stacktraces in + * {@link OutsideLifecycleException}s. {@code false} to disable them (and use them as signals + * only). Disabling them, if you don't care about the stacktraces, can result in some minor + * performance improvements. + */ + public static void setFillInOutsideLifecycleExceptionStacktraces(boolean fillInStacktrace) { + if (lockdown) { + throw new IllegalStateException("Plugins can't be changed anymore"); + } + fillInOutsideLifecycleExceptionStacktraces = fillInStacktrace; + } + /** * Removes all handlers and resets to default behavior. */ diff --git a/autodispose/src/main/java/com/uber/autodispose/OutsideLifecycleException.java b/autodispose/src/main/java/com/uber/autodispose/OutsideLifecycleException.java index 91a670f62..5e0870d4f 100755 --- a/autodispose/src/main/java/com/uber/autodispose/OutsideLifecycleException.java +++ b/autodispose/src/main/java/com/uber/autodispose/OutsideLifecycleException.java @@ -24,4 +24,12 @@ public class OutsideLifecycleException extends RuntimeException { public OutsideLifecycleException(String s) { super(s); } + + @Override public final synchronized Throwable fillInStackTrace() { + if (AutoDisposePlugins.getFillInOutsideLifecycleExceptionStacktraces()) { + return super.fillInStackTrace(); + } else { + return this; + } + } } diff --git a/autodispose/src/test/java/com/uber/autodispose/AutoDisposePluginsTest.java b/autodispose/src/test/java/com/uber/autodispose/AutoDisposePluginsTest.java new file mode 100644 index 000000000..bd8126a64 --- /dev/null +++ b/autodispose/src/test/java/com/uber/autodispose/AutoDisposePluginsTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017. Uber Technologies + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.uber.autodispose; + +import org.junit.After; +import org.junit.Test; + +import static com.google.common.truth.Truth.assertThat; + +public final class AutoDisposePluginsTest { + + @After public void tearDown() { + AutoDisposePlugins.reset(); + } + + @Test public void noStacktraceFill_shouldHaveNoStacktrace() { + AutoDisposePlugins.setFillInOutsideLifecycleExceptionStacktraces(false); + + LifecycleNotStartedException started = + new LifecycleNotStartedException("Lifecycle not started"); + assertThat(started.getStackTrace()).isEmpty(); + + LifecycleEndedException ended = new LifecycleEndedException("Lifecycle ended"); + assertThat(ended.getStackTrace()).isEmpty(); + } + + @Test public void defaultStacktraceFill_shouldHaveStacktrace() { + LifecycleNotStartedException started = + new LifecycleNotStartedException("Lifecycle not started"); + assertThat(started.getStackTrace()).isNotEmpty(); + + LifecycleEndedException ended = new LifecycleEndedException("Lifecycle ended"); + assertThat(ended.getStackTrace()).isNotEmpty(); + } + + @Test public void trueStacktraceFill_shouldHaveStacktrace() { + AutoDisposePlugins.setFillInOutsideLifecycleExceptionStacktraces(true); + + LifecycleNotStartedException started = + new LifecycleNotStartedException("Lifecycle not started"); + assertThat(started.getStackTrace()).isNotEmpty(); + + LifecycleEndedException ended = new LifecycleEndedException("Lifecycle ended"); + assertThat(ended.getStackTrace()).isNotEmpty(); + } +}