Getting a usable, non-localhost IP address for a JVM

I recently had a task where I needed to inform a docker image of the host OS’ IP address. (The docker image needed to make an HTTP call to the host machine, for testing purposes.) However, it’s not trivial to find code to actually get a host machine’s IP address. Here’s some code in Kotlin (and in Java) to accomplish the task; I can’t say it’s perfect (and won’t) but it worked for me, and hopefully this can serve as a tentpole for perhaps better code.
There are two pieces of code here; both eliminate the 10.*.*.* network. If you don’t need that network to be eliminated, well, remove that line.

Kotlin

import java.net.NetworkInterface
fun getAddress(): String {
    return NetworkInterface.getNetworkInterfaces().toList().flatMap {
        it.inetAddresses.toList()
                .filter { it.address.size == 4 }
                .filter { !it.isLoopbackAddress }
                .filter { it.address[0] != 10.toByte() }
                .map { it.hostAddress }
    }.first()
}

Java

The Java code’s a lot more convoluted, and isn’t helped at all by the requirement for a means by which to convert an Enumeration to a Stream (copied shamelessly from “Iterate an Enumeration in Java 8“, by the way.) However, it’s functionally equivalent to the Kotlin code. If it can’t find a valid address or an internal exception is thrown, a RuntimeException is created and thrown.

private static  Stream enumerationAsStream(Enumeration e) {
    return StreamSupport.stream(
            Spliterators.spliteratorUnknownSize(
                    new Iterator() {
                        public T next() {
                            return e.nextElement();
                        }
                        public boolean hasNext() {
                            return e.hasMoreElements();
                        }
                    },
                    Spliterator.ORDERED), false);
}
public static String getAddress() {
    try {
        Optional address = enumerationAsStream(NetworkInterface.getNetworkInterfaces())
                .flatMap(networkInterface ->
                        networkInterface.getInterfaceAddresses().stream()
                )
                .filter(ia -> !ia.getAddress().isLoopbackAddress())
                .map(InterfaceAddress::getAddress)
                .filter(a -> a.getAddress().length == 4)
                .filter(a -> a.getAddress()[0] != 10)
                .findFirst();
        if (address.isPresent()) {
            return address.get().getHostAddress();
        } else {
            throw new RuntimeException("Address not accessible");
        }
    } catch (SocketException e) {
        throw new RuntimeException(e);
    }
}

Summary

This is not perfect code, I wouldn’t think. It was thrown together to fit a specific need, and ideally should have been easily located on StackOverflow or something like that.

Leave a Reply