JsonObject writeTextAnnotation(TextAnnotation ta, boolean doWriteTokenOffsets) {

    // get rid of the views that are empty
    Set<String> viewNames = new HashSet<>(ta.getAvailableViews());
    for (String vu : viewNames) {
      if (ta.getView(vu) == null) {
        logger.warn("View " + vu + " is null");
        ta.removeView(vu);
      }
    }

    JsonObject json = new JsonObject();

    writeString("corpusId", ta.getCorpusId(), json);
    writeString("id", ta.getId(), json);
    writeString("text", ta.getText(), json);
    writeStringArray("tokens", ta.getTokens(), json);
    if (doWriteTokenOffsets) writeTokenOffsets(TOKENOFFSETS, ta.getView(ViewNames.TOKENS), json);

    writeSentences(ta, json);

    JsonArray views = new JsonArray();
    for (String viewName : Sorters.sortSet(ta.getAvailableViews())) {
      if (viewName.equals(ViewNames.SENTENCE)) continue;

      JsonObject view = new JsonObject();

      writeString("viewName", viewName, view);
      views.add(view);

      JsonArray viewData = new JsonArray();
      List<View> topKViews = ta.getTopKViews(viewName);

      for (View topKView : topKViews) {
        JsonObject kView = new JsonObject();
        writeView(topKView, kView);
        viewData.add(kView);
      }

      view.add("viewData", viewData);
    }

    json.add("views", views);

    writeAttributes(ta, json);

    return json;
  }
  private static void writeSentences(TextAnnotation ta, JsonObject json) {

    JsonObject object = new JsonObject();

    SpanLabelView sentenceView = (SpanLabelView) ta.getView(ViewNames.SENTENCE);
    writeString("generator", sentenceView.getViewGenerator(), object);

    writeDouble("score", sentenceView.getScore(), object);
    int numSentences = sentenceView.getNumberOfConstituents();
    int[] sentenceEndPositions = new int[numSentences];

    int id = 0;
    for (Sentence sentence : ta.sentences()) {
      sentenceEndPositions[id++] = sentence.getEndSpan();
    }
    writeIntArray("sentenceEndPositions", sentenceEndPositions, object);

    json.add("sentences", object);
  }
  TextAnnotation readTextAnnotation(String string) throws Exception {
    JsonObject json = (JsonObject) new JsonParser().parse(string);

    String corpusId = readString("corpusId", json);
    String id = readString("id", json);
    String text = readString("text", json);
    String[] tokens = readStringArray("tokens", json);

    Pair<Pair<String, Double>, int[]> sentences = readSentences(json);

    IntPair[] offsets = TokenUtils.getTokenOffsets(text, tokens);

    TextAnnotation ta =
        new TextAnnotation(corpusId, id, text, offsets, tokens, sentences.getSecond());

    JsonArray views = json.getAsJsonArray("views");
    for (int i = 0; i < views.size(); i++) {
      JsonObject view = (JsonObject) views.get(i);
      String viewName = readString("viewName", view);

      JsonArray viewData = view.getAsJsonArray("viewData");
      List<View> topKViews = new ArrayList<>();

      for (int k = 0; k < viewData.size(); k++) {
        JsonObject kView = (JsonObject) viewData.get(k);

        topKViews.add(readView(kView, ta));
      }

      ta.addTopKView(viewName, topKViews);
    }

    readAttributes(ta, json);

    return ta;
  }