code: public JavaWriter emitAnnotation(String annotation, Map<String, ?> attributes)
        throws IOException {
      indent();
      out.write("@");
      emitCompressedType(annotation);
      switch (attributes.size()) {
        case 0:
          break;
        case 1:
          Entry<String, ?> onlyEntry = attributes.entrySet().iterator().next();
          out.write("(");
          if (!"value".equals(onlyEntry.getKey())) {
            out.write(onlyEntry.getKey());
            out.write(" = ");
          }
          emitAnnotationValue(onlyEntry.getValue());
          out.write(")");
          break;
        default:
          boolean split = attributes.size() > MAX_SINGLE_LINE_ATTRIBUTES
              || containsArray(attributes.values());
          out.write("(");
          scopes.push(Scope.ANNOTATION_ATTRIBUTE);
          String separator = split ? "\n" : "";
          for (Entry<String, ?> entry : attributes.entrySet()) {
            out.write(separator);
            separator = split ? ",\n" : ", ";
            if (split) {
              indent();
            }
            out.write(entry.getKey());
            out.write(" = ");
            Object value = entry.getValue();
            emitAnnotationValue(value);
          }
          popScope(Scope.ANNOTATION_ATTRIBUTE);
          if (split) {
            out.write("\n");
            indent();
          }
          out.write(")");
          break;
      }
      out.write("\n");
      return this;
    }
docs: Annotates the next element with {@code annotation} and {@code attributes}.
  
  @param attributes a map from annotation attribute names to their values. Values are encoded
  using Object.toString(); use {@link #stringLiteral} for String values. Object arrays are
  written one element per line.