Discussion:
Versioning fun
(too old to reply)
Arne Vajhøj
2024-03-27 13:11:43 UTC
Permalink
A relative little know fact about the JVM is that
it implicit prefixes class names with the id of
the classloader.

That mean that it is possible to load and use
different version of the same class within the
same application. If one knows how.

$ type HasTest.java
public interface HasTest {
public void test();
}
$ javac HasTest.java
$ copy X_v1.java X.java
$ type X.java
public class X implements HasTest {
public void test() {
System.out.printf("Technically I am a %s, but I am version
1\n", this.getClass().getName());
}
}
$ javac X.java
$ jar cvf v1.jar X.class
added manifest
adding: X.class(in = 588) (out= 376)(deflated 36%)
$ del X.class;*
$ copy X_v2.java X.java
$ type X.java
public class X implements HasTest {
public void test() {
System.out.printf("Technically I am a %s, but I am version
2\n", this.getClass().getName());
}
}
$ javac X.java
$ jar cvf v2.jar X.class
added manifest
adding: X.class(in = 588) (out= 376)(deflated 36%)
$ del X.class;*
$ type TestX.java
import java.io.File;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;

public class TestX {
public static void main(String[] args) throws Exception {
ClassLoader v1 = new URLClassLoader(new URL[] { (new
File("v1.jar")).toURI().toURL() });
HasTest o1 = (HasTest)Class.forName("X", true, v1).newInstance();
o1.test();
ClassLoader v2 = new URLClassLoader(new URL[] { (new
File("v2.jar")).toURI().toURL() });
HasTest o2 = (HasTest)Class.forName("X", true, v2).newInstance();
o2.test();
}
}
$ javac TestX.java
$ java "TestX"
Technically I am a X, but I am version 1
Technically I am a X, but I am version 2

Arne
Single Stage to Orbit
2024-03-27 14:30:59 UTC
Permalink
Post by Arne Vajhøj
$ java "TestX"
Technically I am a X, but I am version 1
Technically I am a X, but I am version 2
It is vital to delete the X.class files otherwise it will load that
instead of the jar files.
--
Tactical Nuclear Kittens
Arne Vajhøj
2024-03-27 15:03:57 UTC
Permalink
Post by Single Stage to Orbit
Post by Arne Vajhøj
$ java "TestX"
Technically I am a X, but I am version 1
Technically I am a X, but I am version 2
It is vital to delete the X.class files otherwise it will load that
instead of the jar files.
Yes. I should probably have mentioned that explicit.

Java class loaders are hierarchical and searched top down. The
default class loader with default classpath of current directory
is searched before the jar files in the special class loaders.

$ type Dump.java
import java.io.File;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.ArrayList;

public class Dump {
private static void dump(String lbl, ClassLoader cl) {
List<ClassLoader> lst = new ArrayList<ClassLoader>();
ClassLoader cl1 = cl;
do {
lst.add(cl1);
cl1 = cl1.getParent();
} while(cl1 != null);
System.out.printf("Class search path for %s:\n", lbl);
for(int i = lst.size() - 1; i >= 0; i--) {
System.out.printf(" %d - %s", lst.size() - i,
lst.get(i).getClass().getName());
if(lst.get(i) instanceof URLClassLoader) {
System.out.print(" -");
for(URL url : ((URLClassLoader)lst.get(i)).getURLs()) {
System.out.printf(" %s", url);
}
}
System.out.println();
}
}
public static void main(String[] args) throws Exception {
dump("Default", Dump.class.getClassLoader());
ClassLoader v1 = new URLClassLoader(new URL[] { (new
File("v1.jar")).toURI().toURL() });
dump("V1 library", v1);
ClassLoader v2 = new URLClassLoader(new URL[] { (new
File("v2.jar")).toURI().toURL() });
dump("V2 library", v2);
}
}
$ javac Dump.java
$ java Dump
Class search path for Default:
1 - sun.misc.Launcher$ExtClassLoader -
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/cldrdata.jar
file:/DISK$X86SYS/SYS0
/SYSCOMMON/openjdk$80/jre/lib/ext/dnsns.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/jaccess.jar
file:/DISK$X86SYS/SY
S0/SYSCOMMON/openjdk$80/jre/lib/ext/localedata.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/nashorn.jar
file:/DISK$X8
6SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunec.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunjce_provider.jar
fil
e:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunpkcs11.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/zipfs.jar
2 - sun.misc.Launcher$AppClassLoader - file:/DISK2/ARNE/
Class search path for V1 library:
1 - sun.misc.Launcher$ExtClassLoader -
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/cldrdata.jar
file:/DISK$X86SYS/SYS0
/SYSCOMMON/openjdk$80/jre/lib/ext/dnsns.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/jaccess.jar
file:/DISK$X86SYS/SY
S0/SYSCOMMON/openjdk$80/jre/lib/ext/localedata.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/nashorn.jar
file:/DISK$X8
6SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunec.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunjce_provider.jar
fil
e:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunpkcs11.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/zipfs.jar
2 - sun.misc.Launcher$AppClassLoader - file:/DISK2/ARNE/
3 - java.net.URLClassLoader - file:/DISK2/ARNE/v1.jar
Class search path for V2 library:
1 - sun.misc.Launcher$ExtClassLoader -
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/cldrdata.jar
file:/DISK$X86SYS/SYS0
/SYSCOMMON/openjdk$80/jre/lib/ext/dnsns.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/jaccess.jar
file:/DISK$X86SYS/SY
S0/SYSCOMMON/openjdk$80/jre/lib/ext/localedata.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/nashorn.jar
file:/DISK$X8
6SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunec.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunjce_provider.jar
fil
e:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunpkcs11.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/zipfs.jar
2 - sun.misc.Launcher$AppClassLoader - file:/DISK2/ARNE/
3 - java.net.URLClassLoader - file:/DISK2/ARNE/v2.jar

Arne
Single Stage to Orbit
2024-03-27 16:13:15 UTC
Permalink
Post by Arne Vajhøj
Post by Single Stage to Orbit
It is vital to delete the X.class files otherwise it will load that
instead of the jar files.
Yes. I should probably have mentioned that explicit.
Java class loaders are hierarchical and searched top down. The
default class loader with default classpath of current directory
is searched before the jar files in the special class loaders.
There's the '-cp' to find these classes in other places. My long
repressed java memories are returning, :(
--
Tactical Nuclear Kittens
Arne Vajhøj
2024-03-27 16:54:16 UTC
Permalink
Post by Single Stage to Orbit
Post by Arne Vajhøj
Post by Single Stage to Orbit
It is vital to delete the X.class files otherwise it will load that
instead of the jar files.
Yes. I should probably have mentioned that explicit.
Java class loaders are hierarchical and searched top down. The
default class loader with default classpath of current directory
is searched before the jar files in the special class loaders.
There's the '-cp' to find these classes in other places. My long
repressed java memories are returning, :(
Whatever is specified by -cp get added to the app class loader.

$ java -cp .:a.jar:/foo/b.jar:/bar/c.jar Dump
Class search path for Default:
1 - sun.misc.Launcher$ExtClassLoader -
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/cldrdata.jar
file:/DISK$X86SYS/SYS0
/SYSCOMMON/openjdk$80/jre/lib/ext/dnsns.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/jaccess.jar
file:/DISK$X86SYS/SY
S0/SYSCOMMON/openjdk$80/jre/lib/ext/localedata.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/nashorn.jar
file:/DISK$X8
6SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunec.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunjce_provider.jar
fil
e:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunpkcs11.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/zipfs.jar
2 - sun.misc.Launcher$AppClassLoader - file:/DISK2/ARNE/
file:/DISK2/ARNE/a.jar file:/foo/b.jar file:/bar/c.jar
Class search path for V1 library:
1 - sun.misc.Launcher$ExtClassLoader -
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/cldrdata.jar
file:/DISK$X86SYS/SYS0
/SYSCOMMON/openjdk$80/jre/lib/ext/dnsns.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/jaccess.jar
file:/DISK$X86SYS/SY
S0/SYSCOMMON/openjdk$80/jre/lib/ext/localedata.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/nashorn.jar
file:/DISK$X8
6SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunec.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunjce_provider.jar
fil
e:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunpkcs11.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/zipfs.jar
2 - sun.misc.Launcher$AppClassLoader - file:/DISK2/ARNE/
file:/DISK2/ARNE/a.jar file:/foo/b.jar file:/bar/c.jar
3 - java.net.URLClassLoader - file:/DISK2/ARNE/v1.jar
Class search path for V2 library:
1 - sun.misc.Launcher$ExtClassLoader -
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/cldrdata.jar
file:/DISK$X86SYS/SYS0
/SYSCOMMON/openjdk$80/jre/lib/ext/dnsns.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/jaccess.jar
file:/DISK$X86SYS/SY
S0/SYSCOMMON/openjdk$80/jre/lib/ext/localedata.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/nashorn.jar
file:/DISK$X8
6SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunec.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunjce_provider.jar
fil
e:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/sunpkcs11.jar
file:/DISK$X86SYS/SYS0/SYSCOMMON/openjdk$80/jre/lib/ext/zipfs.jar
2 - sun.misc.Launcher$AppClassLoader - file:/DISK2/ARNE/
file:/DISK2/ARNE/a.jar file:/foo/b.jar file:/bar/c.jar
3 - java.net.URLClassLoader - file:/DISK2/ARNE/v2.jar

Arne
Lawrence D'Oliveiro
2024-03-27 21:16:33 UTC
Permalink
A relative little know fact about the JVM is that it implicit prefixes
class names with the id of the classloader.
I currently have to use Java for a project that involves connecting to an
in-house server via HTTPS (modifying an existing app). If there is one
word that sums up the Java language and APIs, it is “bureaucracy”.

Consider setting up a TLS/SSL context. In Python, creating the context
object is one call:

sctx = ssl.SSLContext(protocol = ssl.PROTOCOL_TLS_CLIENT)

Loading a private CA cert is one call:

sctx.load_verify_locations(ca_cert_file)

Loading a cert and key for client-side authentication is one call:

sctx.load_cert_chain(client_cert_file, client_key_file)

But in Java, you first need to create a KeyStore. Load the CA cert via a
CertificateFactory and creating a TrustedCertificateEntry. Call the
factory’s generateCertificate routine to load the client cert. Then go
through a whole lot more contortions to load the client key file.

And then, you have to set up a TrustManagerFactory to create a
TrustManager, and a KeyManagerFactory to create a KeyManager, so that you
can load the contents of the KeyStore, via those two separate intermediary
objects, into an actual SSLContext for use in HTTPS connections.

Loading...