After finishing my project, I want to remove all the unused classes to reduce the size of jar file when packaging.
I am using IntelliJ, it can help me detect unused classed but it includes some classes are only called by reflection (runtime only). Moreover, it cannot detect unused classes in external libraries.
One important thing, I want to remove unused classed in external libraries. Example, when I use BiMap from Google Guava, I have to include Guava lib, but I just want to use only BiMap, including whole Guava makes my jar getting big
So, I thinked reversely, instead of finding unused classes, I want to know all the classes is used/called when run (I will remove unused classed/packages manually). How can I do that?
Consider using a tool like Proguard (http://proguard.sourceforge.net/) to do this
I am unsure how you can limit the contents of the jar file to only the referenced Java classes. You may also run into issues when a class is loaded dynamically.
Guava explains on their site how you can include a subset of Guava in your build, by using ProGuard: https://github.com/google/guava/wiki/UsingProGuardWithGuava
Related
I've got a large Java library and I want to develop several smaller applications that interface this library. The library will be present on the target device's class-path as JAR, but I would like to avoid the need to have the entire library (either JAR or source) present at compile-time if possible. (If it matters, the JAR is quite huge and I want to protect intellectual property too, though it's not my primary concern.)
In C++, I would solve this issue by creating a DLL (.so) and copying just the relevant class and function definition headers to my project and adding them to include path at compile time, let the dynamic linker do the job at runtime.
How to do this in Java? One idea I have would be to remove private methods/members, and strip methods of relevant classes so that their bodies are empty and the real classes and methods with same signatures are loaded at runtime. However, this approach seems quite ugly and rudimental, plus some tool would be needed to automate this process. Is there a tool to do this? Is there a better way?
I don't think it's a duplicate of this question. The point of that question is to minimize size of the resulting JAR file at compile time, by removing unnecessary classes. My point is not to remove unused definitions, but to avoid the need of having the complete library JAR at compile time at all. Though these are simmilar and there may be a way how to achieve what I want using ProGuard, the linked question does not discuss it.
There's no exact equivalent for header files in Java, but compiling against the "header" (in the meaning of "contract") without having the actual implementation can be achieved using interfaces:
Create interface for every class you want the "header" for, with relevant methods
Make the actual classes implement the respective interfaces
Pack the interfaces into one JAR, and the implementations into another one
(if you're using a build tool like Maven, use two projects, and let the implementation project depend on the interface one)
Only provide the interface JAR at compile time, and both at run time
There of course will need to be some artifact that knows the actual implementations and can instantiate them, or you'll have to use some lookup that searches classpath for a suitable implementation.
If your problem is only due to the minimization of the final jar and you use Apache Maven, you could try to use the option "provided" when you declare a dependency in the pom.xml.
For example I use this dependency declaration:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.48</version>
<scope>provided</scope>
</dependency>
This means that my java compiler use the bouncycastle library to compile, but finally it doesn't include it in the final jar. You should provide it during execution.
I have a library that I'm using in an Java application - it's important for certain functionality, but it's optional. Meaning that if the JAR file is not there, the program continues on without issue. I'd like to open source my program, but I can not include this library, which is necessary to compile the source code as I have numerous import statements to use the API. I don't want to maintain two code sets. What is the best way to remove the physical jar file from open source release, but still maintain the code to support it where other people could still compile it?
the typical approach taken is to define the wrapper API (i.e. interfaces) and include those interfaces in the open sourced code, and then provide configuration options where one can specify class names of classes that implement certain interfaces.
You will import API interfaces instead of importing classes directly into your open sourced code. This way, you are open sourcing the API but not the implementation of the parts that you do not want to open source or you cannot open source.
There are many examples, but take a look at JDBC API (interfaces) and JDBC drivers (implementation classes) for starters.
I was pretty much typing the same thing as smallworld with one addition. If this API were necessary you can use a project build tool like Maven to handle the dependencies on you project. If someone checks it out from source control with the pom they can download the dependencies for themselves and you don't have to include them in a source repo.
There's probably a number of ways to fix this, here's a couple I can think of:
If you have only a couple of methods you need to invoke in the 3rd party library, you could use reflection to invoke those methods. It creates really verbose code, that is hard to read though.
If you don't have too much of the API in the 3rd party library you use, you could also create a separate JAR file, containing just a non-functional shell of the classes in the library (just types with the same names and methods with the same signatures). You can then use this JAR to distribute and compile against. At run-time you'd replace it with the real JAR if available.
The most common way is probably to just create a wrapper API in a separate module/project for the code that is dependent on the 3rd party library, and possibly distribute a pre-built JAR. This might go against your wish to not maintain two code sets, but may prove to be the best and less painful solution in the long run.
I am working on a desktop application, I use Hibernate and HSQLDB. When I make my application a runnable jar file, it has a bigger fize size than I think. I see that the biggest part is from Hibernate and its dependencies. I am not sure if I need all of the Hibernate features. Is there a way to get rid of the parts of Hibernate and its dependency libraries which I don't use?
Under the /lib/ folder in Hibernate zip you will see a folder called /required/. For very basic Hibernate apps thats all you will need though you may need additional JARs for things such as JPA. I would start by only including the JARs in the lib/required/ directory, see if your project works, and if it doesn't add what you need to get your project working again.
perhaps you could use a tool to analyse your classes and dependencies (for e.g. http://www.dependency-analyzer.org/). Here is another post about it: How do I find out what jar files are actually used when compiling a java project.
the other way is to remove some jars (or even single class files) and try whether your application is still working or not. but i think this is not a very good way...
I can't think of a better tool for this than ProGuard.
ProGuard is a free Java class file shrinker, optimizer, obfuscator, and preverifier. It detects and removes unused classes, fields, methods, and attributes. It optimizes bytecode and removes unused instructions. It renames the remaining classes, fields, and methods using short meaningless names. Finally, it preverifies the processed code for Java 6 or for Java Micro Edition.
I need to deploy only the referenced classes in a very limited environment as A data carousel for Interactive TV. Bandwidth is expensive and .jar files are not supported.
Check out ProGuard which is an obfuscator that will list code and classes that are not used. Obfuscating itself usually results in a smaller foot print.
ProGuard is a free Java class file shrinker, optimizer, obfuscator, and preverifier. It detects and removes unused classes, fields, methods, and attributes. It optimizes bytecode and removes unused instructions. It renames the remaining classes, fields, and methods using short meaningless names. Finally, it preverifies the processed code for Java 6 or for Java Micro Edition.
Sounds like you need a dependency analyzer. This one might do the trick.
ProGuard might be even better, since it can also shrink existing .class files.
Perhaps you could load a custom class loader which does support jar files or ideally pack200 files.
It may not be best practice but are there ways of removing unsused classes from a third party's jar files. Something that looks at the way in which my classes are using the library and does some kind of coverage analysis, then spits out another jar with all of the untouched classes removed.
Obviously there are issues with this. Specifically, the usage scenario I put it though may not use all classes all the time.
But neglecting these problems, can it be done in principle?
There is a way.
The JarJar project does this AFAIR. The first goal of the JarJar project is to allow one to embed third party libraries in your own jar, changing the package structure if necessary. Doing so it can strip out the classes that are not needed.
Check it out at http://code.google.com/p/jarjar/.
Here is a link about shrinking jars: http://sixlegs.com/blog/java/jarjar-keep.html
There is a tool in Ant called a classfileset. You specify the list of root classes that you know you need, and then the classfileset recursively analyzes their code to find all dependencies.
Alternatively, you could develop a good test suite that exercises all of the functions that you need, then run your tests under a test coverage tool. The tool will tell you which classes (and statement in them) were actually utilized. This could give you an even smaller set of code than what you'd find with static analysis.
I use ProGuard for this. As well as being an excellent obfuscator, it has a code shrinking phase which can combine multiple JARs and then strip out any unused classes or class members. It does an excellent job at shrinking.
At a previous job, I used a Java obfuscator that as well as obfuscating the code, also removed classes and methods that weren't being used. If you were doing "Class.byName" or any other type of reflection stuff, you needed to tell the obfuscator because it couldn't tell by inspecting the code what classes or methods called by reflection.
The problem, of course, is that you don't know if other parts of the third party library are doing any reflection, and so removing an "unused" class might cause things to break in an obscure case that you haven't tested.
jar is just a zip file, so I guess you can. If you could get to the source, it's cleaner. Maybe try disassembling the class?
Adding to this question, can that improve performance? Since the classes not used would not be JIT compiled improving startup time or does the java automatically detect that while compiling to bytecode and do not even deal with the code that is not used?
This would be an interesting project (has anyone done it already?)
I presume you'd give the tool your jar(s) as a starting point, and the library jar to clean up. It could use reflection to determine which classes your jar(s) reference directly, and which are used indirectly down the call tree (this is not trivial at all, but doable). If it encounters any reflection code in any of the two places, it should give a very loud warning.