public static <T extends Comparable<? super T>> Range<T> ofString(String str, Function<String, T> converter, Class<T> clazz) {
        if(str.equals(EMPTY)) {
            return emptyRange(clazz);
        }

        int mask = str.charAt(0) == '[' ? LOWER_INCLUSIVE : LOWER_EXCLUSIVE;
        mask |= str.charAt(str.length() - 1) == ']' ? UPPER_INCLUSIVE : UPPER_EXCLUSIVE;

        int delim = str.indexOf(',');

        if (delim == -1) {
            throw new IllegalArgumentException("Cannot find comma character");
        }

        String lowerStr = str.substring(1, delim);
        String upperStr = str.substring(delim + 1, str.length() - 1);

        if (lowerStr.length() == 0 || lowerStr.endsWith(INFINITY)) {
            mask |= LOWER_INFINITE;
        }

        if (upperStr.length() == 0 || upperStr.endsWith(INFINITY)) {
            mask |= UPPER_INFINITE;
        }

        T lower = null;
        T upper = null;

        if ((mask & LOWER_INFINITE) != LOWER_INFINITE) {
            lower = converter.apply(lowerStr);
        }

        if ((mask & UPPER_INFINITE) != UPPER_INFINITE) {
            upper = converter.apply(upperStr);
        }

        return new Range<>(lower, upper, mask, clazz);
    }
@Test
    public void ofStringTest() {
        assertThat(integerRange("[1,3]").lower(), is(1));
        assertThat(integerRange("[1,3]").upper(), is(3));
        assertThat(integerRange("[1,3]").isUpperBoundClosed(), is(true));
        assertThat(integerRange("[1,3]").isLowerBoundClosed(), is(true));

        assertThat(integerRange("[,3]").lower(), is(nullValue()));
        assertThat(integerRange("[,3]").upper(), is(3));
        assertThat(integerRange("[,3]").hasLowerBound(), is(false));
        assertThat(integerRange("[,3]").hasUpperBound(), is(true));
        assertThat(integerRange("[,3]").isUpperBoundClosed(), is(true));
        assertThat(integerRange("[,3]").isLowerBoundClosed(), is(false));

        assertThat(integerRange("[,]").lower(), is(nullValue()));
        assertThat(integerRange("[,]").upper(), is(nullValue()));
        assertThat(integerRange("[,]").hasLowerBound(), is(false));
        assertThat(integerRange("[,]").hasUpperBound(), is(false));
        assertThat(integerRange("[,]").isUpperBoundClosed(), is(false));
        assertThat(integerRange("[,]").isLowerBoundClosed(), is(false));

        assertThat(integerRange("(-5,5]").isUpperBoundClosed(), is(true));
        assertThat(integerRange("(-5,5]").isLowerBoundClosed(), is(false));
        assertThat(integerRange("(,)").contains(integerRange("empty")), is(true));

        assertThat(integerRange("empty").contains(integerRange("(,)")), is(false));
    }