From e36ddab627578bdbcc1d40c0c3303f40887f5a66 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Sun, 15 Jan 2017 16:38:08 -0800 Subject: [PATCH] FormatExceptionPolicy implementations need to implement Serializable and equals/hashCode with the same constraints as SerializableFileFilter. Refactored the `toBytes()` method into the interface `NoLambda`, and moved `SerializableFileFilter.EqualityBasedOnSerialization` to `NoLambda.EqualityBasedOnSerialization`. Technically a breaking change, but will affect exactly zero real-world client code. --- .../spotless/FormatExceptionPolicy.java | 2 +- .../spotless/FormatExceptionPolicyLegacy.java | 7 +- .../java/com/diffplug/spotless/NoLambda.java | 71 +++++++++++++++++++ .../spotless/SerializableFileFilter.java | 40 +---------- .../spotless/SerializableFileFilterImpl.java | 2 +- 5 files changed, 75 insertions(+), 47 deletions(-) create mode 100644 lib/src/main/java/com/diffplug/spotless/NoLambda.java diff --git a/lib/src/main/java/com/diffplug/spotless/FormatExceptionPolicy.java b/lib/src/main/java/com/diffplug/spotless/FormatExceptionPolicy.java index c048f60869..10f8d4c0e5 100644 --- a/lib/src/main/java/com/diffplug/spotless/FormatExceptionPolicy.java +++ b/lib/src/main/java/com/diffplug/spotless/FormatExceptionPolicy.java @@ -20,7 +20,7 @@ import java.nio.file.Path; /** A policy for handling exceptions in the format. */ -public interface FormatExceptionPolicy extends Serializable { +public interface FormatExceptionPolicy extends Serializable, NoLambda { /** Called for every error in the formatter. */ void handleError(Throwable e, FormatterStep step, File file, Path rootDir); diff --git a/lib/src/main/java/com/diffplug/spotless/FormatExceptionPolicyLegacy.java b/lib/src/main/java/com/diffplug/spotless/FormatExceptionPolicyLegacy.java index f87e4b1af3..cb8a40a1f4 100644 --- a/lib/src/main/java/com/diffplug/spotless/FormatExceptionPolicyLegacy.java +++ b/lib/src/main/java/com/diffplug/spotless/FormatExceptionPolicyLegacy.java @@ -20,7 +20,7 @@ import java.util.logging.Level; import java.util.logging.Logger; -class FormatExceptionPolicyLegacy implements FormatExceptionPolicy { +class FormatExceptionPolicyLegacy extends NoLambda.EqualityBasedOnSerialization implements FormatExceptionPolicy { private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(Formatter.class.getName()); @@ -34,9 +34,4 @@ public void handleError(Throwable e, FormatterStep step, File file, Path rootDir logger.log(Level.WARNING, "Unable to apply step '" + step.getName() + "' to '" + rootDir.relativize(file.toPath()), e); } } - - @Override - public byte[] toBytes() { - return LazyForwardingEquality.toBytes(this); - } } diff --git a/lib/src/main/java/com/diffplug/spotless/NoLambda.java b/lib/src/main/java/com/diffplug/spotless/NoLambda.java new file mode 100644 index 0000000000..6ce14d914d --- /dev/null +++ b/lib/src/main/java/com/diffplug/spotless/NoLambda.java @@ -0,0 +1,71 @@ +/* + * Copyright 2016 DiffPlug + * + * 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.diffplug.spotless; + +import java.io.Serializable; +import java.util.Arrays; + +/** + * Marker interface to prevent lambda implementations of + * single-method interfaces that require serializability. + * + * In order for Spotless to support up-to-date checks, all + * of its parameters must be {@link Serializable} so that + * entries can be written to file, and they must implement + * equals and hashCode correctly. + * + * This interface and its standard implementation, + * {@link EqualityBasedOnSerialization}, are a quick way + * to accomplish these goals. + */ +public interface NoLambda extends Serializable { + /** + * Returns a byte array representation of everything inside this `SerializableFileFilter`. + * + * The main purpose of this method is to ensure one can't instantiate this class with lambda + * expressions, which are notoriously difficult to serialize and deserialize properly. (See + * `SerializableFileFilterImpl.SkipFilesNamed` for an example of how to make a serializable + * subclass.) + */ + public byte[] toBytes(); + + /** An implementation of NoLambda in which equality is based on the serialized representation of itself. */ + public static abstract class EqualityBasedOnSerialization implements NoLambda { + private static final long serialVersionUID = 1733798699224768949L; + + @Override + public byte[] toBytes() { + return LazyForwardingEquality.toBytes(this); + } + + @Override + public int hashCode() { + return Arrays.hashCode(toBytes()); + } + + @Override + public boolean equals(Object otherObj) { + if (otherObj == null) { + return false; + } else if (otherObj.getClass().equals(this.getClass())) { + EqualityBasedOnSerialization other = (EqualityBasedOnSerialization) otherObj; + return Arrays.equals(toBytes(), other.toBytes()); + } else { + return false; + } + } + } +} diff --git a/lib/src/main/java/com/diffplug/spotless/SerializableFileFilter.java b/lib/src/main/java/com/diffplug/spotless/SerializableFileFilter.java index c6325af62c..27561758fe 100644 --- a/lib/src/main/java/com/diffplug/spotless/SerializableFileFilter.java +++ b/lib/src/main/java/com/diffplug/spotless/SerializableFileFilter.java @@ -17,49 +17,11 @@ import java.io.FileFilter; import java.io.Serializable; -import java.util.Arrays; /** A file filter with full support for serialization. */ -public interface SerializableFileFilter extends FileFilter, Serializable { +public interface SerializableFileFilter extends FileFilter, Serializable, NoLambda { /** Creates a FileFilter which will accept all files except files with the given name. */ public static SerializableFileFilter skipFilesNamed(String name) { return new SerializableFileFilterImpl.SkipFilesNamed(name); } - - /** - * Returns a byte array representation of everything inside this `SerializableFileFilter`. - * - * The main purpose of this method is to ensure one can't instantiate this class with lambda - * expressions, which are notoriously difficult to serialize and deserialize properly. (See - * `SerializableFileFilterImpl.SkipFilesNamed` for an example of how to make a serializable - * subclass.) - */ - public byte[] toBytes(); - - /** An implementation of SerializableFileFilter in which equality is based on the serialized representation. */ - public static abstract class EqualityBasedOnSerialization implements SerializableFileFilter { - private static final long serialVersionUID = 1733798699224768949L; - - @Override - public byte[] toBytes() { - return LazyForwardingEquality.toBytes(this); - } - - @Override - public int hashCode() { - return Arrays.hashCode(toBytes()); - } - - @Override - public boolean equals(Object otherObj) { - if (otherObj == null) { - return false; - } else if (otherObj.getClass().equals(this.getClass())) { - EqualityBasedOnSerialization other = (EqualityBasedOnSerialization) otherObj; - return Arrays.equals(toBytes(), other.toBytes()); - } else { - return false; - } - } - } } diff --git a/lib/src/main/java/com/diffplug/spotless/SerializableFileFilterImpl.java b/lib/src/main/java/com/diffplug/spotless/SerializableFileFilterImpl.java index d46aee6e6a..82b935839f 100644 --- a/lib/src/main/java/com/diffplug/spotless/SerializableFileFilterImpl.java +++ b/lib/src/main/java/com/diffplug/spotless/SerializableFileFilterImpl.java @@ -19,7 +19,7 @@ import java.util.Objects; class SerializableFileFilterImpl { - static class SkipFilesNamed extends SerializableFileFilter.EqualityBasedOnSerialization { + static class SkipFilesNamed extends NoLambda.EqualityBasedOnSerialization implements SerializableFileFilter { private static final long serialVersionUID = 1L; private final String nameToSkip;