From ee0459f101bc0658444cd15423b4489f7c4d2b99 Mon Sep 17 00:00:00 2001 From: squid233 <60126026+squid233@users.noreply.github.com> Date: Sun, 17 Sep 2023 11:33:42 +0800 Subject: [PATCH] Uses string templates --- .../java/overrungl/FunctionDescriptors.java | 7 ++- .../java/overrungl/internal/Exceptions.java | 37 ++++++++++++++++ .../overrungl/internal/RuntimeHelper.java | 10 ++--- .../main/java/overrungl/os/Architecture.java | 8 +++- .../src/main/java/overrungl/os/Platform.java | 23 ++++++++-- .../main/java/overrungl/util/CheckUtil.java | 2 +- .../java/overrungl/util/DebugAllocator.java | 43 +++++++------------ .../src/main/java/overrungl/glfw/GLFW.java | 2 + .../overrungl/glfw/GLFWErrorCallback.java | 13 ++---- .../src/main/java/overrungl/nfd/NFD.java | 4 +- .../java/overrungl/nfd/NFDEnumerator.java | 2 +- .../main/java/overrungl/opengl/GLUtil.java | 24 +++-------- .../test/java/overrungl/demo/nfd/NFDTest.java | 20 ++++----- 13 files changed, 113 insertions(+), 82 deletions(-) create mode 100644 modules/overrungl.core/src/main/java/overrungl/internal/Exceptions.java diff --git a/modules/overrungl.core/src/main/java/overrungl/FunctionDescriptors.java b/modules/overrungl.core/src/main/java/overrungl/FunctionDescriptors.java index 77b8d514..8a8ba594 100644 --- a/modules/overrungl.core/src/main/java/overrungl/FunctionDescriptors.java +++ b/modules/overrungl.core/src/main/java/overrungl/FunctionDescriptors.java @@ -16,6 +16,7 @@ package overrungl; +import overrungl.internal.Exceptions; import overrungl.util.MemoryUtil; import java.lang.foreign.FunctionDescriptor; @@ -38,7 +39,7 @@ * case 'D' -> JAVA_DOUBLE; * case 'P' -> ADDRESS; * case 'p' -> MemoryUtil.ADDRESS_UNBOUNDED; - * default -> throw new IllegalStateException(); + * default -> throw new IllegalArgumentException(); * }} * * @author squid233 @@ -124,9 +125,7 @@ public static ValueLayout ofValue(char c) throws IllegalArgumentException { case 'P' -> ADDRESS; case 'p' -> MemoryUtil.ADDRESS_UNBOUNDED; default -> - throw new IllegalArgumentException( - STR."Invalid argument c: expected one of B, S, I, J, C, Z, F, D, P or p; got '\{c}'" - ); + throw Exceptions.IAE. "Invalid argument c: expected one of B, S, I, J, C, Z, F, D, P or p; got '\{ c }'" ; }; } diff --git a/modules/overrungl.core/src/main/java/overrungl/internal/Exceptions.java b/modules/overrungl.core/src/main/java/overrungl/internal/Exceptions.java new file mode 100644 index 00000000..54e12662 --- /dev/null +++ b/modules/overrungl.core/src/main/java/overrungl/internal/Exceptions.java @@ -0,0 +1,37 @@ +/* + * MIT License + * + * Copyright (c) 2023 Overrun Organization + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + */ + +package overrungl.internal; + +/** + * Quick create exceptions + * + * @author squid233 + * @since 0.1.0 + */ +public final class Exceptions { + /** + * {@link IllegalStateException} + */ + public static final StringTemplate.Processor ISE = stringTemplate -> + new IllegalStateException(stringTemplate.interpolate()); + + /** + * {@link IllegalArgumentException} + */ + public static final StringTemplate.Processor IAE = stringTemplate -> + new IllegalArgumentException(stringTemplate.interpolate()); +} diff --git a/modules/overrungl.core/src/main/java/overrungl/internal/RuntimeHelper.java b/modules/overrungl.core/src/main/java/overrungl/internal/RuntimeHelper.java index 570bcf6d..00c87c5f 100644 --- a/modules/overrungl.core/src/main/java/overrungl/internal/RuntimeHelper.java +++ b/modules/overrungl.core/src/main/java/overrungl/internal/RuntimeHelper.java @@ -137,7 +137,7 @@ public static String unknownToken(int token) { * @return the string is formatted in {@code STR."\{description} [0x\{toHexString(token)}]"}. */ public static String unknownToken(String description, int token) { - return description + "[0x" + Integer.toHexString(token) + "]"; + return STR. "\{ description } [0x\{ Integer.toHexString(token) }]" ; } /** @@ -161,7 +161,7 @@ public static SymbolLookup load(String module, String basename, String version) uri = localFile.toURI(); } else { // 2. Load from classpath - var file = new File(tmpdir, "overrungl" + System.getProperty("user.name")); + var file = new File(tmpdir, STR. "overrungl\{ System.getProperty("user.name") }" ); if (!file.exists()) { // Create directory file.mkdir(); @@ -171,15 +171,15 @@ public static SymbolLookup load(String module, String basename, String version) // Create directory file.mkdir(); } - var libFile = new File(file, basename + "-" + version + suffix); + var libFile = new File(file, STR. "\{ basename }-\{ version }\{ suffix }" ); if (!libFile.exists()) { // Extract try (var is = STACK_WALKER.getCallerClass().getClassLoader().getResourceAsStream( - module + "/" + os.familyName() + "/" + Architecture.current() + "/" + path + STR. "\{ module }/\{ os.familyName() }/\{ Architecture.current() }/\{ path }" )) { Files.copy(Objects.requireNonNull(is), Path.of(libFile.getAbsolutePath())); } catch (Exception e) { - var exception = new IllegalStateException("File not found: " + file + "; try setting property -Doverrungl.natives to a valid path"); + var exception = new IllegalStateException(STR. "File not found: \{ file }; try setting property -Doverrungl.natives to a valid path" ); exception.addSuppressed(e); throw exception; } diff --git a/modules/overrungl.core/src/main/java/overrungl/os/Architecture.java b/modules/overrungl.core/src/main/java/overrungl/os/Architecture.java index 3239f4fd..a29af38a 100644 --- a/modules/overrungl.core/src/main/java/overrungl/os/Architecture.java +++ b/modules/overrungl.core/src/main/java/overrungl/os/Architecture.java @@ -16,6 +16,8 @@ package overrungl.os; +import overrungl.internal.Exceptions; + import java.util.Locale; /** @@ -29,6 +31,8 @@ public enum Architecture { ARM64, ARM32; + private final String toStringValue = name().toLowerCase(Locale.ROOT); + /** * {@return the current architecture of the current {@linkplain Platform platform}} */ @@ -45,7 +49,7 @@ class Holder { X64; case Platform.MacOSX _ -> arch.startsWith("aarch64") ? ARM64 : X64; case Platform.Windows _ when arch.contains("64") -> arch.startsWith("aarch64") ? ARM64 : X64; - default -> throw new IllegalStateException("Unrecognized or unsupported architecture: " + arch); + default -> throw Exceptions.ISE. "Unrecognized or unsupported architecture: \{ arch }" ; }; } } @@ -54,6 +58,6 @@ class Holder { @Override public String toString() { - return name().toLowerCase(Locale.ROOT); + return toStringValue; } } diff --git a/modules/overrungl.core/src/main/java/overrungl/os/Platform.java b/modules/overrungl.core/src/main/java/overrungl/os/Platform.java index d833d158..72183c55 100644 --- a/modules/overrungl.core/src/main/java/overrungl/os/Platform.java +++ b/modules/overrungl.core/src/main/java/overrungl/os/Platform.java @@ -16,6 +16,8 @@ package overrungl.os; +import overrungl.internal.Exceptions; + /** * The native platform, identifying the operating system and the architecture. * @@ -38,7 +40,7 @@ else if (os.startsWith("Mac OS X") || os.startsWith("Darwin")) CURRENT = MacOSX.INSTANCE; else if (os.startsWith("Windows")) CURRENT = Windows.INSTANCE; - else throw new IllegalStateException("Unrecognized or unsupported platform: " + os); + else throw Exceptions.ISE. "Unrecognized or unsupported platform: \{ os }" ; } } return Holder.CURRENT; @@ -85,6 +87,11 @@ public String sharedLibrarySuffix() { public String sharedLibraryName(String libraryName) { return Platform.unixSharedLibraryName(libraryName, sharedLibrarySuffix()); } + + @Override + public String toString() { + return familyName(); + } } /** @@ -110,6 +117,11 @@ public String sharedLibrarySuffix() { public String sharedLibraryName(String libraryName) { return Platform.unixSharedLibraryName(libraryName, sharedLibrarySuffix()); } + + @Override + public String toString() { + return familyName(); + } } /** @@ -135,6 +147,11 @@ public String sharedLibrarySuffix() { public String sharedLibraryName(String libraryName) { return Platform.withExtension(libraryName, sharedLibrarySuffix()); } + + @Override + public String toString() { + return familyName(); + } } private static String unixSharedLibraryName(String libraryName, String suffix) { @@ -143,9 +160,9 @@ private static String unixSharedLibraryName(String libraryName, String suffix) { } int pos = libraryName.lastIndexOf('/'); if (pos >= 0) { - return libraryName.substring(0, pos + 1) + "lib" + libraryName.substring(pos + 1) + suffix; + return STR. "\{ libraryName.substring(0, pos + 1) }lib\{ libraryName.substring(pos + 1) }\{ suffix }" ; } - return "lib" + libraryName + suffix; + return STR. "lib\{ libraryName }\{ suffix }" ; } /** diff --git a/modules/overrungl.core/src/main/java/overrungl/util/CheckUtil.java b/modules/overrungl.core/src/main/java/overrungl/util/CheckUtil.java index 058d20c3..41743db4 100644 --- a/modules/overrungl.core/src/main/java/overrungl/util/CheckUtil.java +++ b/modules/overrungl.core/src/main/java/overrungl/util/CheckUtil.java @@ -78,7 +78,7 @@ public static void check(boolean condition, String message) throws IllegalStateE * @see #checkNotNullptr(MemorySegment, String) */ public static void checkNotNullptr(MemorySegment segment) throws IllegalStateException { - checkNotNullptr(segment, "condition == false"); + checkNotNullptr(segment, "segment is NULL"); } /** diff --git a/modules/overrungl.core/src/main/java/overrungl/util/DebugAllocator.java b/modules/overrungl.core/src/main/java/overrungl/util/DebugAllocator.java index c7de2ad2..28d6309d 100644 --- a/modules/overrungl.core/src/main/java/overrungl/util/DebugAllocator.java +++ b/modules/overrungl.core/src/main/java/overrungl/util/DebugAllocator.java @@ -20,6 +20,7 @@ import org.jetbrains.annotations.Nullable; import overrungl.Configurations; import overrungl.OverrunGL; +import overrungl.internal.Exceptions; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -44,22 +45,16 @@ final class DebugAllocator { for (Allocation allocation : ALLOCATIONS.keySet()) { StringBuilder sb = new StringBuilder(512); - sb.append("[OverrunGL] ") - .append(allocation.size) - .append(" bytes leaked, thread ") - .append(allocation.threadId) - .append(" (") - .append(THREADS.get(allocation.threadId)) - .append("), address: 0x") - .append(Long.toHexString(allocation.address).toUpperCase()) - .append("\n"); + sb.append(STR. """ + [OverrunGL] \{ allocation.size } bytes leaked,\ + thread \{ allocation.threadId } (\{ THREADS.get(allocation.threadId) }),\ + address: 0x\{ Long.toHexString(allocation.address).toUpperCase() } + """ ); StackTraceElement[] stackTrace = allocation.getElements(); if (stackTrace != null) { for (Object el : stackTrace) { - sb.append("\tat ") - .append(el.toString()) - .append("\n"); + sb.append(STR. "\tat \{ el.toString() }\n" ); } } else { missingStacktrace = true; @@ -104,30 +99,22 @@ private static void trackAbort(long address, Allocation allocationOld, Allocatio trackAbortPrint(allocationOld, "Old", addressHex); trackAbortPrint(allocationNew, "New", addressHex); - throw new IllegalStateException(STR."The memory address specified is already being tracked: 0x\{addressHex}"); + throw Exceptions.ISE. "The memory address specified is already being tracked: 0x\{ addressHex }" ; } private static void trackAbortPrint(Allocation allocation, String name, String address) { StringBuilder sb = new StringBuilder(512); - sb.append("[OverrunGL] ") - .append(name) - .append(" allocation with size ") - .append(allocation.size) - .append(", thread ") - .append(allocation.threadId) - .append(" (") - .append(THREADS.get(allocation.threadId)) - .append("), address: 0x") - .append(address) - .append("\n"); + sb.append(STR. """ + [OverrunGL] \{ name } allocation with size \{ allocation.size },\ + thread \{ allocation.threadId } (\{ THREADS.get(allocation.threadId) }),\ + address: 0x\{ address } + """ ); StackTraceElement[] stackTrace = allocation.getElements(); if (stackTrace != null) { for (Object el : stackTrace) { - sb.append("\tat ") - .append(el.toString()) - .append("\n"); + sb.append(STR. "\tat \{ el.toString() }\n" ); } } @@ -151,7 +138,7 @@ static long untrack(long address) { private static void untrackAbort(long address) { String addressHex = Long.toHexString(address).toUpperCase(); - throw new IllegalStateException(STR."The memory address specified is not being tracked: 0x\{addressHex}"); + throw Exceptions.ISE. "The memory address specified is not being tracked: 0x\{ addressHex }" ; } private record Allocation(long address, long size, long threadId, @Nullable Object[] stacktrace) { diff --git a/modules/overrungl.glfw/src/main/java/overrungl/glfw/GLFW.java b/modules/overrungl.glfw/src/main/java/overrungl/glfw/GLFW.java index bfc4465a..7fe07306 100644 --- a/modules/overrungl.glfw/src/main/java/overrungl/glfw/GLFW.java +++ b/modules/overrungl.glfw/src/main/java/overrungl/glfw/GLFW.java @@ -855,6 +855,8 @@ private GLFW() { /** * Converts the given error code to a readable string. + *

+ * This method is created by OverrunGL and does not belong to the original GLFW library. * * @param errorCode the error code. * @return the error string. diff --git a/modules/overrungl.glfw/src/main/java/overrungl/glfw/GLFWErrorCallback.java b/modules/overrungl.glfw/src/main/java/overrungl/glfw/GLFWErrorCallback.java index 5531ac1f..a96b6c37 100644 --- a/modules/overrungl.glfw/src/main/java/overrungl/glfw/GLFWErrorCallback.java +++ b/modules/overrungl.glfw/src/main/java/overrungl/glfw/GLFWErrorCallback.java @@ -17,6 +17,7 @@ package overrungl.glfw; import overrungl.OverrunGL; +import overrungl.internal.Exceptions; import java.io.PrintStream; import java.util.function.Consumer; @@ -37,7 +38,7 @@ private GLFWErrorCallback() { */ public static IGLFWErrorFun createThrow() { return (errorCode, description) -> { - throw new IllegalStateException(String.format("GLFW error [0x%X]: %s", errorCode, description)); + throw Exceptions.ISE. "GLFW error [0x\{ Integer.toHexString(errorCode) }]: \{ description }" ; }; } @@ -49,16 +50,10 @@ public static IGLFWErrorFun createThrow() { public static IGLFWErrorFun createLog(Consumer logger) { return (errorCode, description) -> { var sb = new StringBuilder(512); - sb.append("[OverrunGL] GLFW ") - .append(GLFW.getErrorString(errorCode)) - .append(" error: ") - .append(description) - .append("\n"); + sb.append(STR. "[OverrunGL] GLFW \{ GLFW.getErrorString(errorCode) } error: \{ description }\n" ); var stack = Thread.currentThread().getStackTrace(); for (int i = 3; i < stack.length; i++) { - sb.append(" at ") - .append(stack[i]) - .append("\n"); + sb.append(STR. " at \{ stack[i] }\n" ); } logger.accept(sb.toString()); }; diff --git a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFD.java b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFD.java index d69db9f7..9ee4deef 100644 --- a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFD.java +++ b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFD.java @@ -64,8 +64,8 @@ * new Pair<>("Image file", "png,jpg")); * var result = NFD.openDialogN(outPath, filterItem, null); * switch (result) { - * case ERROR -> System.err.println("Error: " + NFD.getError()); - * case OKAY -> System.out.println("Success! " + outPath[0]); + * case ERROR -> System.err.println(STR. "Error: \{ NFD.getError() }" ); + * case OKAY -> System.out.println(STR. "Success! \{ outPath[0] }" ); * case CANCEL -> System.out.println("User pressed cancel."); * } * } diff --git a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDEnumerator.java b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDEnumerator.java index a788e148..6a92ed55 100644 --- a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDEnumerator.java +++ b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDEnumerator.java @@ -148,7 +148,7 @@ public static Tuple2 fromPathSetU8(SegmentAllocator al } private static IllegalStateException errorIterating() { - return new IllegalStateException("Error iterating: " + NFD.getError()); + return new IllegalStateException(STR. "Error iterating: \{ NFD.getError() }" ); } @NotNull diff --git a/modules/overrungl.opengl/src/main/java/overrungl/opengl/GLUtil.java b/modules/overrungl.opengl/src/main/java/overrungl/opengl/GLUtil.java index d6424a57..ca34423a 100644 --- a/modules/overrungl.opengl/src/main/java/overrungl/opengl/GLUtil.java +++ b/modules/overrungl.opengl/src/main/java/overrungl/opengl/GLUtil.java @@ -78,16 +78,14 @@ public static Arena setupDebugMessageCallback(Consumer logger) { GL.debugMessageCallback(arena, (source, type, id, severity, message, userParam) -> { var sb = new StringBuilder(768); sb.append("[OverrunGL] OpenGL debug message\n"); - printDetail(sb, "ID", STR."0x\{Integer.toHexString(id).toUpperCase(Locale.ROOT)}"); + printDetail(sb, "ID", STR. "0x\{ Integer.toHexString(id).toUpperCase(Locale.ROOT) }" ); printDetail(sb, "Source", getDebugSource(source)); printDetail(sb, "Type", getDebugType(type)); printDetail(sb, "Severity", getDebugSeverity(severity)); printDetail(sb, "Message", message); var stack = Thread.currentThread().getStackTrace(); for (int i = 3; i < stack.length; i++) { - sb.append(" at ") - .append(stack[i]) - .append("\n"); + sb.append(STR. " at \{ stack[i] }\n" ); } logger.accept(sb.toString()); }, MemorySegment.NULL); @@ -106,16 +104,14 @@ public static Arena setupDebugMessageCallback(Consumer logger) { glDebugMessageCallbackARB(arena, (source, type, id, severity, message, userParam) -> { var sb = new StringBuilder(768); sb.append("[OverrunGL] ARB_debug_output message\n"); - printDetail(sb, "ID", STR."0x\{Integer.toHexString(id).toUpperCase(Locale.ROOT)}"); + printDetail(sb, "ID", STR. "0x\{ Integer.toHexString(id).toUpperCase(Locale.ROOT) }" ); printDetail(sb, "Source", getSourceARB(source)); printDetail(sb, "Type", getTypeARB(type)); printDetail(sb, "Severity", getSeverityARB(severity)); printDetail(sb, "Message", message); var stack = Thread.currentThread().getStackTrace(); for (int i = 3; i < stack.length; i++) { - sb.append(" at ") - .append(stack[i]) - .append("\n"); + sb.append(STR. " at \{ stack[i] }\n" ); } logger.accept(sb.toString()); }, MemorySegment.NULL); @@ -128,15 +124,13 @@ public static Arena setupDebugMessageCallback(Consumer logger) { glDebugMessageCallbackAMD(arena, (id, category, severity, message, userParam) -> { var sb = new StringBuilder(768); sb.append("[OverrunGL] AMD_debug_output message\n"); - printDetail(sb, "ID", STR."0x\{Integer.toHexString(id).toUpperCase(Locale.ROOT)}"); + printDetail(sb, "ID", STR. "0x\{ Integer.toHexString(id).toUpperCase(Locale.ROOT) }" ); printDetail(sb, "Category", getCategoryAMD(category)); printDetail(sb, "Severity", getSeverityAMD(severity)); printDetail(sb, "Message", message); var stack = Thread.currentThread().getStackTrace(); for (int i = 3; i < stack.length; i++) { - sb.append(" at ") - .append(stack[i]) - .append("\n"); + sb.append(STR. " at \{ stack[i] }\n" ); } logger.accept(sb.toString()); }, MemorySegment.NULL); @@ -148,11 +142,7 @@ public static Arena setupDebugMessageCallback(Consumer logger) { } private static void printDetail(StringBuilder sb, String type, String message) { - sb.append(" ") - .append(type) - .append(": ") - .append(message) - .append("\n"); + sb.append(STR. " \{ type }: \{ message }\n" ); } private static String getDebugSource(int source) { diff --git a/modules/samples/src/test/java/overrungl/demo/nfd/NFDTest.java b/modules/samples/src/test/java/overrungl/demo/nfd/NFDTest.java index 75be4ada..7374f897 100644 --- a/modules/samples/src/test/java/overrungl/demo/nfd/NFDTest.java +++ b/modules/samples/src/test/java/overrungl/demo/nfd/NFDTest.java @@ -50,8 +50,8 @@ private static void openDialog() { final NFDResult result = NFD.openDialogN(outPath, filterItem, null); switch (result) { - case ERROR -> System.err.println("Error: " + NFD.getError()); - case OKAY -> System.out.println("Success! " + outPath[0]); + case ERROR -> System.err.println(STR. "Error: \{ NFD.getError() }" ); + case OKAY -> System.out.println(STR. "Success! \{ outPath[0] }" ); case CANCEL -> System.out.println("User pressed cancel."); } } @@ -81,13 +81,13 @@ private static void openDialogMultiple() { MemorySegment outPaths = pOutPaths.get(ValueLayout.ADDRESS, 0); switch (result) { - case ERROR -> System.err.println("Error: " + NFD.getError()); + case ERROR -> System.err.println(STR. "Error: \{ NFD.getError() }" ); case OKAY -> { System.out.println("Success!"); for (long i = 0, numPaths = NFD.pathSetGetCount(outPaths).y(); i < numPaths; i++) { NFD.pathSetGetPathN(outPaths, i, outPath); - System.out.println("Path " + i + ": " + outPath[0]); + System.out.println(STR. "Path \{ i }: \{ outPath[0] }" ); } // remember to free the path-set memory (since NFDResult::OKAY is returned) @@ -121,14 +121,14 @@ private static void openDialogMultipleEnum() { MemorySegment outPaths = pOutPaths.get(ValueLayout.ADDRESS, 0); switch (result) { - case ERROR -> System.err.println("Error: " + NFD.getError()); + case ERROR -> System.err.println(STR. "Error: \{ NFD.getError() }" ); case OKAY -> { System.out.println("Success!"); try (NFDEnumerator enumerator = NFDEnumerator.fromPathSetN(stack, outPaths).y()) { int i = 0; for (String path : enumerator) { - System.out.println("Path " + i + ": " + path); + System.out.println(STR. "Path \{ i }: \{ path }" ); i++; } } @@ -157,8 +157,8 @@ private static void pickFolder() { // show the dialog final NFDResult result = NFD.pickFolderN(outPath, null); switch (result) { - case ERROR -> System.err.println("Error: " + NFD.getError()); - case OKAY -> System.out.println("Success! " + outPath[0]); + case ERROR -> System.err.println(STR. "Error: \{ NFD.getError() }" ); + case OKAY -> System.out.println(STR. "Success! \{ outPath[0] }" ); case CANCEL -> System.out.println("User pressed cancel."); } } @@ -185,8 +185,8 @@ private static void saveDialog() { // show the dialog final NFDResult result = NFD.saveDialogN(savePath, filterItem, null, "Untitled.java"); switch (result) { - case ERROR -> System.err.println("Error: " + NFD.getError()); - case OKAY -> System.out.println("Success! " + savePath[0]); + case ERROR -> System.err.println(STR. "Error: \{ NFD.getError() }" ); + case OKAY -> System.out.println(STR. "Success! \{ savePath[0] }" ); case CANCEL -> System.out.println("User pressed cancel."); } }