You are going to kick yourself when you see this:
    /**
     * Lists directory contents recursively.  Note that
     * the ftp must support such a listing.  Many ftp
     * servers disable recursive listings since it can
     * be used to attack and bog down the server.  An
     * FTP server may also accept the command, but not
     * actually return a recursive listing.
     *
     *  @param  dirname  name of directory OR filemask
     *  @return  an array of directory listing strings
     */
    public String[] dirRecursive(String dirname)
        throws IOException, FTPException {
            return dirRecursive(dirname, false);
    }
    /**
     * Lists directory contents recursively.  Note that
     * the ftp must support such a listing.  Many ftp
     * servers disable recursive listings since it can
     * be used to attack and bog down the server. An
     * FTP server may also accept the command, but not
     * actually return a recursive listing.
     *
     *  @param  dirname  name of directory OR filemask
     *  @return  an array of directory listing strings
     */
    public String[] dirRecursive(String dirname, boolean full)
        throws IOException, FTPException {
       
       checkConnection(true);
        
        try {
            // set up data channel
            data = control.createDataSocket(connectMode);
            data.setTimeout(timeout);
    
            // send the retrieve command
            String command = full ? "LIST -R ":"NLST -R ";
            if (dirname != null)
                command += dirname;
    
            // some FTP servers bomb out if NLST has whitespace appended
            command = command.trim();
            FTPReply reply = control.sendCommand(command);
    
            // check the control response. wu-ftp returns 550 if the
            // directory is empty, so we handle 550 appropriately. Similarly
            // proFTPD returns 450
            String[] validCodes1 = {"125", "150", "450", "550"};
            lastValidReply = control.validateReply(reply, validCodes1);  
    
            // an empty array of files for 450/550
            String[] result = new String[0];
            
            // a normal reply ... extract the file list
            String replyCode = lastValidReply.getReplyCode();
            if (!replyCode.equals("450") && !replyCode.equals("550")) {
             // get a character input stream to read data from .
             LineNumberReader in = null;
                Vector lines = new Vector();    
                try {
                in = new LineNumberReader(
                       new InputStreamReader(data.getInputStream()));
    
                 // read a line at a time
                 String line = null;
                 while ((line = readLine(in)) != null) {
                     if (line.trim().length() != 0) {
                            lines.addElement(line);
                        }
                 }
                }
                finally {
                    try {
                        if (in != null)
                            in.close();
                    }
                    catch (IOException ex) {
                        log.error("Failed to close socket in dir()", ex);
                    }
                    closeDataSocket();
                }
                    
                // check the control response
                String[] validCodes2 = {"226", "250"};
                reply = control.readReply();
                lastValidReply = control.validateReply(reply, validCodes2);
    
                // empty array is default
                if (!lines.isEmpty()) {
                    result = new String[lines.size()];
                    lines.copyInto(result);
                }
            }
            return result;
        }
        finally {
            closeDataSocket();
        }        
    }
Keep in mind that the ftp server you are communicating with must support it.  Many do not have it enabled by default because it opens a hole for a potential DOS attack on large directories.  I have also found one ftp server where the recursive option worked when a did a full list (LIST -R) but onl