Add shortcut to SymbolLookup::find

XMLWordPrintable

    • Type: CSR
    • Resolution: Approved
    • Priority: P3
    • 23
    • Component/s: core-libs
    • None
    • source
    • minimal
    • Hide
      As the interface `SymbolLookup` is not sealed, anyone can create a custom implementation of it. Hence, it is possible, that some of these potential custom implementations already have a method `findOrThrow` defined.

      The new method is discoverable via reflection.
      Show
      As the interface `SymbolLookup` is not sealed, anyone can create a custom implementation of it. Hence, it is possible, that some of these potential custom implementations already have a method `findOrThrow` defined. The new method is discoverable via reflection.
    • Java API
    • SE

      Summary

      Add a default method SymbolLookup.findOrThrow(String name) that will throw an exception with a useful message if a symbol is not found.

      Problem

      It is a common pattern to call symbolLookup.find(name).orElseThrow() or symbolLookup.find(name).get() in order to obtain a symbol. In the case that a symbol cannot be found, the exception thrown above does not provide the given name in its description. Using symbolLookup.find(name).orElseThrow(() -> ... name ...) would incur a capturing lambda being created.

      Solution

      Add a method that will provide a relevant exception message, should a symbol not be found. The method does not incur lambda capturing internally.

      Specification

      <pre><code> diff --git a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java index 9bfc7964322e1..3bc416b9c6272 100644 --- a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java +++ b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java @@ -39,6 +39,7 @@ import java.lang.invoke.MethodHandles; import java.nio.file.FileSystems; import java.nio.file.Path; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; @@ -79,7 +80,7 @@ * {@snippet lang = java: * try (Arena arena = Arena.ofConfined()) { * SymbolLookup libGL = SymbolLookup.libraryLookup("libGL.so", arena); // libGL.so loaded here - * MemorySegment glGetString = libGL.find("glGetString").orElseThrow(); + * MemorySegment glGetString = libGL.findOrThrow("glGetString"); * ... * } // libGL.so unloaded here *} @@ -93,7 +94,7 @@ * System.loadLibrary("GL"); // libGL.so loaded here * ... * SymbolLookup libGL = SymbolLookup.loaderLookup(); - * MemorySegment glGetString = libGL.find("glGetString").orElseThrow(); + * MemorySegment glGetString = libGL.findOrThrow("glGetString"); * } * * This symbol lookup, which is known as a <em>loader lookup</em>, is dynamic with @@ -130,7 +131,7 @@ * {@snippet lang = java: * Linker nativeLinker = Linker.nativeLinker(); * SymbolLookup stdlib = nativeLinker.defaultLookup(); - * MemorySegment malloc = stdlib.find("malloc").orElseThrow(); + * MemorySegment malloc = stdlib.findOrThrow("malloc"); *} * * @since 22 @@ -144,9 +145,40 @@ public interface SymbolLookup { * @param name the symbol name * @return a zero-length memory segment whose address indicates the address of * the symbol, if found + * @see #findOrThrow(String) */ Optional<MemorySegment> find(String name); + /** + * Returns the address of the symbol with the given name or throws an exception. + *<p> + * This is equivalent to the following code, but is more efficient: + * to: + * {@snippet lang= java : + * String name = ... + * MemorySegment address = lookup.find(name) + * .orElseThrow(() -> new NoSuchElementException("Symbol not found: " + name)); + * } + * + * @param name the symbol name + * @return a zero-length memory segment whose address indicates the address of + * the symbol + * @throws NoSuchElementException if no symbol address can be found for the + * given name + * @see #find(String) + * + * @since 23 + */ + default MemorySegment findOrThrow(String name) { + Objects.requireNonNull(name); + Optional<MemorySegment> address = find(name); + // Avoid lambda capturing + if (address.isPresent()) { + return address.get(); + } + throw new NoSuchElementException("Symbol not found: " + name); + } + /** * {@return a composed symbol lookup that returns the result of finding the symbol * with this lookup if found, otherwise returns the result of finding diff --git a/src/java.base/share/classes/java/lang/foreign/package-info.java b/src/java.base/share/classes/java/lang/foreign/package-info.java index b2a6a5f447440..6594826e40524 100644 --- a/src/java.base/share/classes/java/lang/foreign/package-info.java +++ b/src/java.base/share/classes/java/lang/foreign/package-info.java @@ -100,7 +100,7 @@ * Linker linker = Linker.nativeLinker(); * SymbolLookup stdlib = linker.defaultLookup(); * MethodHandle strlen = linker.downcallHandle( - * stdlib.find("strlen").orElseThrow(), + * stdlib.findOrThrow("strlen"), * FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS) * ); * @@ -111,7 +111,7 @@ *} * * Here, we obtain a {@linkplain java.lang.foreign.Linker#nativeLinker() native linker} - * and we use it to {@linkplain java.lang.foreign.SymbolLookup#find(java.lang.String) look up} + * and we use it to {@linkplain java.lang.foreign.SymbolLookup#findOrThrow(java.lang.String) look up} * the {@code strlen} function in the standard C library; a <em>downcall method handle</em> * targeting said function is subsequently * {@linkplain java.lang.foreign.Linker#downcallHandle(FunctionDescriptor, Linker.Option...) obtained}. </code></pre>

            Assignee:
            Per-Ake Minborg
            Reporter:
            Maurizio Cimadamore
            Jorn Vernee
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: