@Override
    public JsonElement serialize(
        CreatureTypeSaveObject src, Type typeOfSrc, JsonSerializationContext context) {
      JsonObject endObject = new JsonObject();
      endObject.addProperty(FILE_VERSION_KEY, FILE_VERSION);
      JsonObject types = new JsonObject();
      for (CreatureTypeBuilder type : src.types.get().values()) {
        JsonObject entry = new JsonObject();
        entry.addProperty(SPAWN_RATE_KEY, type.spawnRate);
        entry.addProperty(MAX_CREATURE_KEY, type.maxNumberOfCreature);
        entry.addProperty(CHUNK_CHANCE_KEY, type.getChunkSpawnChance());
        entry.addProperty(SPAWN_MEDIUM_KEY, type.getRawSpawnMedium());
        entry.addProperty(ITER_PER_CHUNK, type.getIterationsPerChunk());
        entry.addProperty(ITER_PER_PACK, type.getIterationsPerPack());
        entry.addProperty(OPTIONAL_PARAM_KEY, type.getSpawnExpression());
        entry.addProperty(DEFAULT_BIOME_CAP_KEY, type.getDefaultBiomeCap());

        JsonObject biomeCaps = new JsonObject();
        for (Entry<String, Integer> capEntry : type.getBiomeCaps().entrySet()) {
          biomeCaps.addProperty(capEntry.getKey(), capEntry.getValue());
        }
        entry.add(MAPPING_TO_CAP, biomeCaps);
        types.add(type.typeID, entry);
      }
      endObject.add(TYPE_KEY, types);
      return endObject;
    }
    @Override
    public CreatureTypeSaveObject deserialize(
        JsonElement json, Type typeOfT, JsonDeserializationContext context)
        throws JsonParseException {
      CreatureTypeSaveObject saveObject = new CreatureTypeSaveObject();
      JsonObject endObject = GsonHelper.getAsJsonObject(json);
      String fileVersion = GsonHelper.getMemberOrDefault(endObject, FILE_VERSION_KEY, FILE_VERSION);
      JsonElement jsonElement = endObject.get(TYPE_KEY);
      if (jsonElement != null && jsonElement.isJsonObject()) {
        JsonObject types = jsonElement.getAsJsonObject();
        TreeMap<String, CreatureTypeBuilder> typeMap = new TreeMap<String, CreatureTypeBuilder>();
        for (Entry<String, JsonElement> entry : types.entrySet()) {
          JsonObject builderObject = GsonHelper.getAsJsonObject(entry.getValue());
          CreatureTypeBuilder builder =
              new CreatureTypeBuilder(
                  entry.getKey(),
                  GsonHelper.getMemberOrDefault(builderObject, SPAWN_RATE_KEY, 1),
                  GsonHelper.getMemberOrDefault(builderObject, MAX_CREATURE_KEY, 10));
          builder.withChanceToChunkSpawn(
              GsonHelper.getMemberOrDefault(builderObject, CHUNK_CHANCE_KEY, 0f));
          builder.setRawMedium(
              GsonHelper.getMemberOrDefault(builderObject, SPAWN_MEDIUM_KEY, "air"));
          builder.setIterationsPerChunk(
              GsonHelper.getMemberOrDefault(builderObject, ITER_PER_CHUNK, 3));
          builder.setIterationsPerPack(
              GsonHelper.getMemberOrDefault(builderObject, ITER_PER_PACK, 4));
          if (fileVersion.equals("1.0")) {
            TagConverter tag =
                new TagConverter(GsonHelper.getMemberOrDefault(builderObject, "Tags", ""));
            builder.withSpawnExpression(tag.expression);

          } else {
            builder.withSpawnExpression(
                GsonHelper.getMemberOrDefault(builderObject, OPTIONAL_PARAM_KEY, ""));
          }
          builder.withDefaultBiomeCap(
              GsonHelper.getMemberOrDefault(builderObject, DEFAULT_BIOME_CAP_KEY, -1));
          JsonObject caps =
              GsonHelper.getMemberOrDefault(builderObject, MAPPING_TO_CAP, new JsonObject());
          for (Entry<String, JsonElement> capEntry : caps.entrySet()) {
            builder.withBiomeCap(
                capEntry.getKey(),
                GsonHelper.getAsOrDefault(builderObject, builder.getDefaultBiomeCap()));
            if (capEntry.getValue().isJsonPrimitive()
                && capEntry.getValue().getAsJsonPrimitive().isNumber()) {
              builder.withBiomeCap(
                  capEntry.getKey(), capEntry.getValue().getAsJsonPrimitive().getAsInt());
            }
          }
          typeMap.put(builder.typeID, builder);
        }
        saveObject.types = Optional.of(typeMap);
      }
      return saveObject;
    }