public static void write()

in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/StubxWriter.java [42:189]


  public static void write(
      DataOutputStream out,
      Map<String, String> importedAnnotations,
      Map<String, Set<String>> packageAnnotations,
      Map<String, Set<String>> typeAnnotations,
      Map<String, MethodAnnotationsRecord> methodRecords,
      Set<String> nullMarkedClasses,
      Map<String, Set<Integer>> nullableUpperBounds)
      throws IOException {
    // File format version/magic number
    out.writeInt(VERSION_1_FILE_MAGIC_NUMBER);
    // Followed by the number of string dictionary entries
    int numStringEntries = 0;
    Map<String, Integer> encodingDictionary = new LinkedHashMap<>();
    List<String> strings = new ArrayList<String>();
    List<String> kindNames =
        Arrays.stream(NestedAnnotationInfo.TypePathEntry.Kind.values()).map(Enum::name).toList();
    List<String> annotationNames =
        Arrays.stream(NestedAnnotationInfo.Annotation.values()).map(Enum::name).toList();
    ImmutableList<Collection<String>> keysets =
        ImmutableList.of(
            importedAnnotations.values(),
            packageAnnotations.keySet(),
            typeAnnotations.keySet(),
            methodRecords.keySet(),
            nullMarkedClasses,
            nullableUpperBounds.keySet(),
            kindNames,
            annotationNames);
    for (Collection<String> keyset : keysets) {
      for (String key : keyset) {
        if (encodingDictionary.containsKey(key)) {
          continue;
        }
        strings.add(key);
        encodingDictionary.put(key, numStringEntries);
        ++numStringEntries;
      }
    }
    out.writeInt(numStringEntries);
    // Followed by the entries themselves
    for (String s : strings) {
      out.writeUTF(s);
    }
    // Followed by the number of encoded package annotation records
    int packageAnnotationSize = 0;
    for (Map.Entry<String, Set<String>> entry : packageAnnotations.entrySet()) {
      packageAnnotationSize += entry.getValue().size();
    }
    out.writeInt(packageAnnotationSize);
    // Followed by those records as pairs of ints pointing into the dictionary
    for (Map.Entry<String, Set<String>> entry : packageAnnotations.entrySet()) {
      for (String annot : entry.getValue()) {
        out.writeInt(encodingDictionary.get(entry.getKey()));
        out.writeInt(encodingDictionary.get(importedAnnotations.get(annot)));
      }
    }
    // Followed by the number of encoded type annotation records
    int typeAnnotationSize = 0;
    for (Map.Entry<String, Set<String>> entry : typeAnnotations.entrySet()) {
      typeAnnotationSize += entry.getValue().size();
    }
    out.writeInt(typeAnnotationSize);
    // Followed by those records as pairs of ints pointing into the dictionary
    for (Map.Entry<String, Set<String>> entry : typeAnnotations.entrySet()) {
      for (String annot : entry.getValue()) {
        out.writeInt(encodingDictionary.get(entry.getKey()));
        out.writeInt(encodingDictionary.get(importedAnnotations.get(annot)));
      }
    }
    // Followed by the number of encoded method return/declaration annotation records
    int methodAnnotationSize = 0;
    int methodTypeParamNullableUpperbounds = 0;
    int methodArgumentRecordsSize = 0;
    int methodNestedAnnotSize = 0;
    for (Map.Entry<String, MethodAnnotationsRecord> entry : methodRecords.entrySet()) {
      methodAnnotationSize += entry.getValue().methodAnnotations().size();
      methodTypeParamNullableUpperbounds += entry.getValue().typeParamNullableUpperbounds().size();
      methodArgumentRecordsSize += entry.getValue().argumentAnnotations().size();
      methodNestedAnnotSize += entry.getValue().nestedAnnotationInfo().size();
    }
    out.writeInt(methodAnnotationSize);
    // Followed by those records as pairs of ints pointing into the dictionary
    for (Map.Entry<String, MethodAnnotationsRecord> entry : methodRecords.entrySet()) {
      for (String annot : entry.getValue().methodAnnotations()) {
        out.writeInt(encodingDictionary.get(entry.getKey()));
        out.writeInt(encodingDictionary.get(importedAnnotations.get(annot)));
      }
    }
    out.writeInt(methodTypeParamNullableUpperbounds);
    // followed by method type variables
    for (Map.Entry<String, MethodAnnotationsRecord> entry : methodRecords.entrySet()) {
      for (int nullableIndex : entry.getValue().typeParamNullableUpperbounds()) {
        out.writeInt(encodingDictionary.get(entry.getKey()));
        out.writeInt(nullableIndex);
      }
    }
    // Followed by the number of encoded method argument annotation records
    out.writeInt(methodArgumentRecordsSize);
    // Followed by those records as a triplet of ints ( 0 and 2 point in the dictionary, 1 is the
    //  argument position)
    for (Map.Entry<String, MethodAnnotationsRecord> entry : methodRecords.entrySet()) {
      for (Map.Entry<Integer, ImmutableSet<String>> argEntry :
          entry.getValue().argumentAnnotations().entrySet()) {
        for (String annot : argEntry.getValue()) {
          out.writeInt(encodingDictionary.get(entry.getKey()));
          out.writeInt(argEntry.getKey());
          out.writeInt(encodingDictionary.get(importedAnnotations.get(annot)));
        }
      }
    }
    // Followed by the number of nested annotation information records
    out.writeInt(methodNestedAnnotSize);
    // Followed by the nested annotation information
    for (Map.Entry<String, MethodAnnotationsRecord> entry : methodRecords.entrySet()) {
      for (Map.Entry<Integer, NestedAnnotationInfo> nestedInfoEntry :
          entry.getValue().nestedAnnotationInfo().entries()) {
        // index, annotation, list size, (TypePathEntry) list of (kind, index)
        out.writeInt(encodingDictionary.get(entry.getKey()));
        out.writeInt(nestedInfoEntry.getKey()); // -1: return type, 0+: parameter index
        NestedAnnotationInfo nestedInfo = nestedInfoEntry.getValue();
        out.writeInt(encodingDictionary.get(nestedInfo.annotation().name())); // annotation type
        out.writeInt(nestedInfo.typePath().size()); // length of TypePathEntry
        for (NestedAnnotationInfo.TypePathEntry typePath : nestedInfoEntry.getValue().typePath()) {
          out.writeInt(encodingDictionary.get(typePath.kind().name())); // Kind of nested type
          out.writeInt(typePath.index()); // index related to nested type
        }
      }
    }
    // Followed by the number of NullMarked Classes
    out.writeInt(nullMarkedClasses.size());
    // Followed by the null marked class records from the dictionary
    for (String entry : nullMarkedClasses) {
      out.writeInt(encodingDictionary.get(entry));
    }
    // Followed by the number of nullable upper bounds records
    out.writeInt(nullableUpperBounds.size());
    for (Map.Entry<String, Set<Integer>> entry : nullableUpperBounds.entrySet()) {
      // Followed by the number of parameters with nullable upper bound
      Set<Integer> parameters = entry.getValue();
      out.writeInt(parameters.size());
      for (Integer parameter : parameters) {
        // Followed by the nullable upper bound record as a pair of integers
        out.writeInt(encodingDictionary.get(entry.getKey()));
        out.writeInt(parameter);
      }
    }
  }