@Override
  public void close() throws IOException {
    if (closed) {
      return;
    }

    closed = true;

    marshalTarget.finish();

    if (!openOutputStreams.isEmpty()) {
      try (Closer closer = new Closer()) {
        openOutputStreams.keySet().forEach(closer::register);
        throw new MarshalingException(
            String.format(
                "Failed to serialize object at %s, because output streams for the "
                    + "following keys were not closed: %s",
                this, openOutputStreams.values()));
      }
    }

    if (!marshalTargetStarted) {
      throw new MarshalingException(
          String.format(
              "Marshaler of %s did not call any %s methods.",
              marshaler.getClass(), MarshalContext.class));
    }
  }
 /**
  * Returns the first marshaler (in iteration order) that is capable of marshaling the given
  * object.
  *
  * @param object object that the returned marshaler must be capable of handling
  * @param marshalers collection of marshalers
  * @return the marshaler
  * @throws MarshalingException if no marshaler is capable
  */
 public static Marshaler<?> findMarshaler(
     Object object, Collection<? extends Marshaler<?>> marshalers) throws MarshalingException {
   Objects.requireNonNull(object);
   Objects.requireNonNull(marshalers);
   return marshalers
       .stream()
       .filter(marshaler -> marshaler.canHandle(object))
       .findFirst()
       .orElseThrow(
           () ->
               new MarshalingException(
                   String.format(
                       "None of %s is capable of marshaling instance: %s.", marshalers, object)));
 }
 @SuppressWarnings("unchecked")
 private <T> void uncheckedPut(Marshaler<T> marshaler, Object object) throws IOException {
   marshaler.put((T) object, this);
 }
 @SuppressWarnings("unchecked")
 private static <T> boolean isSelfContained(Marshaler<T> marshaler, Object object) {
   return marshaler.isImmutable((T) object);
 }