@Override
 protected RevTag read(ObjectId id, BufferedReader reader, TYPE type) throws IOException {
   Preconditions.checkArgument(TYPE.TAG.equals(type), "Wrong type: %s", type.name());
   String name = parseLine(requireLine(reader), "name");
   String message = parseLine(requireLine(reader), "message");
   String commitId = parseLine(requireLine(reader), "commitid");
   RevPerson tagger = parsePerson(requireLine(reader));
   RevTag tag = new RevTagImpl(id, name, ObjectId.valueOf(commitId), message, tagger);
   return tag;
 }
        @Override
        protected RevFeature read(ObjectId id, BufferedReader reader, TYPE type)
            throws IOException {
          Preconditions.checkArgument(TYPE.FEATURE.equals(type), "Wrong type: %s", type.name());
          List<Object> values = Lists.newArrayList();
          String line;
          while ((line = reader.readLine()) != null) {
            values.add(parseAttribute(line));
          }

          ImmutableList.Builder<Optional<Object>> valuesBuilder =
              new ImmutableList.Builder<Optional<Object>>();
          for (Object value : values) {
            valuesBuilder.add(Optional.fromNullable(value));
          }
          return RevFeatureImpl.build(valuesBuilder.build());
        }
        @Override
        protected RevTree read(ObjectId id, BufferedReader reader, TYPE type) throws IOException {
          Preconditions.checkArgument(TYPE.TREE.equals(type), "Wrong type: %s", type.name());
          Builder<Node> features = ImmutableList.builder();
          Builder<Node> trees = ImmutableList.builder();
          TreeMap<Integer, Bucket> subtrees = Maps.newTreeMap();
          long size = Long.parseLong(parseLine(requireLine(reader), "size"));
          int numTrees = Integer.parseInt(parseLine(requireLine(reader), "numtrees"));
          String line;
          while ((line = reader.readLine()) != null) {
            Preconditions.checkArgument(!line.isEmpty(), "Empty tree element definition");
            ArrayList<String> tokens = Lists.newArrayList(Splitter.on('\t').split(line));
            String nodeType = tokens.get(0);
            if (nodeType.equals(TextWriter.TreeNode.REF.name())) {
              Node entryRef = parseNodeLine(line);
              if (entryRef.getType().equals(TYPE.TREE)) {
                trees.add(entryRef);
              } else {
                features.add(entryRef);
              }
            } else if (nodeType.equals(TextWriter.TreeNode.BUCKET.name())) {
              Preconditions.checkArgument(tokens.size() == 4, "Wrong bucket definition: %s", line);
              Integer idx = Integer.parseInt(tokens.get(1));
              ObjectId bucketId = ObjectId.valueOf(tokens.get(2));
              Envelope bounds = parseBBox(tokens.get(3));
              Bucket bucket = Bucket.create(bucketId, bounds);
              subtrees.put(idx, bucket);
            } else {
              throw new IllegalArgumentException("Wrong tree element definition: " + line);
            }
          }

          RevTree tree;
          if (subtrees.isEmpty()) {
            tree = RevTreeImpl.createLeafTree(id, size, features.build(), trees.build());
          } else {
            tree = RevTreeImpl.createNodeTree(id, size, numTrees, subtrees);
          }
          return tree;
        }
        @Override
        protected RevCommit read(ObjectId id, BufferedReader reader, TYPE type) throws IOException {
          Preconditions.checkArgument(TYPE.COMMIT.equals(type), "Wrong type: %s", type.name());
          String tree = parseLine(requireLine(reader), "tree");
          List<String> parents =
              Lists.newArrayList(
                  Splitter.on(' ')
                      .omitEmptyStrings()
                      .split(parseLine(requireLine(reader), "parents")));
          RevPerson author = parsePerson(requireLine(reader), "author");
          RevPerson committer = parsePerson(requireLine(reader), "committer");
          String message = parseMessage(reader);

          CommitBuilder builder = new CommitBuilder();
          builder.setAuthor(author.getName().orNull());
          builder.setAuthorEmail(author.getEmail().orNull());
          builder.setAuthorTimestamp(author.getTimestamp());
          builder.setAuthorTimeZoneOffset(author.getTimeZoneOffset());
          builder.setCommitter(committer.getName().orNull());
          builder.setCommitterEmail(committer.getEmail().orNull());
          builder.setCommitterTimestamp(committer.getTimestamp());
          builder.setCommitterTimeZoneOffset(committer.getTimeZoneOffset());
          builder.setMessage(message);
          List<ObjectId> parentIds =
              Lists.newArrayList(
                  Iterators.transform(
                      parents.iterator(),
                      new Function<String, ObjectId>() {

                        @Override
                        public ObjectId apply(String input) {
                          ObjectId objectId = ObjectId.valueOf(input);
                          return objectId;
                        }
                      }));
          builder.setParentIds(parentIds);
          builder.setTreeId(ObjectId.valueOf(tree));
          RevCommit commit = builder.build();
          return commit;
        }
        @Override
        protected RevFeatureType read(ObjectId id, BufferedReader reader, TYPE type)
            throws IOException {
          Preconditions.checkArgument(TYPE.FEATURETYPE.equals(type), "Wrong type: %s", type.name());
          builder = new SimpleFeatureTypeBuilder();
          typeFactory = builder.getFeatureTypeFactory();
          String name = parseLine(requireLine(reader), "name");
          SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
          if (name.contains(":")) {
            int idx = name.lastIndexOf(':');
            String namespace = name.substring(0, idx);
            String local = name.substring(idx + 1);
            builder.setName(new NameImpl(namespace, local));
          } else {
            builder.setName(new NameImpl(name));
          }

          String line;
          while ((line = reader.readLine()) != null) {
            builder.add(parseAttributeDescriptor(line));
          }
          SimpleFeatureType sft = builder.buildFeatureType();
          return RevFeatureTypeImpl.build(sft);
        }