public static Change load(LineNumberReader reader, Pool pool) throws Exception {
    String baseColumnName = null;
    int columnInsertIndex = -1;

    List<String> columnNames = null;
    List<DBpediaType> columnTypes = null;

    List<Integer> rowIndices = null;
    List<DataExtension> dataExtensions = null;

    List<Row> oldRows = null;
    List<Row> newRows = null;

    int firstNewCellIndex = -1;

    String line;
    while ((line = reader.readLine()) != null && !"/ec/".equals(line)) {
      int equal = line.indexOf('=');
      CharSequence field = line.subSequence(0, equal);
      String value = line.substring(equal + 1);

      if ("baseColumnName".equals(field)) {
        baseColumnName = value;
      } else if ("columnInsertIndex".equals(field)) {
        columnInsertIndex = Integer.parseInt(value);
      } else if ("firstNewCellIndex".equals(field)) {
        firstNewCellIndex = Integer.parseInt(value);
      } else if ("rowIndexCount".equals(field)) {
        int count = Integer.parseInt(value);

        rowIndices = new ArrayList<Integer>(count);
        for (int i = 0; i < count; i++) {
          line = reader.readLine();
          if (line != null) {
            rowIndices.add(Integer.parseInt(line));
          }
        }
      } else if ("columnNameCount".equals(field)) {
        int count = Integer.parseInt(value);

        columnNames = new ArrayList<String>(count);
        for (int i = 0; i < count; i++) {
          line = reader.readLine();
          if (line != null) {
            columnNames.add(line);
          }
        }
      } else if ("columnTypeCount".equals(field)) {
        int count = Integer.parseInt(value);

        columnTypes = new ArrayList<DBpediaType>(count);
        for (int i = 0; i < count; i++) {
          line = reader.readLine();
          columnTypes.add(DBpediaType.load(ParsingUtilities.evaluateJsonStringToObject(line)));
        }
      } else if ("dataExtensionCount".equals(field)) {
        int count = Integer.parseInt(value);

        dataExtensions = new ArrayList<DataExtension>(count);
        for (int i = 0; i < count; i++) {
          line = reader.readLine();

          if (line == null) {
            continue;
          }

          if (line.length() == 0) {
            dataExtensions.add(null);
            continue;
          }

          int rowCount = Integer.parseInt(line);
          Object[][] data = new Object[rowCount][];

          for (int r = 0; r < rowCount; r++) {
            Object[] row = new Object[columnNames.size()];
            for (int c = 0; c < columnNames.size(); c++) {
              line = reader.readLine();

              row[c] = ReconCandidate.loadStreaming(line);
            }

            data[r] = row;
          }

          dataExtensions.add(new DataExtension(data));
        }
      } else if ("oldRowCount".equals(field)) {
        int count = Integer.parseInt(value);

        oldRows = new ArrayList<Row>(count);
        for (int i = 0; i < count; i++) {
          line = reader.readLine();
          if (line != null) {
            oldRows.add(Row.load(line, pool));
          }
        }
      } else if ("newRowCount".equals(field)) {
        int count = Integer.parseInt(value);

        newRows = new ArrayList<Row>(count);
        for (int i = 0; i < count; i++) {
          line = reader.readLine();
          if (line != null) {
            newRows.add(Row.load(line, pool));
          }
        }
      }
    }

    DBpediaDataExtensionChange change =
        new DBpediaDataExtensionChange(
            baseColumnName,
            columnInsertIndex,
            columnNames,
            columnTypes,
            rowIndices,
            dataExtensions,
            firstNewCellIndex,
            oldRows,
            newRows);

    return change;
  }