I asked the folks on the SourceForge JFlex mailing list, and one of them replied to me - turns out JFlex 1.4.* can't handle Unicode characters that are not representable in 16 bits.
Oh, but it can handle those.
First at all, let me bring a correction to \u2f800-\u2fa1f. The last value is indeed not representable on 16 bits, but only because the UNICODE block definition stops at \u2fa1d, thus the value is UNICODE invalid even on its 32 bits representation
Now, the trick to convince JFlex to handle OK your troubled [\u2f800-\u2fa1d] range: Java code (and string literals) uses sort-of a UTF16 encoding, so a 16-bits "surrogate" (the higher UTF16 word) followed by the other 16 bits paired character.
For the range that you need, you are lucky: the first 16bits surrogate stays the same for the whole range i.e. \uD87E, while the lower 16bit varies in the [\uDC00-\uDE1D] range. So, your han macro becomes
han = [\u3400-\u9fff\uf900-\ufaff] | \uD87E[\uDC00-\uDE1D]
A resource which, in my laziness to transform 32bit wchars to UTF16/8 encoding, I found useful: http://www.fileformat.info. E.g. http://www.fileformat.info/info/unicode/char/2fa1d/index.htm and scroll down to "UTF-16 (hex)" or "C/C++/Java source code".