File: src/java/org/apache/commons/math/complex/ComplexFormat.java
Issue: java.lang.StringIndexOutOfBoundsException in ComplexFormat.parse(String source, ParsePosition pos)
The parse(String source, ParsePosition pos) method in the ComplexFormat class does not check whether the imaginary character is set or not which produces StringIndexOutOfBoundsException in the substring method :
(line 375 of ComplexFormat)
...
        // parse imaginary character
        int n = getImaginaryCharacter().length();
        startIndex = pos.getIndex();
        int endIndex = startIndex + n;
        if (source.substring(startIndex, endIndex).compareTo(
            getImaginaryCharacter()) != 0) {
...
I encoutered this exception typing in a JTextFied with ComplexFormat set to look up an AbstractFormatter.
If only the user types the imaginary part of the complex number first, he gets this exception.
Solution: Before setting to n length of the imaginary character, check if the source contains it. My proposal:
...
        int n = 0;
        if (source.contains(getImaginaryCharacter()))
        n = getImaginaryCharacter().length();
...		 
F.S.

Buggy code:
public Complex parse(String source, ParsePosition pos) {
    int initialIndex = pos.getIndex();

    // parse whitespace
    parseAndIgnoreWhitespace(source, pos);

    // parse real
    Number re = parseNumber(source, getRealFormat(), pos);
    if (re == null) {
        // invalid real number
        // set index back to initial, error index should already be set
        // character examined.
        pos.setIndex(initialIndex);
        return null;
    }

    // parse sign
    int startIndex = pos.getIndex();
    char c = parseNextCharacter(source, pos);
    int sign = 0;
    switch (c) {
    case 0 :
        // no sign
        // return real only complex number
        return new Complex(re.doubleValue(), 0.0);
    case '-' :
        sign = -1;
        break;
    case '+' :
        sign = 1;
        break;
    default :
        // invalid sign
        // set index back to initial, error index should be the last
        // character examined.
        pos.setIndex(initialIndex);
        pos.setErrorIndex(startIndex);
        return null;
    }

    // parse whitespace
    parseAndIgnoreWhitespace(source, pos);

    // parse imaginary
    Number im = parseNumber(source, getRealFormat(), pos);
    if (im == null) {
        // invalid imaginary number
        // set index back to initial, error index should already be set
        // character examined.
        pos.setIndex(initialIndex);
        return null;
    }

    // parse imaginary character
    int n = getImaginaryCharacter().length();
    startIndex = pos.getIndex();
    int endIndex = startIndex + n;
    if (
        source.substring(startIndex, endIndex).compareTo(
        getImaginaryCharacter()) != 0) {
        // set index back to initial, error index should be the start index
        // character examined.
        pos.setIndex(initialIndex);
        pos.setErrorIndex(startIndex);
        return null;
    }
    pos.setIndex(endIndex);

    return new Complex(re.doubleValue(), im.doubleValue() * sign);
}

Fixed code:
public Complex parse(String source, ParsePosition pos) {
    int initialIndex = pos.getIndex();

    // parse whitespace
    parseAndIgnoreWhitespace(source, pos);

    // parse real
    Number re = parseNumber(source, getRealFormat(), pos);
    if (re == null) {
        // invalid real number
        // set index back to initial, error index should already be set
        // character examined.
        pos.setIndex(initialIndex);
        return null;
    }

    // parse sign
    int startIndex = pos.getIndex();
    char c = parseNextCharacter(source, pos);
    int sign = 0;
    switch (c) {
    case 0 :
        // no sign
        // return real only complex number
        return new Complex(re.doubleValue(), 0.0);
    case '-' :
        sign = -1;
        break;
    case '+' :
        sign = 1;
        break;
    default :
        // invalid sign
        // set index back to initial, error index should be the last
        // character examined.
        pos.setIndex(initialIndex);
        pos.setErrorIndex(startIndex);
        return null;
    }

    // parse whitespace
    parseAndIgnoreWhitespace(source, pos);

    // parse imaginary
    Number im = parseNumber(source, getRealFormat(), pos);
    if (im == null) {
        // invalid imaginary number
        // set index back to initial, error index should already be set
        // character examined.
        pos.setIndex(initialIndex);
        return null;
    }

    // parse imaginary character
    int n = getImaginaryCharacter().length();
    startIndex = pos.getIndex();
    int endIndex = startIndex + n;
    if ((startIndex >= source.length()) ||
        (endIndex > source.length()) ||
        source.substring(startIndex, endIndex).compareTo(
        getImaginaryCharacter()) != 0) {
        // set index back to initial, error index should be the start index
        // character examined.
        pos.setIndex(initialIndex);
        pos.setErrorIndex(startIndex);
        return null;
    }
    pos.setIndex(endIndex);

    return new Complex(re.doubleValue(), im.doubleValue() * sign);
}