From 844ba49c766b95e199b5908fcdc0f0eb925f9cca Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 26 Aug 2017 20:39:39 +0100 Subject: [PATCH] Value: Avoid danger of JVM-level deadlock during initialisation --- CHANGELOG | 1 + .../kemitix/conditional/FalseCondition.java | 2 +- .../kemitix/conditional/FalseValueClause.java | 64 +++++++++++++ .../kemitix/conditional/TrueCondition.java | 2 +- .../kemitix/conditional/TrueValueClause.java | 69 ++++++++++++++ .../java/net/kemitix/conditional/Value.java | 94 +------------------ 6 files changed, 138 insertions(+), 94 deletions(-) create mode 100644 src/main/java/net/kemitix/conditional/FalseValueClause.java create mode 100644 src/main/java/net/kemitix/conditional/TrueValueClause.java diff --git a/CHANGELOG b/CHANGELOG index d23865d..9eb5da8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ CHANGELOG ----- * Add `.travis-support` +* Avoid danger of JVM-level deadlock during `Value` initialisation * Avoid danger of JVM-level deadlock during `Condition` initialisation * Upgrade `kemitix-parent` to 3.2.0 * Upgrade `kemitix-checkstyle-parent` to 3.2.0 diff --git a/src/main/java/net/kemitix/conditional/FalseCondition.java b/src/main/java/net/kemitix/conditional/FalseCondition.java index 8695649..165a649 100644 --- a/src/main/java/net/kemitix/conditional/FalseCondition.java +++ b/src/main/java/net/kemitix/conditional/FalseCondition.java @@ -26,7 +26,7 @@ package net.kemitix.conditional; * * @author Paul Campbell (pcampbell@kemitix.net). */ -public final class FalseCondition implements Condition { +final class FalseCondition implements Condition { protected static final Condition FALSE = new net.kemitix.conditional.FalseCondition(); diff --git a/src/main/java/net/kemitix/conditional/FalseValueClause.java b/src/main/java/net/kemitix/conditional/FalseValueClause.java new file mode 100644 index 0000000..e0143e0 --- /dev/null +++ b/src/main/java/net/kemitix/conditional/FalseValueClause.java @@ -0,0 +1,64 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Paul Campbell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.kemitix.conditional; + +import java.util.function.Supplier; + +/** + * An intermediate state where the clause has evaluated to false. + * + * @param the type of the value + * + * @author Paul Campbell (pcampbell@kemitix.net). + */ +class FalseValueClause implements Value.ValueClause { + + protected static final Value.ValueClause FALSE = new FalseValueClause(); + + @Override + public ValueSupplier then(final Supplier trueSupplier) { + return new FalseValueSupplier(); + } + + @Override + public Value.ValueClause and(final boolean clause) { + return this; + } + + @Override + public Value.ValueClause or(final boolean clause) { + return Value.where(clause); + } + + /** + * An intermediate result of the {@link Value} where the clause has evaluated to false. + */ + private class FalseValueSupplier implements ValueSupplier { + + @Override + public T otherwise(final Supplier falseSupplier) { + return falseSupplier.get(); + } + + } + +} diff --git a/src/main/java/net/kemitix/conditional/TrueCondition.java b/src/main/java/net/kemitix/conditional/TrueCondition.java index ba15c80..d2132d1 100644 --- a/src/main/java/net/kemitix/conditional/TrueCondition.java +++ b/src/main/java/net/kemitix/conditional/TrueCondition.java @@ -26,7 +26,7 @@ package net.kemitix.conditional; * * @author Paul Campbell (pcampbell@kemitix.net). */ -public final class TrueCondition implements Condition { +final class TrueCondition implements Condition { protected static final Condition TRUE = new net.kemitix.conditional.TrueCondition(); diff --git a/src/main/java/net/kemitix/conditional/TrueValueClause.java b/src/main/java/net/kemitix/conditional/TrueValueClause.java new file mode 100644 index 0000000..c98f2be --- /dev/null +++ b/src/main/java/net/kemitix/conditional/TrueValueClause.java @@ -0,0 +1,69 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Paul Campbell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.kemitix.conditional; + +import lombok.RequiredArgsConstructor; + +import java.util.function.Supplier; + +/** + * An intermediate state where the clause has evaluated to true. + * + * @param the type of the value + * + * @author Paul Campbell (pcampbell@kemitix.net). + */ +class TrueValueClause implements Value.ValueClause { + + protected static final Value.ValueClause TRUE = new TrueValueClause(); + + @Override + public ValueSupplier then(final Supplier trueSupplier) { + return new TrueValueSupplier(trueSupplier); + } + + @Override + public Value.ValueClause and(final boolean clause) { + return Value.where(clause); + } + + @Override + public Value.ValueClause or(final boolean clause) { + return this; + } + + /** + * An intermediate result of the {@link Value} where the clause has evaluated to true. + */ + @RequiredArgsConstructor + private class TrueValueSupplier implements ValueSupplier { + + private final Supplier valueSupplier; + + @Override + public T otherwise(final Supplier falseSupplier) { + return valueSupplier.get(); + } + + } + +} diff --git a/src/main/java/net/kemitix/conditional/Value.java b/src/main/java/net/kemitix/conditional/Value.java index 5944a2d..24908c2 100644 --- a/src/main/java/net/kemitix/conditional/Value.java +++ b/src/main/java/net/kemitix/conditional/Value.java @@ -21,14 +21,7 @@ package net.kemitix.conditional; -import lombok.RequiredArgsConstructor; - -import java.util.AbstractMap.SimpleEntry; -import java.util.Collections; -import java.util.Map; import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** * A Value from an if-then-else in a functional-style. @@ -37,14 +30,6 @@ import java.util.stream.Stream; */ public interface Value { - ValueClause TRUE = new TrueValueClause(); - - ValueClause FALSE = new FalseValueClause(); - - Map VALUE_CLAUSES = Collections.unmodifiableMap( - Stream.of(new SimpleEntry<>(true, TRUE), new SimpleEntry<>(false, FALSE)) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); - /** * Create a new {@link ValueClause} for the clause. * @@ -53,9 +38,9 @@ public interface Value { * * @return a true or false value clause */ - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "avoidinlineconditionals"}) static ValueClause where(final boolean clause) { - return (ValueClause) VALUE_CLAUSES.get(clause); + return (ValueClause) (clause ? TrueValueClause.TRUE : FalseValueClause.FALSE); } /** @@ -146,79 +131,4 @@ public interface Value { } - /** - * An intermediate state where the clause has evaluated to true. - * - * @param the type of the value - */ - class TrueValueClause implements ValueClause { - - @Override - public ValueSupplier then(final Supplier trueSupplier) { - return new TrueValueSupplier(trueSupplier); - } - - @Override - public ValueClause and(final boolean clause) { - return Value.where(clause); - } - - @Override - public ValueClause or(final boolean clause) { - return this; - } - - /** - * An intermediate result of the {@link Value} where the clause has evaluated to true. - */ - @RequiredArgsConstructor - private class TrueValueSupplier implements ValueSupplier { - - private final Supplier valueSupplier; - - @Override - public T otherwise(final Supplier falseSupplier) { - return valueSupplier.get(); - } - - } - - } - - /** - * An intermediate state where the clause has evaluated to false. - * - * @param the type of the value - */ - class FalseValueClause implements ValueClause { - - @Override - public ValueSupplier then(final Supplier trueSupplier) { - return new FalseValueSupplier(); - } - - @Override - public ValueClause and(final boolean clause) { - return this; - } - - @Override - public ValueClause or(final boolean clause) { - return Value.where(clause); - } - - /** - * An intermediate result of the {@link Value} where the clause has evaluated to false. - */ - private class FalseValueSupplier implements ValueSupplier { - - @Override - public T otherwise(final Supplier falseSupplier) { - return falseSupplier.get(); - } - - } - - } - }