What I don't like about JNI is how it approaches wrapper generation - essentially assuming you are writing your C/C++ code *specifically* to be used in Java. Case in point being the fact you basically have to directly modify your header files. This can of course be avoided by writing code/headers that include JNI and your native headers - but then on top of that you need to write wrapper headers and wrapper code. Most other wrapper systems don't make this assumption and just let you write an interface or some wrapper code and be done with it.
On top of that actual generation of the wrapped binaries isn't nearly as smooth and integrated as say Ruby native gems. Maybe it can be set up to be cleanly automated so everything will be generated for your build target at compile time but in my currently limited time dealing with Java I've yet to see such a setup.
I would like to point out I'm no expert on JNI and have only used it twice before going all SWIG. Actually if you know of a good example or guide for JNI that could set me straight I'd love to see it.