Reputation: 443
I am aware that to combine several jars and create one executable jar, I would need to use a tool like OneJar if I don't want to unpack the dependent jars. OneJar has its own custom class loader which can find the required classes in the associated jars and load them.
My question is : Why is the default class loader not able to load classes from within the attached jars. Is it because of Security ? I would appreciate a clear explanation of the reasons behind the need for a custom class loader when creating a single executable jar which holds other dependent jars (without unpacking them). Thanks,
Upvotes: 3
Views: 2146
Reputation: 1638
In addition to other answers (the one from Stephen being the more accurate so far), also consider that the JVM does not preemptively explore the available classpath entries, so in order to find class com.foo.Bar it will look at a path like com/foo/Bar.class in the entries listed in the classpath. If this path could be inside a nested jar (that is not itself listed in the classpath declaration), in order to find said path the classloader should first explore all the nested jar (unpacking them in the process) in order to do the appropriate lookup.
Upvotes: 1
Reputation: 14096
The technical reason is that the uri specification for jar:
does not support nesting.
You could write a URI handler that addresses this need, but performance will start to hit as you nest down inside each jar file.
With a single jar file, random access is possible as the index gives file system offsets and you can seek each offset and read only the file you want
With a nested jar, you can seek the inner jar, but to pull a file out of that jar you have to unzip the inner jar from the outer before you can seek.
I would look at solutions such as those offered by either OSGi or by the Maven Shade Plugin if you don't want to extract the jar files to a temporary directory and build your own classloader from the resulting classpath
Upvotes: 2
Reputation: 136022
You can place all jars your app needs in you app folder (eg lib) and either use
java -cp lib/*.jar ...
or enumerate all jars in main jar's manifest Class-Path attribute.
Upvotes: 0
Reputation: 1284
I doubt the decision is due to security: it would be surprising if anything is made more or less secure by being nested. In fact it might be quite nice to be able to sign all JAR's as a whole in my uber-JAR and have them all checked for integrity as part of verifying my JAR.
I would think the main reasons are performance and simplicity. If JAR's can be nested, what should be the answers to these questions:
It seems most straightforward to think of a JAR just like a shared library: it's a nice, packed, indexed, signed, flat, ready-to-link package. It's notable that Unix .so's and Windows .dll's also do not allow nesting, and for much the same reasons I suspect.
Side note: creating "uberjar's" in general is often not needed: you can usually use the Class-Path
field in the main JAR's manifest to allow it to pull in external libs.
Upvotes: 0