{"id":407,"date":"2017-08-14T15:02:10","date_gmt":"2017-08-14T23:02:10","guid":{"rendered":"http:\/\/www.nathanbak.com\/?p=407"},"modified":"2026-01-02T20:05:20","modified_gmt":"2026-01-03T04:05:20","slug":"dynamically-downloading-a-jar-and-adding-to-classpath","status":"publish","type":"post","link":"https:\/\/nathanbak.com\/?p=407","title":{"rendered":"Dynamically downloading a JAR and adding to classpath"},"content":{"rendered":"<p>I recently had a situation where I had a JAR that had dependencies on another JAR, but wouldn&#8217;t always be packaged with the other JAR.\u00a0 I&#8217;m not completely happy with what I ended up doing, but since I succeeded in doing what I wasn&#8217;t certain was possible, I decided to document it.\u00a0 Basically (as the title suggests), I tweaked my code so that at runtime it will download the JAR and add it to the classpath.<\/p>\n<h3>Downloading from a URL<\/h3>\n<p>Normally I&#8217;d use something like the <a href=\"https:\/\/commons.apache.org\/proper\/commons-io\/\">Apache Commons IO<\/a> library to help with downloading the JAR, but since that&#8217;s one of the pieces in the JAR to be downloaded, I&#8217;m in a catch-22 situation.\u00a0 Instead, I used vanilla Java for the implementation.\u00a0 I ran into some minor complications because the server hosting the JAR did not have a signed certificate, so I had to force Java to ignore certificate errors.\u00a0 Fortunately, no authentication was required&#8211;otherwise things would have been a bit more complicated.\u00a0 Here is my class:<\/p>\n<pre>\n\n<div class=\"codecolorer-container java default\" style=\"overflow:auto;white-space:nowrap;width:435px;height:300px;\"><div class=\"java codecolorer\"><span class=\"kw1\">package<\/span> <span class=\"co2\">com.nathanbak.gomi<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.io.File<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.io.FileOutputStream<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.io.IOException<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.io.InputStream<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.net.URL<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.nio.channels.Channels<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.nio.channels.ReadableByteChannel<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.security.KeyManagementException<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.security.NoSuchAlgorithmException<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.security.cert.CertificateException<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.security.cert.X509Certificate<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">javax.net.ssl.HostnameVerifier<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">javax.net.ssl.HttpsURLConnection<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">javax.net.ssl.SSLContext<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">javax.net.ssl.SSLSession<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">javax.net.ssl.TrustManager<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">javax.net.ssl.X509TrustManager<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">public<\/span> <span class=\"kw1\">class<\/span> UrlDownloader <span class=\"br0\">&#123;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"co3\">\/**<br \/>\n&nbsp; &nbsp; &nbsp;* Downloads the specified URL to the specified file location. Maximum size<br \/>\n&nbsp; &nbsp; &nbsp;* allowed is &lt;code&gt;Long.MAX_VALUE&lt;\/code&gt; bytes.<br \/>\n&nbsp; &nbsp; &nbsp;* <br \/>\n&nbsp; &nbsp; &nbsp;* @param url<br \/>\n&nbsp; &nbsp; &nbsp;* &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;location to read<br \/>\n&nbsp; &nbsp; &nbsp;* @param file<br \/>\n&nbsp; &nbsp; &nbsp;* &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;location to write<br \/>\n&nbsp; &nbsp; &nbsp;* @throws NoSuchAlgorithmException<br \/>\n&nbsp; &nbsp; &nbsp;* @throws KeyManagementException<br \/>\n&nbsp; &nbsp; &nbsp;* @throws IOException<br \/>\n&nbsp; &nbsp; &nbsp;*\/<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">public<\/span> <span class=\"kw4\">void<\/span> download<span class=\"br0\">&#40;<\/span><a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+url\"><span class=\"kw3\">URL<\/span><\/a> url, <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+file\"><span class=\"kw3\">File<\/span><\/a> file<span class=\"br0\">&#41;<\/span> <span class=\"kw1\">throws<\/span> <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+nosuchalgorithmexception\"><span class=\"kw3\">NoSuchAlgorithmException<\/span><\/a>, <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+keymanagementexception\"><span class=\"kw3\">KeyManagementException<\/span><\/a>, <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+ioexception\"><span class=\"kw3\">IOException<\/span><\/a> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; TrustManager <span class=\"br0\">&#91;<\/span><span class=\"br0\">&#93;<\/span> trustManagers <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> TrustManager <span class=\"br0\">&#91;<\/span><span class=\"br0\">&#93;<\/span> <span class=\"br0\">&#123;<\/span> <span class=\"kw1\">new<\/span> NvbTrustManager<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">final<\/span> SSLContext context <span class=\"sy0\">=<\/span> SSLContext.<span class=\"me1\">getInstance<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;SSL&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; context.<span class=\"me1\">init<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw2\">null<\/span>, trustManagers, <span class=\"kw2\">null<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Set connections to use lenient TrustManager and HostnameVerifier<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; HttpsURLConnection.<span class=\"me1\">setDefaultSSLSocketFactory<\/span><span class=\"br0\">&#40;<\/span>context.<span class=\"me1\">getSocketFactory<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; HttpsURLConnection.<span class=\"me1\">setDefaultHostnameVerifier<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw1\">new<\/span> NvbHostnameVerifier<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+inputstream\"><span class=\"kw3\">InputStream<\/span><\/a> is <span class=\"sy0\">=<\/span> url.<span class=\"me1\">openStream<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; ReadableByteChannel rbc <span class=\"sy0\">=<\/span> Channels.<span class=\"me1\">newChannel<\/span><span class=\"br0\">&#40;<\/span>is<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+fileoutputstream\"><span class=\"kw3\">FileOutputStream<\/span><\/a> fos <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">try<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fos <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+fileoutputstream\"><span class=\"kw3\">FileOutputStream<\/span><\/a><span class=\"br0\">&#40;<\/span>file<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fos.<span class=\"me1\">getChannel<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">transferFrom<\/span><span class=\"br0\">&#40;<\/span>rbc, <span class=\"nu0\">0<\/span>, <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+long\"><span class=\"kw3\">Long<\/span><\/a>.<span class=\"me1\">MAX_VALUE<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span> <span class=\"kw1\">finally<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>fos <span class=\"sy0\">!=<\/span> <span class=\"kw2\">null<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fos.<span class=\"me1\">close<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; is.<span class=\"me1\">close<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"co3\">\/**<br \/>\n&nbsp; &nbsp; &nbsp;* Simple &lt;code&gt;TrustManager&lt;\/code&gt; that allows unsigned certificates.<br \/>\n&nbsp; &nbsp; &nbsp;*\/<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">private<\/span> <span class=\"kw1\">static<\/span> <span class=\"kw1\">final<\/span> <span class=\"kw1\">class<\/span> NvbTrustManager <span class=\"kw1\">implements<\/span> TrustManager, X509TrustManager <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; @Override<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">public<\/span> <span class=\"kw4\">void<\/span> checkClientTrusted<span class=\"br0\">&#40;<\/span><a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+x509certificate\"><span class=\"kw3\">X509Certificate<\/span><\/a><span class=\"br0\">&#91;<\/span><span class=\"br0\">&#93;<\/span> chain, <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string\"><span class=\"kw3\">String<\/span><\/a> authType<span class=\"br0\">&#41;<\/span> <span class=\"kw1\">throws<\/span> <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+certificateexception\"><span class=\"kw3\">CertificateException<\/span><\/a> <span class=\"br0\">&#123;<\/span> <span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; @Override<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">public<\/span> <span class=\"kw4\">void<\/span> checkServerTrusted<span class=\"br0\">&#40;<\/span><a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+x509certificate\"><span class=\"kw3\">X509Certificate<\/span><\/a><span class=\"br0\">&#91;<\/span><span class=\"br0\">&#93;<\/span> chain, <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string\"><span class=\"kw3\">String<\/span><\/a> authType<span class=\"br0\">&#41;<\/span> <span class=\"kw1\">throws<\/span> <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+certificateexception\"><span class=\"kw3\">CertificateException<\/span><\/a> <span class=\"br0\">&#123;<\/span> <span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; @Override<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">public<\/span> <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+x509certificate\"><span class=\"kw3\">X509Certificate<\/span><\/a><span class=\"br0\">&#91;<\/span><span class=\"br0\">&#93;<\/span> getAcceptedIssuers<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">return<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <br \/>\n&nbsp; &nbsp; <span class=\"co3\">\/**<br \/>\n&nbsp; &nbsp; &nbsp;* Simple &lt;code&gt;HostnameVerifier&lt;\/code&gt; that allows any hostname and session.<br \/>\n&nbsp; &nbsp; &nbsp;*\/<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">private<\/span> <span class=\"kw1\">static<\/span> <span class=\"kw1\">final<\/span> <span class=\"kw1\">class<\/span> NvbHostnameVerifier <span class=\"kw1\">implements<\/span> HostnameVerifier <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; @Override<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">public<\/span> <span class=\"kw4\">boolean<\/span> verify<span class=\"br0\">&#40;<\/span><a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string\"><span class=\"kw3\">String<\/span><\/a> hostname, SSLSession session<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">return<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n\n<\/pre>\n<h3>Adding JAR to classpath<\/h3>\n<p>This was my first foray into dynamically changing the classpath at runtime.\u00a0 I found many examples of how to load a specific class (when you know the full class name) from a JAR file, but there wasn&#8217;t as much information about stuffing a JAR of whatever into the current, running classpath.\u00a0 After much trial and error, this is what I finally produced:<\/p>\n<pre>\n\n<div class=\"codecolorer-container java default\" style=\"overflow:auto;white-space:nowrap;width:435px;height:300px;\"><div class=\"java codecolorer\"><span class=\"kw1\">package<\/span> <span class=\"co2\">com.nathanbak.gomi<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.io.File<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.lang.reflect.InvocationTargetException<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.lang.reflect.Method<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.net.MalformedURLException<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">import<\/span> <span class=\"co2\">java.net.URL<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">public<\/span> <span class=\"kw1\">class<\/span> JarAdder <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">public<\/span> <span class=\"kw4\">void<\/span> addJarToClasspath<span class=\"br0\">&#40;<\/span><a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+file\"><span class=\"kw3\">File<\/span><\/a> jar<span class=\"br0\">&#41;<\/span> <span class=\"kw1\">throws<\/span> <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+nosuchmethodexception\"><span class=\"kw3\">NoSuchMethodException<\/span><\/a>, <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+securityexception\"><span class=\"kw3\">SecurityException<\/span><\/a>, <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+illegalaccessexception\"><span class=\"kw3\">IllegalAccessException<\/span><\/a>, <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+illegalargumentexception\"><span class=\"kw3\">IllegalArgumentException<\/span><\/a>, <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+invocationtargetexception\"><span class=\"kw3\">InvocationTargetException<\/span><\/a>, <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+malformedurlexception\"><span class=\"kw3\">MalformedURLException<\/span><\/a> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Get the ClassLoader class <\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+classloader\"><span class=\"kw3\">ClassLoader<\/span><\/a> cl <span class=\"sy0\">=<\/span> <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+classloader\"><span class=\"kw3\">ClassLoader<\/span><\/a>.<span class=\"me1\">getSystemClassLoader<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; Class<span class=\"sy0\">&lt;?&gt;<\/span> clazz <span class=\"sy0\">=<\/span> cl.<span class=\"me1\">getClass<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Get the protected addURL method from the parent URLClassLoader class<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+method\"><span class=\"kw3\">Method<\/span><\/a> method <span class=\"sy0\">=<\/span> clazz.<span class=\"me1\">getSuperclass<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">getDeclaredMethod<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;addURL&quot;<\/span>, <span class=\"kw1\">new<\/span> <span class=\"kw1\">Class<\/span><span class=\"br0\">&#91;<\/span><span class=\"br0\">&#93;<\/span> <span class=\"br0\">&#123;<\/span><a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+url\"><span class=\"kw3\">URL<\/span><\/a>.<span class=\"kw1\">class<\/span><span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Run projected addURL method to add JAR to classpath<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; method.<span class=\"me1\">setAccessible<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw2\">true<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; method.<span class=\"me1\">invoke<\/span><span class=\"br0\">&#40;<\/span>cl, <span class=\"kw1\">new<\/span> <a href=\"http:\/\/www.google.com\/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+object\"><span class=\"kw3\">Object<\/span><\/a><span class=\"br0\">&#91;<\/span><span class=\"br0\">&#93;<\/span> <span class=\"br0\">&#123;<\/span>jar.<span class=\"me1\">toURI<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">toURL<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n\n<\/pre>\n<p>The addJarToClasspath() method wasn&#8217;t necessary on my Windows system.\u00a0 My main JAR had a classpath to the dependency JAR specified in the MANIFEST.MF and as long as the JAR was downloaded there, it would be found.\u00a0 However, on Linux it didn&#8217;t work and so the method is necessary (and it doesn&#8217;t seem to hurt anything on Windows).<\/p>\n<h3>Other thoughts<\/h3>\n<ul>\n<li>It is important to do the download and classpath changes before calling any code that depends on the stuff in the JAR.\u00a0 Even imports in the same class can cause problems.<\/li>\n<li>The downloadUrl() method is pretty generic and could be reused in a lot of situations provided the content being downloaded doesn&#8217;t get to big.<\/li>\n<li>Different versions of Java seem to behave differently&#8211;I&#8217;ve only tested two Java&#8217;s so far (one on Windows and one on Linux), but have seen very different behaviour.<\/li>\n<li>Since the certificate checking is disabled and code is loaded and at runtime, it seems like it would be an easy setup to attack or hack.<\/li>\n<li>This method could potentially be used for applications to self-update without needing to restart.<\/li>\n<\/ul>\n<h3>Conclusion<\/h3>\n<p>I&#8217;m not sure this is a permanent solution for my problem, but it does work for the time being.\u00a0 Also, I think the parts I learned while going through the process have potential to be used in future situations.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I recently had a situation where I had a JAR that had dependencies on another JAR, but wouldn&#8217;t always be packaged with the other JAR.\u00a0 I&#8217;m not completely happy with what I ended up doing, but since I succeeded in doing what I wasn&#8217;t certain was possible, I decided to document it.\u00a0 Basically (as the &hellip; <a href=\"https:\/\/nathanbak.com\/?p=407\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Dynamically downloading a JAR and adding to classpath&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[16],"class_list":["post-407","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-java"],"_links":{"self":[{"href":"https:\/\/nathanbak.com\/index.php?rest_route=\/wp\/v2\/posts\/407","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nathanbak.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nathanbak.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nathanbak.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nathanbak.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=407"}],"version-history":[{"count":6,"href":"https:\/\/nathanbak.com\/index.php?rest_route=\/wp\/v2\/posts\/407\/revisions"}],"predecessor-version":[{"id":415,"href":"https:\/\/nathanbak.com\/index.php?rest_route=\/wp\/v2\/posts\/407\/revisions\/415"}],"wp:attachment":[{"href":"https:\/\/nathanbak.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=407"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nathanbak.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=407"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nathanbak.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=407"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}