public static <T> MutationDetector forValueWithCoder(T value, Coder<T> coder)
      throws CoderException {
    if (value == null) {
      return noopMutationDetector();
    } else {
      return new CodedValueMutationDetector<>(value, coder);
    }
  }
@Test
  public void testMutationWithEqualEncodings() throws Exception {
    class EncodingBadStructuralValueCoder extends AtomicCoder<List<Object>> {
      @Override
      public void encode(List<Object> value, OutputStream outStream)
          throws CoderException, IOException {
        outStream.write(new byte[] {1, 2, -3, 45});
      }

      @Override
      public List<Object> decode(InputStream inStream) throws CoderException, IOException {
        // Consume the written bytes
        inStream.read(new byte[4]);
        return new ArrayList<>();
      }

      @Override
      public Object structuralValue(List<Object> value) {
        // Structural values are never equal to each other.
        return new Object();
      }
    }

    List<Object> ls = new ArrayList<>();
    ls.add(1);
    ls.add("foo");

    MutationDetector detector =
        MutationDetectors.forValueWithCoder(ls, new EncodingBadStructuralValueCoder());
    ls.add(new Byte[] {1, 2, -3, 45});

    // The structural values should be unequal, but the encoded bytes are equivalent, which is the
    // system definition of equality.
    detector.verifyUnmodified();
  }