Package limn.io

Class Resources

java.lang.Object
limn.io.Resources

public final class Resources extends Object
Reads a classpath resource or a file whole, and says what was being read when it cannot.

Every loader in the toolkit opens a resource the same way: ask the class loader, throw if it answers nothing, read all the bytes, wrap the IOException. The nine copies of that block differed only in the noun in the message — image, audio, glTF, shader, font — and in how many of the four steps each remembered. This is the block once, with the noun as a parameter, so a failure still says "reading font /limn/fonts/x.ttf" and never "reading resource".

Two lookups, because the callers use two. bytes(Class, String, String) resolves the name the way Class.getResourceAsStream(java.lang.String) does: an absolute name with a leading slash, or one relative to the class's package. bytes(ClassLoader, String, String) resolves it the way ClassLoader.getResourceAsStream(java.lang.String) does: always from the root, never with a leading slash. A caller keeps whichever it had; the two are not interchangeable.

On the module path, a class in a named module finds only its own module's resources, so the class form asks the class's module first and then its class loader, which is where the class path's answer comes from. What the loader cannot see is a resource inside a named module's package that the module does not open: an application that is a named module keeps what the toolkit loads by name in a package it opens, in a directory whose name is not a package name (static-assets/, app-images/), or opens the stream itself, in its own code, and hands it to bytes(InputStream, String, String), which is what the toolkit's own modules do with theirs.

A resource that is absent is an IllegalStateException (the jar was built without it, which is a fact about the build and not a fault of the caller); a read that fails is an UncheckedIOException. The IfPresent forms answer null for the first case, for the loaders whose resource is optional — a heavy fallback font, a translation a domain does not carry.

  • Method Details

    • bytes

      public static byte[] bytes(Class<?> owner, String resource, String what)
      The whole of a classpath resource, resolved relative to owner.
      Parameters:
      owner - the class whose loader, and whose package for a relative name, resolve it
      resource - the resource name
      what - the noun for the message: "image", "shader", "font"
      Returns:
      the bytes, never null
      Throws:
      IllegalStateException - if there is no such resource
      UncheckedIOException - if reading it fails
    • bytes

      public static byte[] bytes(ClassLoader loader, String resource, String what)
      The whole of a classpath resource, resolved from the root by loader.
      Parameters:
      loader - the loader to ask
      resource - the resource name, with no leading slash
      what - the noun for the message
      Returns:
      the bytes, never null
      Throws:
      IllegalStateException - if there is no such resource
      UncheckedIOException - if reading it fails
    • bytesIfPresent

      public static byte @Nullable [] bytesIfPresent(Class<?> owner, String resource, String what)
      bytes(Class, String, String), or null when there is no such resource.
      Parameters:
      owner - the class whose loader, and whose package for a relative name, resolve it
      resource - the resource name
      what - the noun for the message
      Returns:
      the bytes, or null if the resource is absent
      Throws:
      UncheckedIOException - if reading it fails
    • bytesIfPresent

      public static byte @Nullable [] bytesIfPresent(ClassLoader loader, String resource, String what)
      bytes(ClassLoader, String, String), or null when there is no such resource.
      Parameters:
      loader - the loader to ask
      resource - the resource name, with no leading slash
      what - the noun for the message
      Returns:
      the bytes, or null if the resource is absent
      Throws:
      UncheckedIOException - if reading it fails
    • text

      public static String text(Class<?> owner, String resource, String what)
      The whole of a classpath resource as UTF-8 text, resolved relative to owner.
      Parameters:
      owner - the class whose loader, and whose package for a relative name, resolve it
      resource - the resource name
      what - the noun for the message
      Returns:
      the text, never null
      Throws:
      IllegalStateException - if there is no such resource
      UncheckedIOException - if reading it fails
    • textIfPresent

      public static @Nullable String textIfPresent(Class<?> owner, String resource, String what)
      text(Class, String, String), or null when there is no such resource.
      Parameters:
      owner - the class whose loader, and whose package for a relative name, resolve it
      resource - the resource name
      what - the noun for the message
      Returns:
      the text, or null if the resource is absent
      Throws:
      UncheckedIOException - if reading it fails
    • textIfPresent

      public static @Nullable String textIfPresent(ClassLoader loader, String resource, String what)
      text(Class, String, String) resolved from the root by loader, or null when there is no such resource.
      Parameters:
      loader - the loader to ask
      resource - the resource name, with no leading slash
      what - the noun for the message
      Returns:
      the text, or null if the resource is absent
      Throws:
      UncheckedIOException - if reading it fails
    • bytes

      public static byte[] bytes(@Nullable InputStream opened, String resource, String what)
      The whole of a resource the caller opened, and closes it.

      For a named module's own resource in a package it does not open, which only that module's code can open: Resources.bytes(Icons.class.getResourceAsStream(name), name, "icon").

      Parameters:
      opened - the open stream, or null when the lookup found nothing
      resource - the resource name, for the message
      what - the noun for the message
      Returns:
      the bytes, never null
      Throws:
      IllegalStateException - if opened is null
      UncheckedIOException - if reading it fails
    • bytesIfPresent

      public static byte @Nullable [] bytesIfPresent(@Nullable InputStream opened, String resource, String what)
      bytes(InputStream, String, String), or null when opened is null.
      Parameters:
      opened - the open stream, or null when the lookup found nothing
      resource - the resource name, for the message
      what - the noun for the message
      Returns:
      the bytes, or null if there was nothing to read
      Throws:
      UncheckedIOException - if reading it fails
    • text

      public static String text(@Nullable InputStream opened, String resource, String what)
      Parameters:
      opened - the open stream, or null when the lookup found nothing
      resource - the resource name, for the message
      what - the noun for the message
      Returns:
      the text, never null
      Throws:
      IllegalStateException - if opened is null
      UncheckedIOException - if reading it fails
    • bytes

      public static byte[] bytes(Path file, String what)
      The whole of a file.
      Parameters:
      file - the file
      what - the noun for the message: "image", "font", "Ogg stream"
      Returns:
      the bytes, never null
      Throws:
      UncheckedIOException - if reading it fails, the file being absent included