@Override
  public boolean equals(Object o) {
    if (o == null) return false;

    if (!(o instanceof ComplexType)) return false;

    ComplexType element = (ComplexType) o;

    if (!Util.compare(element.name, name)) return false;
    if (!Util.compare(element.age, age)) return false;

    return true;
  }
  protected List<Pair<String, String>> createQuery(Random rndGen) {
    if (rndGen.nextInt(2) == 0) {
      return null;
    } else {
      List<Pair<String, String>> query = new ArrayList<Pair<String, String>>();

      int size = rndGen.nextInt(5);

      for (int i = 0; i < size; i++) {
        query.add(
            new Pair<String, String>(
                Util.createSimpleRandomString(rndGen, rndGen.nextInt(10) + 1, 'a', 'z'),
                Util.createComplexRandomString(rndGen, rndGen.nextInt(30))));
      }

      return query;
    }
  }
  private JsonElement createJson(Random rndGen, int currentDepth, boolean canBeNull) {
    final int maxDepth = 3;

    int kind = rndGen.nextInt(15);

    if (currentDepth == 0) {
      kind = rndGen.nextInt(8) + 8;
    }

    switch (kind) {
      case 0:
        return new JsonPrimitive(true);

      case 1:
        return new JsonPrimitive(false);

      case 2:
        return new JsonPrimitive(rndGen.nextInt());

      case 3:
        return new JsonPrimitive(rndGen.nextInt() >> rndGen.nextInt(10));

      case 4:
      case 5:
      case 6:
        return new JsonPrimitive(Util.createComplexRandomString(rndGen, rndGen.nextInt(10)));

      case 7:
        if (canBeNull) {
          return JsonNull.INSTANCE;
        } else {
          return new JsonPrimitive(Util.createComplexRandomString(rndGen, rndGen.nextInt(10)));
        }

      case 8:
      case 9:
      case 10:
        if (currentDepth > maxDepth) {
          return new JsonPrimitive("max depth");
        } else {
          int size = rndGen.nextInt(5);
          JsonArray array = new JsonArray();
          for (int i = 0; i < size; i++) {
            array.add(createJson(rndGen, currentDepth + 1, true));
          }

          return array;
        }

      default:
        if (currentDepth > maxDepth) {
          return new JsonPrimitive("max depth");
        } else {
          int size = rndGen.nextInt(5);
          JsonObject result = new JsonObject();

          for (int i = 0; i < size; i++) {
            String key;
            do {
              key = Util.createComplexRandomString(rndGen, rndGen.nextInt(3) + 3);
            } while (result.has(key));

            result.add(key, createJson(rndGen, currentDepth + 1, true));
          }

          return result;
        }
    }
  }
 public ComplexType(Random r) {
   name = Util.createSimpleRandomString(r, 10);
   age = r.nextInt(80);
 }