|There is execution flow. And code references.
Neither guarantees finding all code usage.
Code is loaded dynamically in java. A class is not loaded until it is referenced. The byte codes contain that information though so it can be dynamically determined. But that doesn't mean it actually runs.
Then a developer can write code that dynamically loads classes. Or they can use libraries that do that.
So normally execution flow needs to be done to determine what runs.
But, for example, what happen if there is a report that only runs on the first of the month and you use execution profiling on the 15th to find all the classes that are used. You will not find the classes used in that report.
So it is manual process...
You use profiling and attempt to execute your application. The profiled classes are the ones that are executed. Anything else isn't. Then build your jar(s) using only those and then completely test the application. If your tests are complete then it should work.