You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2016/07/07 09:18:36 UTC
[02/10] brooklyn-server git commit: Maybe offers more clarity around
whether it creates an exception on Absent
Maybe offers more clarity around whether it creates an exception on Absent
and has a toOptional, and tests
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/785342a4
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/785342a4
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/785342a4
Branch: refs/heads/master
Commit: 785342a4aebe0af47fac1e44205f85c28d320f79
Parents: 1f973df
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Jun 24 22:48:10 2016 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Jun 24 22:52:15 2016 +0100
----------------------------------------------------------------------
.../org/apache/brooklyn/util/guava/Maybe.java | 47 ++++-
.../apache/brooklyn/util/guava/MaybeTest.java | 178 +++++++++++++++++++
2 files changed, 217 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/785342a4/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
index f64d712..73c9761 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
@@ -45,29 +45,54 @@ public abstract class Maybe<T> implements Serializable, Supplier<T> {
private static final long serialVersionUID = -6372099069863179019L;
+ /** Returns an absent indicator. No message is available and access does not include any reference to this creation.
+ * Therefore it is fast and simple, but hard to work with if someone might {@link #get()} it and want a useful exception.
+ * See also {@link #absentNoTrace(String)} to include a message with very low overhead,
+ * or {@link #absentWithTrace(String)} or {@link #absent(Throwable)} for more control over the exception thrown.
+ */
public static <T> Maybe<T> absent() {
- return new Absent<T>();
+ return new Maybe.Absent<T>();
}
- /** Creates an absent whose get throws an {@link IllegalStateException} with the indicated message.
- * Both stack traces (the cause and the callers) are provided, which can be quite handy. */
+ /** Convenience for {@link #absentWithTrace(String)}. */
public static <T> Maybe<T> absent(final String message) {
+ return absent(new IllegalStateException(message));
+ }
+
+ /** Creates an absent whose {@link #get()} throws an {@link IllegalStateException} with the indicated message.
+ * Both stack traces (the cause and the callers) are provided, which can be quite handy,
+ * but comparatively expensive as the cause stack trace has to generated when this method is invoked,
+ * even if it is never accessed. See also {@link #absentNoTrace(String)} and {@link #absent(Throwable)}. */
+ public static <T> Maybe<T> absentWithTrace(final String message) {
+ return absent(new IllegalStateException(message));
+ }
+
+ /** Creates an absent whose get throws an {@link IllegalStateException} with the indicated message,
+ * but not a stack trace for the calling location. As stack traces can be comparatively expensive
+ * this is useful for efficiency, but it can make debugging harder as the origin of the absence is not kept,
+ * in contrast to {@link #absentWithTrace(String)} and {@link #absent(Throwable)}. */
+ public static <T> Maybe<T> absentNoTrace(final String message) {
return absent(new IllegalStateExceptionSupplier(message));
}
- /** Creates an absent whose get throws an {@link IllegalStateException} with the indicated cause.
- * Both stack traces (the cause and the callers) are provided, which can be quite handy. */
+ /** As {@link #absentWithTrace(String)} but using the provided exception instead of this location
+ * as the cause, and a string based on this cause as the message on the {@link IllegalStateException}
+ * thrown if a user does a {@link #get()}.
+ * Useful if an {@link Exception} has already been generated (and no overhead)
+ * or if you want to supply a specific cause as in <code>absent(new MyException(...))</code>
+ * (but there is the Exception creation overhead there). */
public static <T> Maybe<T> absent(final Throwable cause) {
return absent(new IllegalStateExceptionSupplier(cause));
}
- /** Creates an absent whose get throws an {@link IllegalStateException} with the indicated message and underlying cause.
- * Both stack traces (the cause and the callers) are provided, which can be quite handy. */
+ /** As {@link #absent(Throwable)} but using the given message as the message on the {@link IllegalStateException}
+ * thrown if a user does a {@link #get()}. */
public static <T> Maybe<T> absent(final String message, final Throwable cause) {
return absent(new IllegalStateExceptionSupplier(message, cause));
}
- /** Creates an absent whose get throws an {@link RuntimeException} generated on demand from the given supplier */
+ /** Creates an absent whose {@link #get()} throws a {@link RuntimeException}
+ * generated on demand from the given supplier */
public static <T> Maybe<T> absent(final Supplier<? extends RuntimeException> exceptionSupplier) {
return new Absent<T>(Preconditions.checkNotNull(exceptionSupplier));
}
@@ -108,6 +133,12 @@ public abstract class Maybe<T> implements Serializable, Supplier<T> {
public static <T> Maybe<T> of(@Nullable T value) {
return ofAllowingNull(value);
}
+
+ /** Converts the given {@link Maybe} to {@link Optional}, failing if this {@link Maybe} contains null. */
+ public Optional<T> toOptional() {
+ if (isPresent()) return Optional.of(get());
+ return Optional.absent();
+ }
/** Creates a new Maybe object using {@link #ofDisallowingNull(Object)} semantics.
* It is recommended to use that method for clarity.
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/785342a4/utils/common/src/test/java/org/apache/brooklyn/util/guava/MaybeTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/guava/MaybeTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/guava/MaybeTest.java
new file mode 100644
index 0000000..5870303
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/guava/MaybeTest.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.brooklyn.util.guava;
+
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.exceptions.UserFacingException;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Optional;
+
+public class MaybeTest {
+
+ @Test
+ public void testMaybeGet() {
+ Maybe<String> m = Maybe.of("yes");
+ Assert.assertTrue(m.isPresent());
+ Assert.assertEquals(m.get(), "yes");
+ }
+
+ @Test
+ public void testMaybeToOptional() {
+ Maybe<String> m = Maybe.of("yes");
+ Optional<String> o = m.toOptional();
+ Assert.assertTrue(o.isPresent());
+ Assert.assertEquals(o.get(), "yes");
+ }
+
+ @Test
+ public void testMaybeGetNull() {
+ Maybe<String> m = Maybe.ofAllowingNull(null);
+ Assert.assertTrue(m.isPresent());
+ Assert.assertEquals(m.get(), null);
+ }
+
+ @Test
+ public void testMaybeDefaultAllowsNull() {
+ // but note you have to cast it if you try to do it explicitly
+ // (of course normally it's a variable...)
+ Maybe<Object> m = Maybe.of((Object)null);
+ Assert.assertTrue(m.isPresent());
+ Assert.assertEquals(m.get(), null);
+ }
+
+ @Test
+ public void testMaybeDisallowingNull() {
+ Maybe<Object> m = Maybe.ofDisallowingNull(null);
+ try {
+ m.get();
+ Asserts.shouldHaveFailedPreviously();
+ } catch (Exception e) {
+ Asserts.expectedFailureContainsIgnoreCase(e, "null");
+ }
+ }
+
+ @Test
+ public void testMaybeToOptionalFailsOnNull() {
+ Maybe<String> m = Maybe.ofAllowingNull(null);
+ try {
+ m.toOptional();
+ Asserts.shouldHaveFailedPreviously();
+ } catch (Exception e) {
+ Asserts.expectedFailureOfType(e, NullPointerException.class);
+ }
+ }
+
+ @Test
+ public void testMaybeAbsent() {
+ Maybe<String> m = Maybe.absent("nope");
+ Assert.assertFalse(m.isPresent());
+ assertGetFailsContaining(m, "nope");
+ }
+
+ protected Exception assertGetFailsContaining(Maybe<?> m, String phrase) {
+ try {
+ getInExplicitMethod(m);
+ throw Asserts.shouldHaveFailedPreviously();
+ } catch (Exception e) {
+ Asserts.expectedFailureContains(e, phrase);
+ return e;
+ }
+ }
+
+ @Test
+ public void testMaybeAbsentToOptional() {
+ Maybe<String> m = Maybe.absent("nope");
+ Optional<String> o = m.toOptional();
+ Assert.assertFalse(o.isPresent());
+ try {
+ o.get();
+ throw Asserts.shouldHaveFailedPreviously();
+ } catch (Exception e) {
+ Asserts.expectedFailureContains(e, "absent");
+ }
+ }
+
+ // --- now check traces ----
+
+ /** an explicit method we can search for in the trace */
+ protected <T> T getInExplicitMethod(Maybe<T> m) {
+ return m.get();
+ }
+
+ protected boolean containsClassAndMethod(StackTraceElement[] stackTrace, String className, String methodName) {
+ boolean methodFound = (methodName==null);
+ boolean classFound = (className==null);
+ for (StackTraceElement element: stackTrace) {
+ if (className!=null && className.equals(element.getClassName())) classFound = true;
+ if (methodName!=null && methodName.equals(element.getMethodName())) methodFound = true;
+ }
+ return methodFound && classFound;
+ }
+ protected boolean containsGetExplicitMethod(Throwable e) {
+ return containsClassAndMethod(e.getStackTrace(), MaybeTest.class.getName(), "getInExplicitMethod");
+ }
+ protected boolean containsMaybeMethod(Throwable e, String methodName) {
+ return containsClassAndMethod(e.getStackTrace(), Maybe.class.getName(), methodName);
+ }
+
+ @Test
+ public void testMaybeAbsentMessageIncludesSource() {
+ Maybe<Object> m = Maybe.absent("nope");
+ Assert.assertFalse(m.isPresent());
+ Exception e = assertGetFailsContaining(m, "nope");
+
+ e.printStackTrace();
+ Assert.assertTrue(containsGetExplicitMethod(e), "Outer trace should be in explicit method");
+ Assert.assertFalse(containsMaybeMethod(e, "absent"), "Outer trace should not be from 'absent'");
+
+ Assert.assertFalse(containsGetExplicitMethod(e.getCause()), "Inner trace should not be in explicit method");
+ Assert.assertTrue(containsMaybeMethod(e.getCause(), "absent"), "Inner trace should be from 'absent'");
+ }
+
+ @Test
+ public void testMaybeAbsentMessageNoTraceDoesNotIncludeSource() {
+ Maybe<Object> m = Maybe.absentNoTrace("nope");
+ Assert.assertFalse(m.isPresent());
+ Exception e = assertGetFailsContaining(m, "nope");
+ Assert.assertTrue(containsGetExplicitMethod(e), "Outer trace should be in explicit method");
+ Assert.assertFalse(containsMaybeMethod(e, "absentNoTrace"), "Outer trace should not be from 'absentNoTrace'");
+ Assert.assertNull(e.getCause());
+ }
+
+ protected Exception newRE(String message) { return new UserFacingException(message); }
+
+ @Test
+ public void testMaybeAbsentThrowableIncludesGivenSourceOnly() {
+ Maybe<Object> m = Maybe.absent(newRE("nope"));
+ Assert.assertFalse(m.isPresent());
+ Exception e = assertGetFailsContaining(m, "nope");
+ Assert.assertTrue(e instanceof IllegalStateException, "Outer should be ISE, not "+e);
+ Assert.assertTrue(containsGetExplicitMethod(e), "Outer trace should be in explicit method");
+ Assert.assertFalse(containsMaybeMethod(e, "absent"), "Outer trace should not be from 'absent'");
+ Assert.assertFalse(containsMaybeMethod(e, "newRE"), "Outer trace should not be 'newRE'");
+
+ Assert.assertTrue(e.getCause() instanceof UserFacingException, "Inner should be UFE, not "+e.getCause());
+ Assert.assertFalse(containsGetExplicitMethod(e.getCause()), "Inner trace should not be in explicit method");
+ Assert.assertFalse(containsMaybeMethod(e.getCause(), "absent"), "Inner trace should not be from 'absent'");
+ Assert.assertTrue(containsClassAndMethod(e.getCause().getStackTrace(), MaybeTest.class.getName(), "newRE"), "Inner trace SHOULD be from 'newRE'");
+ }
+
+}