public int compare(MediaType mediaType1, MediaType mediaType2) {
   double quality1 = mediaType1.getQualityValue();
   double quality2 = mediaType2.getQualityValue();
   int qualityComparison = Double.compare(quality2, quality1);
   if (qualityComparison != 0) {
     return qualityComparison; // audio/*;q=0.7 < audio/*;q=0.3
   } else if (mediaType1.isWildcardType() && !mediaType2.isWildcardType()) { // */* < audio/*
     return 1;
   } else if (mediaType2.isWildcardType() && !mediaType1.isWildcardType()) { // audio/* > */*
     return -1;
   } else if (!mediaType1
       .getType()
       .equals(mediaType2.getType())) { // audio/basic == text/html
     return 0;
   } else { // mediaType1.getType().equals(mediaType2.getType())
     if (mediaType1.isWildcardSubtype()
         && !mediaType2.isWildcardSubtype()) { // audio/* < audio/basic
       return 1;
     } else if (mediaType2.isWildcardSubtype()
         && !mediaType1.isWildcardSubtype()) { // audio/basic > audio/*
       return -1;
     } else if (!mediaType1
         .getSubtype()
         .equals(mediaType2.getSubtype())) { // audio/basic == audio/wave
       return 0;
     } else {
       int paramsSize1 = mediaType1.parameters.size();
       int paramsSize2 = mediaType2.parameters.size();
       return (paramsSize2 < paramsSize1
           ? -1
           : (paramsSize2 == paramsSize1 ? 0 : 1)); // audio/basic;level=1 < audio/basic
     }
   }
 }
  /**
   * Indicate whether this {@code MediaType} is compatible with the given media type.
   *
   * <p>For instance, {@code text/*} is compatible with {@code text/plain}, {@code text/html}, and
   * vice versa. In effect, this method is similar to {@link #includes(MediaType)}, except that it
   * <b>is</b> symmetric.
   *
   * @param other the reference media type with which to compare
   * @return <code>true</code> if this media type is compatible with the given media type; <code>
   *     false</code> otherwise
   */
  public boolean isCompatibleWith(MediaType other) {
    if (other == null) {
      return false;
    }
    if (isWildcardType() || other.isWildcardType()) {
      return true;
    } else if (this.type.equals(other.type)) {
      if (this.subtype.equals(other.subtype)
          || this.isWildcardSubtype()
          || other.isWildcardSubtype()) {
        return true;
      }
      // application/*+xml is compatible with application/soap+xml, and vice-versa
      int thisPlusIdx = this.subtype.indexOf('+');
      int otherPlusIdx = other.subtype.indexOf('+');
      if (thisPlusIdx != -1 && otherPlusIdx != -1) {
        String thisSubtypeNoSuffix = this.subtype.substring(0, thisPlusIdx);
        String otherSubtypeNoSuffix = other.subtype.substring(0, otherPlusIdx);

        String thisSubtypeSuffix = this.subtype.substring(thisPlusIdx + 1);
        String otherSubtypeSuffix = other.subtype.substring(otherPlusIdx + 1);

        if (thisSubtypeSuffix.equals(otherSubtypeSuffix)
            && (WILDCARD_TYPE.equals(thisSubtypeNoSuffix)
                || WILDCARD_TYPE.equals(otherSubtypeNoSuffix))) {
          return true;
        }
      }
    }
    return false;
  }
 @Override
 public void write(JSONEntity entity, MediaType contentType, HttpOutputMessage outputMessage)
     throws IOException, HttpMessageNotWritableException {
   // First write the entity to a JSON string
   try {
     HttpHeaders headers = outputMessage.getHeaders();
     if (headers.getContentType() == null) {
       if (contentType == null
           || contentType.isWildcardType()
           || contentType.isWildcardSubtype()) {
         contentType = MediaType.APPLICATION_JSON;
       }
       if (contentType != null) {
         headers.setContentType(contentType);
       }
     }
     String jsonString = EntityFactory.createJSONStringForEntity(entity);
     long length =
         JSONEntityHttpMessageConverter.writeToStream(
             jsonString, outputMessage.getBody(), contentType.getCharSet());
     if (headers.getContentLength() == -1) {
       headers.setContentLength(length);
     }
   } catch (JSONObjectAdapterException e) {
     throw new HttpMessageNotWritableException(e.getMessage());
   }
 }
 /**
  * Add default headers to the output message.
  *
  * <p>This implementation delegates to {@link #getDefaultContentType(Object)} if a content type
  * was not provided, calls {@link #getContentLength}, and sets the corresponding headers
  *
  * @since 4.2
  */
 protected void addDefaultHeaders(HttpHeaders headers, T t, MediaType contentType)
     throws IOException {
   if (headers.getContentType() == null) {
     MediaType contentTypeToUse = contentType;
     if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
       contentTypeToUse = getDefaultContentType(t);
     } else if (MediaType.APPLICATION_OCTET_STREAM.equals(contentType)) {
       MediaType mediaType = getDefaultContentType(t);
       contentTypeToUse = (mediaType != null ? mediaType : contentTypeToUse);
     }
     if (contentTypeToUse != null) {
       headers.setContentType(contentTypeToUse);
     }
   }
   if (headers.getContentLength() == -1) {
     Long contentLength = getContentLength(t, headers.getContentType());
     if (contentLength != null) {
       headers.setContentLength(contentLength);
     }
   }
 }
  private void writeInternal(
      BufferedImage image, MediaType contentType, HttpHeaders headers, OutputStream body)
      throws IOException, HttpMessageNotWritableException {

    if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
      contentType = getDefaultContentType();
    }
    Assert.notNull(
        contentType,
        "Count not determine Content-Type, set one using the 'defaultContentType' property");
    headers.setContentType(contentType);
    ImageOutputStream imageOutputStream = null;
    ImageWriter imageWriter = null;
    try {
      Iterator<ImageWriter> imageWriters =
          ImageIO.getImageWritersByMIMEType(contentType.toString());
      if (imageWriters.hasNext()) {
        imageWriter = imageWriters.next();
        ImageWriteParam iwp = imageWriter.getDefaultWriteParam();
        process(iwp);
        imageOutputStream = createImageOutputStream(body);
        imageWriter.setOutput(imageOutputStream);
        imageWriter.write(null, new IIOImage(image, null, null), iwp);
      } else {
        throw new HttpMessageNotWritableException(
            "Could not find javax.imageio.ImageWriter for Content-Type [" + contentType + "]");
      }
    } finally {
      if (imageWriter != null) {
        imageWriter.dispose();
      }
      if (imageOutputStream != null) {
        try {
          imageOutputStream.close();
        } catch (IOException ex) {
          // ignore
        }
      }
    }
  }
  /**
   * This implementation delegates to {@link #getDefaultContentType(Object)} if a content type was
   * not provided, calls {@link #getContentLength}, and sets the corresponding headers on the output
   * message. It then calls {@link #writeInternal}.
   */
  public final void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
      throws IOException, HttpMessageNotWritableException {

    HttpHeaders headers = outputMessage.getHeaders();
    if (headers.getContentType() == null) {
      MediaType contentTypeToUse = contentType;
      if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
        contentTypeToUse = getDefaultContentType(t);
      }
      if (contentTypeToUse != null) {
        headers.setContentType(contentTypeToUse);
      }
    }
    if (headers.getContentLength() == -1) {
      Long contentLength = getContentLength(t, headers.getContentType());
      if (contentLength != null) {
        headers.setContentLength(contentLength);
      }
    }
    writeInternal(t, outputMessage);
    outputMessage.getBody().flush();
  }