From 6113458241d6e874c3ae263163f850a00545d437 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 31 Oct 2016 22:43:52 -0700 Subject: [PATCH] Morphed ForwardingEquality into LazyForwardingEquality. --- ...ality.java => LazyForwardingEquality.java} | 43 ++++++++++++------ ...t.java => LazyForwardingEqualityTest.java} | 45 +++++++++---------- 2 files changed, 52 insertions(+), 36 deletions(-) rename src/main/java/com/diffplug/gradle/spotless/{ForwardingEquality.java => LazyForwardingEquality.java} (60%) rename src/test/java/com/diffplug/gradle/spotless/{ForwardingEqualityTest.java => LazyForwardingEqualityTest.java} (52%) diff --git a/src/main/java/com/diffplug/gradle/spotless/ForwardingEquality.java b/src/main/java/com/diffplug/gradle/spotless/LazyForwardingEquality.java similarity index 60% rename from src/main/java/com/diffplug/gradle/spotless/ForwardingEquality.java rename to src/main/java/com/diffplug/gradle/spotless/LazyForwardingEquality.java index b067060e89..b2d3e35a7d 100644 --- a/src/main/java/com/diffplug/gradle/spotless/ForwardingEquality.java +++ b/src/main/java/com/diffplug/gradle/spotless/LazyForwardingEquality.java @@ -22,25 +22,42 @@ import java.io.Serializable; import java.util.Objects; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * Implements equality, hashcode, and serialization entirely in terms - * of the given key. It is appropriate for subclasses of this class - * to use `@SuppressWarnings("serial")`. + * of a lazily-computed key. */ @SuppressWarnings("serial") -public abstract class ForwardingEquality implements Serializable { - private T key; +public abstract class LazyForwardingEquality implements Serializable { + /** Null indicates that the key has not yet been set. */ + @Nullable + private transient volatile T key; - ForwardingEquality(T key) { - this.key = Objects.requireNonNull(key); - } + /** + * This function is guaranteed to be called at most once. + * If the key is never required, then it will never be called at all. + */ + @Nonnull + protected abstract T calculateKey(); - protected T key() { + /** Returns the underlying key, possibly triggering a call to {{@link #calculateKey()}. */ + @Nonnull + protected final T key() { + // double-checked locking for lazy evaluation of calculateKey + if (key == null) { + synchronized (this) { + if (key == null) { + key = calculateKey(); + } + } + } return key; } private void writeObject(ObjectOutputStream out) throws IOException { - out.writeObject(key); + out.writeObject(key()); } @SuppressWarnings("unchecked") @@ -54,18 +71,18 @@ private void readObjectNoData() throws ObjectStreamException { } @Override - public boolean equals(Object other) { + public final boolean equals(Object other) { if (other == null) { return false; } else if (getClass().equals(other.getClass())) { - return key.equals(((ForwardingEquality) other).key); + return key().equals(((LazyForwardingEquality) other).key()); } else { return false; } } @Override - public int hashCode() { - return key.hashCode(); + public final int hashCode() { + return key().hashCode(); } } diff --git a/src/test/java/com/diffplug/gradle/spotless/ForwardingEqualityTest.java b/src/test/java/com/diffplug/gradle/spotless/LazyForwardingEqualityTest.java similarity index 52% rename from src/test/java/com/diffplug/gradle/spotless/ForwardingEqualityTest.java rename to src/test/java/com/diffplug/gradle/spotless/LazyForwardingEqualityTest.java index 3c053e9d03..c5a5900548 100644 --- a/src/test/java/com/diffplug/gradle/spotless/ForwardingEqualityTest.java +++ b/src/test/java/com/diffplug/gradle/spotless/LazyForwardingEqualityTest.java @@ -15,30 +15,37 @@ */ package com.diffplug.gradle.spotless; +import static com.diffplug.common.testing.SerializableTester.*; + import org.junit.Test; import com.diffplug.common.testing.EqualsTester; -import com.diffplug.common.testing.SerializableTester; -public class ForwardingEqualityTest { +@SuppressWarnings("serial") +public class LazyForwardingEqualityTest { static Str s(String key) { return new Str(key); } - @SuppressWarnings("serial") - static class Str extends ForwardingEquality { + static Other o(String key) { + return new Other(key); + } + + static class Str extends LazyForwardingEquality { + private String key; + Str(String key) { - super(key); + this.key = key; } - } - static Int i(int key) { - return new Int(key); + @Override + protected String calculateKey() { + return key; + } } - @SuppressWarnings("serial") - static class Int extends ForwardingEquality { - Int(int key) { + static class Other extends Str { + Other(String key) { super(key); } } @@ -46,18 +53,10 @@ static class Int extends ForwardingEquality { @Test public void testEquality() { new EqualsTester() - .addEqualityGroup(s("hello"), s("hello"), s("h" + "ello")) - .addEqualityGroup(s("world"), s("world"), s("wor" + "ld")) - .addEqualityGroup(i(3), i(3), i(1 + 2)) - .addEqualityGroup(i(-6), i(-6), i(1 - 7)) + .addEqualityGroup(s("hello"), reserializeAndAssert(s("hello"))) + .addEqualityGroup(s("world"), reserializeAndAssert(s("world"))) + .addEqualityGroup(o("hello"), reserializeAndAssert(o("hello"))) + .addEqualityGroup(o("world"), reserializeAndAssert(o("world"))) .testEquals(); } - - @Test - public void testSerialization() { - SerializableTester.reserializeAndAssert(s("hello")); - SerializableTester.reserializeAndAssert(s("world")); - SerializableTester.reserializeAndAssert(i(4)); - SerializableTester.reserializeAndAssert(i(-6)); - } }