java.net host identity, and a real java.util.Properties - #704
Merged
Merged
Conversation
added 5 commits
August 22, 2026 16:02
InetAddress grew getLocalHost, getAllByName, .getCanonicalHostName and .getAddress, and java.net.NetworkInterface is new: getNetworkInterfaces, getByName, getByInetAddress, .getInetAddresses, .getHardwareAddress, .getDisplayName, over getifaddrs(3). IPv4, like the rest of jolt.socket. getifaddrs reports one entry per address, so the entries are grouped by name into one interface each, which is the shape java.net presents. Touching any java.net class now loads jolt.socket on demand, the courtesy java.time and MessageDigest already had. A JVM library reaching for InetAddress should no more have to know which namespace installs it than it does on the JVM. System/getProperties returned a plain map, which answered .getProperty as a key lookup and so read nil for every system property — a library that reads them through the Properties API saw nothing. There is now a java.util.Properties with the defaults chain the JVM's has: it shares the override table, so a setProperty through it is what System/getProperty reports, and the values jolt computes on read (user.dir, java.class.path) are its defaults rather than frozen entries, so they stay current. The three spellings of "is this a hashmap-backed jhost" are one predicate now. They had drifted, which is why Properties was countable but not seqable until the map view went through one accessor.
…sses resolve lazily Two corrections to the previous commit, both found by checking the reference rather than assuming. java.util.Properties: the JVM is precise about which operations span the defaults chain. getProperty, propertyNames and stringPropertyNames do; the inherited Hashtable surface — get, containsKey, keySet, values, size — does not. A Properties holding only defaults answers isEmpty true and an empty keySet while its propertyNames lists them. The whole Map surface had been made defaults-aware, which is a superset the JVM does not have. That leaves System/getProperties, whose values must be visible to get and count because on the JVM they are real entries. It now holds them as real entries, rebuilt per call so user.dir and java.class.path stay current, and writes through to the override store so a setProperty is what System/getProperty reports. NetworkInterface no longer reverse-resolves every address as it enumerates. The JVM leaves an address read off an interface unresolved — its toString is "/127.0.0.1" — and resolves on the first .getHostName, caching. Resolving eagerly put a DNS round trip per address in the way of listing interfaces.
…lts chain nests A 30-case differential run against the reference turned up two divergences. setProperty consulted the defaults for the value it returns. On the JVM it delegates to Hashtable.put, so it reports what THIS object held — nil when the key was only ever in the defaults — not the value it is now shadowing. A Properties whose defaults is itself a Properties searched only that object's own table, because the defaults were read with a plain map lookup and the Map surface is defaults-blind. getProperty and propertyNames now recurse down the chain, as the JVM's recursive defaults.getProperty does. The three cases are pinned in the jolt.socket gate.
Changelog only: main's Unreleased entries (rounds 1 and 4, the interface-tag dispatch fix) and this branch's meet in one Added and one Fixed section.
Changelog only: the FFI entries join this branch's under one Added and one Fixed section.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes jolt-6227.
The bead was filed from clj-uuid's comments; reading its
node.cljshowed those comments describe the approach it rejects.make-node-idnever calls.getHardwareAddress— it digests the machine's identity strings instead. So the gap is different from what was filed, and this implements what the code actually reaches for.java.net
InetAddress/getLocalHost,getAllByName(an array, soalength/agethold),.getCanonicalHostName,.getAddress,.isLoopbackAddress,.equals/.hashCode; and a newjava.net.NetworkInterface—getNetworkInterfaces,getByName,getByInetAddress,.getInetAddresses,.getHardwareAddress,.getDisplayName,.isLoopback— overgetifaddrs(3),gethostname(2)andgetnameinfo(3). IPv4, matching the rest ofjolt.socket.getifaddrsreports one entry per address, so an interface with an address and a MAC appears twice; the entries are grouped by name into one interface each, which is the shapejava.netpresents. An address read off an interface carries no hostname — the JVM prints it/127.0.0.1— and.getHostNameresolves once and caches, rather than putting a DNS round trip per address in the way of enumerating interfaces.Touching any
java.netclass now loadsjolt.socketon demand, the courtesyjava.timeandMessageDigestalready had. A JVM library reaching forInetAddressshould no more have to know which namespace installs it than it does on the JVM..getHardwareAddressandgetByInetAddressare here even though clj-uuid doesn't use them: they're the documentedjava.netsurface, and thegetifaddrswalk that answers the rest already has the data.java.util.Properties
Found along the way, and needed for the same caller:
System/getPropertiesreturned a plain map, so.getPropertyread as a key lookup and answerednilfor every system property. There's now a realPropertieswith the JVM'sdefaultschain — and its exact span:getProperty,propertyNamesandstringPropertyNamessee the defaults; the inheritedHashtablesurface (get,containsKey,keySet,values,size) does not. APropertiesholding only defaults answersisEmptytrue with an emptykeySetwhilepropertyNameslists them.System/getPropertiesholds its values as real entries, as on the JVM, rebuilt per call souser.dirandjava.class.pathstay current instead of freezing at the first call, and writes through to the storeSystem/getPropertyreads.While in there, the three spellings of "is this a hashmap-backed host object" were one predicate's worth of drift; they are one now, so a shim of that shape cannot be countable through one accessor and opaque through another.
Validation
make testgreen: exit 0, 82 CI targets, 0 new divergences, 0 failuresjolt.socketgate (make smokegreps its marker), each expectation certified against JVM Clojure 1.12.5 first — including the defaults-span split and the lazy-resolve-and-cache behaviourjava.netwith no require)InetAddress/getLocalHostrenders byte-identically to the JVM on this machineall-local-addresses+make-node-idrun end to end and are stable across calls; theconfiglibrary's(->> (System/getProperties) (map (fn [[k v]] …)))still resolveshost-interop.md) — the "gated behind(require 'jolt.socket)" note is no longer true