Since Java runs on the JIT (just in time compiler) your code has to be readable and since it translates down to byte code, it has to be read by the JVM at execution time. So you are left to work within that framework. You can make it more difficult to steel your code, but you are talking about an open system you have chosen to use in development, it rubs against the basic philosophy of Java.
So you enter the what I call they why Bother Zone of application development. Obfuscate or not to obfuscate, that is the question. I did an exercise purely for my own curiosity sake and reverse engineered an obfuscated project. It took more time, but was very doable. So you can make it harder to get to an understanding of your source by reverse engineering. Egh.
You can get a program to give you an EXE out and lose all the niceties of being able to run anywhere there is a supporting JVM. Again I say: egh.
Another approach is to do Enterprise level Java solution and host your project on the web, so your client does not get you system, just some HTML interfacing produced by your web service. Well... egh.
Security it a billion dollar a year industry and hiding your code behind bulletproof inscriptions and locks can be far more expensive than the original development. So Open Source has sprung up and is alive and well. Use it, abuse it, make it, break it... pay for support and make us rich.
I choose the latter where the client pays for support: installation and yearly support licensing and etc.