From a5408f5fc653a801c5980bf138cd71b6985938a8 Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 10 Aug 2025 14:47:17 +0200 Subject: [PATCH 1/6] extract compiler module --- .../common/classpath/ClassPathScanner.java | 2 + .../classpath/impl/ClassPathScannerImpl.java | 5 +- .../rlib/common/compiler/ByteCode.java | 18 -- .../rlib/common/compiler/Compiler.java | 63 ---- .../rlib/common/compiler/CompilerFactory.java | 35 --- .../common/compiler/impl/CompileByteCode.java | 36 --- .../compiler/impl/CompileJavaFileManager.java | 66 ---- .../common/compiler/impl/CompileListener.java | 49 --- .../common/compiler/impl/CompilerImpl.java | 291 ------------------ .../javasabr/rlib/common/util/FileUtils.java | 80 +++-- .../common/util/array/ArrayComparator.java | 8 +- .../rlib/common/compiler/CompilerTests.java | 36 --- rlib-compiler/build.gradle | 5 + .../java/javasabr/rlib/compiler/ByteCode.java | 11 + .../java/javasabr/rlib/compiler/Compiler.java | 18 ++ .../rlib/compiler/CompilerFactory.java | 24 ++ .../compiler/impl/CompileEventListener.java | 35 +++ .../rlib/compiler/impl/CompiledByteCode.java | 42 +++ .../impl/CompiledClassesClassLoader.java | 28 +- .../impl/CompiledJavaFileManager.java | 54 ++++ .../rlib}/compiler/impl/JavaFileSource.java | 21 +- .../rlib/compiler/impl/JdkCompiler.java | 139 +++++++++ .../rlib/compiler/impl}/package-info.java | 2 +- .../javasabr/rlib/compiler}/package-info.java | 2 +- .../javasabr/rlib/compiler/CompilerTests.java | 79 +++++ .../java/source/TestCompileDependency.java | 5 + .../java/source/TestCompileJavaSource.java | 0 .../java/source/TestCompileRecord.java | 1 + settings.gradle | 3 +- 29 files changed, 480 insertions(+), 678 deletions(-) delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/compiler/ByteCode.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/compiler/Compiler.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/compiler/CompilerFactory.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileByteCode.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileJavaFileManager.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileListener.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompilerImpl.java delete mode 100644 rlib-common/src/test/java/javasabr/rlib/common/compiler/CompilerTests.java create mode 100644 rlib-compiler/build.gradle create mode 100644 rlib-compiler/src/main/java/javasabr/rlib/compiler/ByteCode.java create mode 100644 rlib-compiler/src/main/java/javasabr/rlib/compiler/Compiler.java create mode 100644 rlib-compiler/src/main/java/javasabr/rlib/compiler/CompilerFactory.java create mode 100644 rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompileEventListener.java create mode 100644 rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledByteCode.java rename rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileClassLoader.java => rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledClassesClassLoader.java (50%) create mode 100644 rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledJavaFileManager.java rename {rlib-common/src/main/java/javasabr/rlib/common => rlib-compiler/src/main/java/javasabr/rlib}/compiler/impl/JavaFileSource.java (64%) create mode 100644 rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java rename {rlib-common/src/main/java/javasabr/rlib/common/compiler => rlib-compiler/src/main/java/javasabr/rlib/compiler/impl}/package-info.java (58%) rename {rlib-common/src/main/java/javasabr/rlib/common/compiler/impl => rlib-compiler/src/main/java/javasabr/rlib/compiler}/package-info.java (56%) create mode 100644 rlib-compiler/src/test/java/javasabr/rlib/compiler/CompilerTests.java create mode 100644 rlib-compiler/src/test/resources/java/source/TestCompileDependency.java rename {rlib-common => rlib-compiler}/src/test/resources/java/source/TestCompileJavaSource.java (100%) create mode 100644 rlib-compiler/src/test/resources/java/source/TestCompileRecord.java diff --git a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScanner.java b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScanner.java index 135b2e12..988a762f 100644 --- a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScanner.java +++ b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScanner.java @@ -14,6 +14,8 @@ public interface ClassPathScanner { String JAR_EXTENSION = ".jar"; + String SOURCE_EXTENSION = ".java"; + String CLASS_EXTENSION = ".class"; @Nullable ClassPathScanner NULL_SCANNER = null; diff --git a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ClassPathScannerImpl.java b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ClassPathScannerImpl.java index 7a0f8934..ac100cd0 100644 --- a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ClassPathScannerImpl.java +++ b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ClassPathScannerImpl.java @@ -15,7 +15,6 @@ import java.util.jar.JarInputStream; import java.util.zip.ZipException; import javasabr.rlib.common.classpath.ClassPathScanner; -import javasabr.rlib.common.compiler.Compiler; import javasabr.rlib.common.io.impl.ReuseBytesInputStream; import javasabr.rlib.common.io.impl.ReuseBytesOutputStream; import javasabr.rlib.common.util.ArrayUtils; @@ -246,7 +245,7 @@ private void scanDirectory( } loadClass(rootPath, file, path, classes); - } else if (!filename.endsWith(Compiler.SOURCE_EXTENSION)) { + } else if (!filename.endsWith(SOURCE_EXTENSION)) { String path = file .subpath(rootPath.getNameCount(), file.getNameCount()) @@ -310,7 +309,7 @@ private void scanJarInputStream( scanJar(classes, resources, rin); } else if (name.endsWith(CLASS_EXTENSION)) { loadClass(null, null, name, classes); - } else if (!name.endsWith(Compiler.SOURCE_EXTENSION)) { + } else if (!name.endsWith(SOURCE_EXTENSION)) { resources.add(name); } } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/compiler/ByteCode.java b/rlib-common/src/main/java/javasabr/rlib/common/compiler/ByteCode.java deleted file mode 100644 index 399b0bd8..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/compiler/ByteCode.java +++ /dev/null @@ -1,18 +0,0 @@ -package javasabr.rlib.common.compiler; - -import org.jspecify.annotations.NullMarked; - -/** - * The interface to implement byte code container. - * - * @author JavaSaBr - */ -public interface ByteCode { - - /** - * Get the byte code. - * - * @return the byte code. - */ - byte[] getByteCode(); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/compiler/Compiler.java b/rlib-common/src/main/java/javasabr/rlib/common/compiler/Compiler.java deleted file mode 100644 index 3f10b701..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/compiler/Compiler.java +++ /dev/null @@ -1,63 +0,0 @@ -package javasabr.rlib.common.compiler; - -import java.io.File; -import java.net.URI; -import java.nio.file.Path; - -/** - * The interface to implement a compiler. - * - * @author JavaSaBr - */ -public interface Compiler { - - /** - * The constant SOURCE_EXTENSION. - */ - String SOURCE_EXTENSION = ".java"; - - /** - * The constant CLASS_EXTENSION. - */ - String CLASS_EXTENSION = ".class"; - - /** - * Compile files. - * - * @param files the file list. - * @return the classes list. - */ - Class[] compile(File... files); - - /** - * Compile files. - * - * @param paths the file list. - * @return the classes list. - */ - Class[] compile(Path... paths); - - /** - * Compile resources. - * - * @param uris the resource list. - * @return the classes list. - */ - Class[] compile(URI... uris); - - /** - * Compile all classes from directories. - * - * @param files the directory list. - * @return the classes list. - */ - Class[] compileDirectory(File... files); - - /** - * Compile all classes from directories. - * - * @param paths the directory list. - * @return the classes list. - */ - Class[] compileDirectory(Path... paths); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/compiler/CompilerFactory.java b/rlib-common/src/main/java/javasabr/rlib/common/compiler/CompilerFactory.java deleted file mode 100644 index 794cacc4..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/compiler/CompilerFactory.java +++ /dev/null @@ -1,35 +0,0 @@ -package javasabr.rlib.common.compiler; - -import javasabr.rlib.common.compiler.impl.CompilerImpl; -import javax.tools.ToolProvider; -import org.jspecify.annotations.NullMarked; - -/** - * The factory of java compilers. - * - * @author JavaSaBr - */ -public class CompilerFactory { - - /** - * Check availability compiler API in current runtime. - * - * @return true if a compiler is available. - */ - public static boolean isAvailableCompiler() { - return ToolProvider.getSystemJavaCompiler() != null; - } - - /** - * Create a new default compiler. - * - * @return the new compiler. - */ - public static Compiler newDefaultCompiler() { - return new CompilerImpl(true); - } - - private CompilerFactory() { - throw new RuntimeException(); - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileByteCode.java b/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileByteCode.java deleted file mode 100644 index 5edbdf52..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileByteCode.java +++ /dev/null @@ -1,36 +0,0 @@ -package javasabr.rlib.common.compiler.impl; - -import java.io.ByteArrayOutputStream; -import java.io.OutputStream; -import java.net.URI; -import javasabr.rlib.common.compiler.ByteCode; -import javasabr.rlib.common.compiler.Compiler; -import javax.tools.SimpleJavaFileObject; - -/** - * The implementation of byte code container. - * - * @author JavaSaBr - */ -public class CompileByteCode extends SimpleJavaFileObject implements ByteCode { - - /** - * The stream with byte code. - */ - private final ByteArrayOutputStream outputStream; - - public CompileByteCode(final String name) { - super(URI.create("byte:///" + name.replace('/', '.') + Compiler.CLASS_EXTENSION), Kind.CLASS); - this.outputStream = new ByteArrayOutputStream(); - } - - @Override - public byte[] getByteCode() { - return outputStream.toByteArray(); - } - - @Override - public OutputStream openOutputStream() { - return outputStream; - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileJavaFileManager.java b/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileJavaFileManager.java deleted file mode 100644 index 6f9f4b0c..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileJavaFileManager.java +++ /dev/null @@ -1,66 +0,0 @@ -package javasabr.rlib.common.compiler.impl; - -import javasabr.rlib.common.util.array.Array; -import javasabr.rlib.common.util.array.ArrayFactory; -import javax.tools.FileObject; -import javax.tools.ForwardingJavaFileManager; -import javax.tools.JavaFileObject; -import javax.tools.JavaFileObject.Kind; -import javax.tools.StandardJavaFileManager; - -/** - * The manager to load byte code of classes. - * - * @author JavaSaBr - */ -public class CompileJavaFileManager extends ForwardingJavaFileManager { - - /** - * The list of names of loaded classes. - */ - private final Array classNames; - - /** - * The loaded of compiled classes. - */ - private final CompileClassLoader loader; - - public CompileJavaFileManager( - final StandardJavaFileManager fileManager, - final CompileClassLoader loader) { - super(fileManager); - this.loader = loader; - this.classNames = ArrayFactory.newArray(String.class); - } - - /** - * Clear the list of names of loaded classes. - */ - public void clear() { - classNames.clear(); - } - - /** - * Get class names. - * - * @return the list of names of loaded classes. - */ - public String[] getClassNames() { - return classNames.toArray(new String[classNames.size()]); - } - - @Override - public JavaFileObject getJavaFileForOutput( - final Location location, - final String name, - final Kind kind, - final FileObject sibling) { - - final CompileByteCode byteCode = new CompileByteCode(name); - - loader.addByteCode(byteCode); - classNames.add(name); - - return byteCode; - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileListener.java b/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileListener.java deleted file mode 100644 index f5889aad..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileListener.java +++ /dev/null @@ -1,49 +0,0 @@ -package javasabr.rlib.common.compiler.impl; - -import static javasabr.rlib.common.util.ClassUtils.unsafeCast; -import static javasabr.rlib.common.util.ObjectUtils.notNull; - -import javasabr.rlib.common.util.array.Array; -import javasabr.rlib.common.util.array.ArrayFactory; -import javax.tools.Diagnostic; -import javax.tools.DiagnosticListener; -import javax.tools.JavaFileObject; - -/** - * The listener of compile events. - * - * @author JavaSaBr - */ -public class CompileListener implements DiagnosticListener { - - /** - * The list of diagnostic reports. - */ - private final Array> diagnostics; - - public CompileListener() { - this.diagnostics = ArrayFactory.newArray(Diagnostic.class); - } - - /** - * Clear reports. - */ - public void clear() { - diagnostics.clear(); - } - - /** - * Get diagnostics. - * - * @return the list of diagnostic reports. - */ - public Diagnostic[] getDiagnostics() { - final Diagnostic[] array = diagnostics.toArray(Diagnostic.class); - return notNull(unsafeCast(array)); - } - - @Override - public void report(final Diagnostic diagnostic) { - diagnostics.add(diagnostic); - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompilerImpl.java b/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompilerImpl.java deleted file mode 100644 index 1e33566b..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompilerImpl.java +++ /dev/null @@ -1,291 +0,0 @@ -package javasabr.rlib.common.compiler.impl; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import javasabr.rlib.common.compiler.Compiler; -import javasabr.rlib.common.util.array.Array; -import javasabr.rlib.common.util.array.ArrayCollectors; -import javasabr.rlib.common.util.array.ArrayFactory; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; -import javax.tools.Diagnostic; -import javax.tools.JavaCompiler; -import javax.tools.JavaCompiler.CompilationTask; -import javax.tools.JavaFileObject; -import javax.tools.StandardJavaFileManager; -import javax.tools.ToolProvider; -import org.jspecify.annotations.Nullable; - -/** - * The base implementation of a compiler using a compiler from JDK. - * - * @author JavaSaBr - */ -public class CompilerImpl implements Compiler { - - private static final Logger LOGGER = LoggerManager.getLogger(Compiler.class); - - /** - * The constant EMPTY_CLASSES. - */ - private static final Class[] EMPTY_CLASSES = new Class[0]; - - /** - * The compile listener. - */ - private final CompileListener listener; - - /** - * The java compiler. - */ - private final JavaCompiler compiler; - - /** - * The class loader. - */ - private final CompileClassLoader loader; - - /** - * The java files manager. - */ - private final CompileJavaFileManager fileManager; - - /** - * The flag of showing reports. - */ - private final boolean showDiagnostic; - - public CompilerImpl(final boolean showDiagnostic) { - this.compiler = ToolProvider.getSystemJavaCompiler(); - this.listener = new CompileListener(); - this.loader = new CompileClassLoader(); - - final StandardJavaFileManager standardJavaFileManager = compiler.getStandardFileManager(listener, null, null); - - this.fileManager = new CompileJavaFileManager(standardJavaFileManager, loader); - this.showDiagnostic = showDiagnostic; - } - - @Override - public Class[] compile(final File... files) { - if (files.length < 1) { - return EMPTY_CLASSES; - } - - final Array javaSource = Arrays - .stream(files) - .map(JavaFileSource::new) - .collect(ArrayCollectors.toArray(JavaFileObject.class)); - - return compile(null, javaSource); - } - - @Override - public Class[] compile(final Path... paths) { - if (paths.length < 1) { - return EMPTY_CLASSES; - } - - final Array javaSource = Arrays - .stream(paths) - .map(JavaFileSource::new) - .collect(ArrayCollectors.toArray(JavaFileObject.class)); - - return compile(null, javaSource); - } - - @Override - public Class[] compile(final URI... uris) { - - final Array javaSource = Arrays - .stream(uris) - .map(JavaFileSource::new) - .collect(ArrayCollectors.toArray(JavaFileObject.class)); - - return compile(null, javaSource); - } - - /** - * Compile the list of sources with the list of options. - * - * @param options the compile options. - * @param source the list of sources. - * @return the list of compiled classes. - */ - protected synchronized Class[] compile( - @Nullable final Iterable options, - final Iterable source) { - - final JavaCompiler compiler = getCompiler(); - - final CompileJavaFileManager fileManager = getFileManager(); - final CompileListener listener = getListener(); - final CompileClassLoader loader = getLoader(); - - try { - - final CompilationTask task = compiler.getTask(null, fileManager, listener, options, null, source); - task.call(); - - final Diagnostic[] diagnostics = listener.getDiagnostics(); - - if (isShowDiagnostic() && diagnostics.length > 0) { - - LOGGER.warning("errors:"); - - for (final Diagnostic diagnostic : diagnostics) { - LOGGER.warning(String.valueOf(diagnostic)); - } - } - - final Array> result = ArrayFactory.newArray(Class.class); - final String[] classNames = fileManager.getClassNames(); - - for (final String className : classNames) { - try { - final Class cs = Class.forName(className, false, loader); - result.add(cs); - } catch (final ClassNotFoundException e) { - LOGGER.warning(e); - } - } - - return result.toArray(new Class[result.size()]); - - } finally { - listener.clear(); - fileManager.clear(); - } - } - - /** - * Compile classes from a directory. - * - * @param container the container. - * @param directory the directory. - */ - private void compileDirectory(final Array> container, final File directory) { - - final File[] files = directory.listFiles(); - if (files == null || files.length < 1) { - return; - } - - for (final File file : files) { - if (file.isDirectory()) { - compileDirectory(container, file); - } else if (file - .getName() - .endsWith(Compiler.SOURCE_EXTENSION)) { - container.addAll(compile(file)); - } - } - } - - @Override - public Class[] compileDirectory(final File... files) { - - final Array> container = ArrayFactory.newArray(Class.class); - - for (final File directory : files) { - - if (!directory.exists() || !directory.isDirectory()) { - continue; - } - - compileDirectory(container, directory); - } - - return container.toArray(new Class[container.size()]); - } - - /** - * Compile classes from a directory. - * - * @param container the container. - * @param directory the directory. - */ - private void compileDirectory(final Array> container, final Path directory) { - try (DirectoryStream stream = Files.newDirectoryStream(directory)) { - - for (final Path path : stream) { - if (Files.isDirectory(path)) { - compileDirectory(container, path); - } else if (path - .toString() - .endsWith(Compiler.SOURCE_EXTENSION)) { - container.addAll(compile(path)); - } - } - - } catch (IOException e) { - LOGGER.warning(e); - } - } - - @Override - public Class[] compileDirectory(Path... paths) { - - final Array> container = ArrayFactory.newArray(Class.class); - - for (final Path path : paths) { - - if (!Files.exists(path) || !Files.isDirectory(path)) { - continue; - } - - compileDirectory(container, path); - } - - return container.toArray(new Class[container.size()]); - - } - - /** - * Gets compiler. - * - * @return the java compiler. - */ - protected JavaCompiler getCompiler() { - return compiler; - } - - /** - * Gets file manager. - * - * @return the java files manager. - */ - protected CompileJavaFileManager getFileManager() { - return fileManager; - } - - /** - * Gets listener. - * - * @return the compile listener. - */ - protected CompileListener getListener() { - return listener; - } - - /** - * Gets loader. - * - * @return the class loader. - */ - protected CompileClassLoader getLoader() { - return loader; - } - - /** - * @return true id need o show reports. - */ - private boolean isShowDiagnostic() { - return showDiagnostic; - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/FileUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/FileUtils.java index eaec478a..883d8b85 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/FileUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/FileUtils.java @@ -10,6 +10,7 @@ import java.net.URI; import java.net.URL; import java.nio.CharBuffer; +import java.nio.file.DirectoryStream; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; @@ -132,37 +133,32 @@ public static String normalizeName(@Nullable String filename) { .replaceAll("_"); } - /** - * Add recursive all files to the container from the folder. - * - * @param container the file container. - * @param dir the folder. - * @param withFolders need to add folders. - * @param extensions extensions filter. - */ public static void addFilesTo( Array container, - Path dir, - boolean withFolders, + Path directory, + boolean includeDirectoriesToResult, String @Nullable ... extensions) { - if (Files.isDirectory(dir) && withFolders) { - container.add(dir); + if (Files.isDirectory(directory) && includeDirectoriesToResult) { + container.add(directory); } - if (!Files.exists(dir)) { + if (!Files.exists(directory)) { LoggerManager .getDefaultLogger() - .warning(dir, arg -> "Folder " + arg + " not found"); + .warning(directory, "Directory:[%s] not found"::formatted); return; } - try (var stream = Files.newDirectoryStream(dir)) { - for (var path : stream) { - if (Files.isDirectory(path)) { - addFilesTo(container, path, withFolders, extensions); - } else if (extensions == null || extensions.length < 1 || containsExtensions(extensions, path.getFileName())) { - container.add(path); + try (DirectoryStream stream = Files.newDirectoryStream(directory)) { + for (Path file : stream) { + if (Files.isDirectory(file)) { + addFilesTo(container, file, includeDirectoriesToResult, extensions); + continue; + } + + if (extensions == null || extensions.length < 1 || hasExtensions(file.getFileName(), extensions)) { + container.add(file); } } @@ -171,26 +167,20 @@ public static void addFilesTo( } } - /** - * Check the extensions of the file. - * - * @param extensions the checked extensions. - * @param path the file. - * @return true if the file has a checked extension. - */ - public static boolean containsExtensions(String @Nullable [] extensions, Path path) { - return containsExtensions(extensions, path.toString()); + public static String fileName(Path file) { + return file.getFileName().toString(); } - /** - * Check the extensions of the path. - * - * @param extensions the checked extensions. - * @param path the path. - * @return true if the path has a checked extension. - */ - public static boolean containsExtensions(String @Nullable [] extensions, String path) { - return ArrayUtils.anyMatchR(extensions, path, String::endsWith); + public static boolean hasExtension(Path file, String extension) { + return fileName(file).endsWith(extension); + } + + public static boolean hasExtensions(Path fileName, String @Nullable [] extensions) { + return hasExtensions(fileName.toString(), extensions); + } + + public static boolean hasExtensions(String fileName, String @Nullable [] extensions) { + return ArrayUtils.anyMatchR(extensions, fileName, String::endsWith); } /** @@ -200,8 +190,8 @@ public static boolean containsExtensions(String @Nullable [] extensions, String * @param path the file. * @return true if the file has a checked extension. */ - public static boolean containsExtensions(@Nullable Array extensions, Path path) { - return containsExtensions(extensions, path.toString()); + public static boolean hasExtensions(@Nullable Array extensions, Path path) { + return hasExtensions(extensions, path.toString()); } /** @@ -211,7 +201,7 @@ public static boolean containsExtensions(@Nullable Array extensions, Pat * @param path the path. * @return true if the path has a checked extension. */ - public static boolean containsExtensions(@Nullable Array extensions, String path) { + public static boolean hasExtensions(@Nullable Array extensions, String path) { return extensions != null && extensions.anyMatchR(path, String::endsWith); } @@ -222,8 +212,8 @@ public static boolean containsExtensions(@Nullable Array extensions, Str * @param path the file. * @return true if the file has a checked extension. */ - public static boolean containsExtensions(@Nullable Collection extensions, Path path) { - return containsExtensions(extensions, path.toString()); + public static boolean hasExtensions(@Nullable Collection extensions, Path path) { + return hasExtensions(extensions, path.toString()); } /** @@ -233,7 +223,7 @@ public static boolean containsExtensions(@Nullable Collection extensions * @param path the path. * @return true if the path has a checked extension. */ - public static boolean containsExtensions(@Nullable Collection extensions, String path) { + public static boolean hasExtensions(@Nullable Collection extensions, String path) { return extensions != null && extensions .stream() .anyMatch(path::endsWith); @@ -437,7 +427,7 @@ public static Path[] getFiles(Package pckg, String @Nullable ... extensions) { if (Files.isDirectory(file)) { files.addAll(getFiles(file, extensions)); - } else if (extensions == null || extensions.length < 1 || containsExtensions(extensions, path)) { + } else if (extensions == null || extensions.length < 1 || hasExtensions(path, extensions)) { files.add(file); } } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/array/ArrayComparator.java b/rlib-common/src/main/java/javasabr/rlib/common/util/array/ArrayComparator.java index 6a639c4a..48d3d760 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/array/ArrayComparator.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/array/ArrayComparator.java @@ -14,15 +14,15 @@ public interface ArrayComparator extends Comparator { @Override - default int compare(@Nullable T first, @Nullable T second) { + default int compare(@Nullable T left, @Nullable T right) { - if (first == null) { + if (left == null) { return 1; - } else if (second == null) { + } else if (right == null) { return -1; } - return compareImpl(first, second); + return compareImpl(left, right); } /** diff --git a/rlib-common/src/test/java/javasabr/rlib/common/compiler/CompilerTests.java b/rlib-common/src/test/java/javasabr/rlib/common/compiler/CompilerTests.java deleted file mode 100644 index 6b75fe61..00000000 --- a/rlib-common/src/test/java/javasabr/rlib/common/compiler/CompilerTests.java +++ /dev/null @@ -1,36 +0,0 @@ -package javasabr.rlib.common.compiler; - -import java.lang.reflect.InvocationTargetException; -import java.net.URISyntaxException; -import javasabr.rlib.common.util.ClassUtils; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * The list of tests to work with compiler API. - * - * @author JavaSaBr - */ -public class CompilerTests { - - @Test - void compileTest() - throws URISyntaxException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { - - var javaSource = getClass().getResource("/java/source/TestCompileJavaSource.java"); - - var compiler = CompilerFactory.newDefaultCompiler(); - var compiled = compiler.compile(javaSource.toURI()); - - Assertions.assertEquals(1, compiled.length); - Assertions.assertEquals("TestCompileJavaSource", compiled[0].getName()); - - var instance = ClassUtils.newInstance(compiled[0]); - var method = instance - .getClass() - .getMethod("makeString"); - var result = method.invoke(instance); - - Assertions.assertEquals("testString", result); - } -} diff --git a/rlib-compiler/build.gradle b/rlib-compiler/build.gradle new file mode 100644 index 00000000..f8325ab9 --- /dev/null +++ b/rlib-compiler/build.gradle @@ -0,0 +1,5 @@ + +dependencies { + api projects.rlibCommon + testImplementation projects.rlibLoggerImpl +} \ No newline at end of file diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/ByteCode.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/ByteCode.java new file mode 100644 index 00000000..d62be4f3 --- /dev/null +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/ByteCode.java @@ -0,0 +1,11 @@ +package javasabr.rlib.compiler; + +/** + * @author JavaSaBr + */ +public interface ByteCode { + + byte[] byteCode(); + + String name(); +} diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/Compiler.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/Compiler.java new file mode 100644 index 00000000..38ce00e9 --- /dev/null +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/Compiler.java @@ -0,0 +1,18 @@ +package javasabr.rlib.compiler; + +import java.net.URI; +import java.nio.file.Path; +import javasabr.rlib.common.util.array.Array; + +/** + * @author JavaSaBr + */ +public interface Compiler { + + String SOURCE_EXTENSION = ".java"; + String CLASS_EXTENSION = ".class"; + + Array> compileByUrls(Array urls); + Array> compileFiles(Array files); + Array> compileDirectories(Array directories); +} diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/CompilerFactory.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/CompilerFactory.java new file mode 100644 index 00000000..8f66d8c1 --- /dev/null +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/CompilerFactory.java @@ -0,0 +1,24 @@ +package javasabr.rlib.compiler; + +import javasabr.rlib.compiler.impl.JdkCompiler; +import javax.tools.ToolProvider; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * @author JavaSaBr + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class CompilerFactory { + + /** + * Check availability compiler API in current runtime. + */ + public static boolean isAvailableCompiler() { + return ToolProvider.getSystemJavaCompiler() != null; + } + + public static Compiler newDefaultCompiler() { + return new JdkCompiler(true); + } +} diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompileEventListener.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompileEventListener.java new file mode 100644 index 00000000..aaa3b346 --- /dev/null +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompileEventListener.java @@ -0,0 +1,35 @@ +package javasabr.rlib.compiler.impl; + +import javasabr.rlib.common.util.array.Array; +import javasabr.rlib.common.util.array.ArrayFactory; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticListener; +import javax.tools.JavaFileObject; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; + +/** + * @author JavaSaBr + */ +@Getter +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public class CompileEventListener implements DiagnosticListener { + + Array> diagnostics; + + public CompileEventListener() { + this.diagnostics = ArrayFactory.newArray(Diagnostic.class); + } + + public void clear() { + diagnostics.clear(); + } + + @Override + public void report(Diagnostic diagnostic) { + diagnostics.add(diagnostic); + } +} diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledByteCode.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledByteCode.java new file mode 100644 index 00000000..c69b61c2 --- /dev/null +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledByteCode.java @@ -0,0 +1,42 @@ +package javasabr.rlib.compiler.impl; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.net.URI; +import javasabr.rlib.compiler.ByteCode; +import javasabr.rlib.compiler.Compiler; +import javax.tools.SimpleJavaFileObject; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; + +/** + * @author JavaSaBr + */ +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public class CompiledByteCode extends SimpleJavaFileObject implements ByteCode { + + ByteArrayOutputStream outputStream; + + @Getter + String name; + + public CompiledByteCode(String name) { + super(URI.create("byte:///" + name.replace('/', '.') + Compiler.CLASS_EXTENSION), Kind.CLASS); + this.outputStream = new ByteArrayOutputStream(); + this.name = name; + + } + + @Override + public byte[] byteCode() { + return outputStream.toByteArray(); + } + + @Override + public OutputStream openOutputStream() { + return outputStream; + } +} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileClassLoader.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledClassesClassLoader.java similarity index 50% rename from rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileClassLoader.java rename to rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledClassesClassLoader.java index e880a995..ea88000e 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/CompileClassLoader.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledClassesClassLoader.java @@ -1,31 +1,27 @@ -package javasabr.rlib.common.compiler.impl; +package javasabr.rlib.compiler.impl; -import javasabr.rlib.common.compiler.ByteCode; +import javasabr.rlib.compiler.ByteCode; import javasabr.rlib.common.util.Utils; import javasabr.rlib.common.util.array.Array; import javasabr.rlib.common.util.array.ArrayFactory; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; /** - * The implementation of a class loader of compiled classes. - * * @author JavaSaBr */ -public class CompileClassLoader extends ClassLoader { +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public class CompiledClassesClassLoader extends ClassLoader { - /** - * The list of byte codes of loaded classes. - */ - private final Array byteCode; + Array byteCode; - public CompileClassLoader() { + public CompiledClassesClassLoader() { this.byteCode = ArrayFactory.newArray(ByteCode.class); } /** * Add a new compiled class. - * - * @param byteCode the byte code */ public synchronized void addByteCode(ByteCode byteCode) { this.byteCode.add(byteCode); @@ -38,9 +34,11 @@ public synchronized void addByteCode(ByteCode byteCode) { return null; } - for (var byteCode : this.byteCode) { - var content = byteCode.getByteCode(); - return Utils.uncheckedGet(() -> defineClass(name, content, 0, content.length)); + for (ByteCode byteCode : this.byteCode) { + if (name.equals(byteCode.name())) { + byte[] content = byteCode.byteCode(); + return Utils.uncheckedGet(() -> defineClass(name, content, 0, content.length)); + } } return null; diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledJavaFileManager.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledJavaFileManager.java new file mode 100644 index 00000000..c28e8561 --- /dev/null +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledJavaFileManager.java @@ -0,0 +1,54 @@ +package javasabr.rlib.compiler.impl; + +import javasabr.rlib.common.util.array.Array; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.StandardJavaFileManager; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +/** + * @author JavaSaBr + */ +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public class CompiledJavaFileManager extends ForwardingJavaFileManager { + + Array classNames; + CompiledClassesClassLoader classLoader; + + public CompiledJavaFileManager( + StandardJavaFileManager fileManager, + CompiledClassesClassLoader classLoader) { + super(fileManager); + this.classLoader = classLoader; + this.classNames = Array.ofType(String.class); + } + + /** + * Clear the list of names of loaded classes. + */ + public void clear() { + classNames.clear(); + } + + public String[] classNames() { + return classNames.toArray(); + } + + @Override + public JavaFileObject getJavaFileForOutput( + Location location, + String name, + Kind kind, + FileObject sibling) { + + CompiledByteCode byteCode = new CompiledByteCode(name); + + classLoader.addByteCode(byteCode); + classNames.add(name); + + return byteCode; + } +} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/JavaFileSource.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JavaFileSource.java similarity index 64% rename from rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/JavaFileSource.java rename to rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JavaFileSource.java index 136c52ce..4e85f77b 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/JavaFileSource.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JavaFileSource.java @@ -1,34 +1,28 @@ -package javasabr.rlib.common.compiler.impl; +package javasabr.rlib.compiler.impl; -import java.io.File; import java.io.IOException; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import javax.tools.SimpleJavaFileObject; /** - * The implementation of java class source. - * * @author JavaSaBr */ public class JavaFileSource extends SimpleJavaFileObject { - protected JavaFileSource(final File file) { - super(file.toURI(), Kind.SOURCE); - } - - protected JavaFileSource(final Path path) { + protected JavaFileSource(Path path) { super(path.toUri(), Kind.SOURCE); } - protected JavaFileSource(final URI uri) { + protected JavaFileSource(URI uri) { super(uri, Kind.SOURCE); } @Override - public boolean equals(final Object obj) { + public boolean equals(Object obj) { if (this == obj) { return true; @@ -52,9 +46,8 @@ public boolean equals(final Object obj) { } @Override - public CharSequence getCharContent(final boolean ignoreEncodingErrors) throws IOException { - final Path path = Paths.get(uri); - return new String(Files.readAllBytes(path), "UTF-8"); + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return Files.readString(Paths.get(uri), StandardCharsets.UTF_8); } @Override diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java new file mode 100644 index 00000000..21bcf893 --- /dev/null +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java @@ -0,0 +1,139 @@ +package javasabr.rlib.compiler.impl; + +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import javasabr.rlib.common.util.FileUtils; +import javasabr.rlib.compiler.Compiler; +import javasabr.rlib.common.util.array.Array; +import javasabr.rlib.common.util.array.ArrayCollectors; +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerManager; +import javax.tools.Diagnostic; +import javax.tools.JavaCompiler; +import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; +import org.jspecify.annotations.Nullable; + +/** + * @author JavaSaBr + */ +@Getter +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public class JdkCompiler implements Compiler { + + private static final Logger LOGGER = LoggerManager.getLogger(Compiler.class); + + private static final Class[] EMPTY_CLASSES = new Class[0]; + + CompileEventListener listener; + JavaCompiler compiler; + CompiledClassesClassLoader loader; + CompiledJavaFileManager fileManager; + + boolean showDiagnostic; + + public JdkCompiler(final boolean showDiagnostic) { + this.compiler = ToolProvider.getSystemJavaCompiler(); + this.listener = new CompileEventListener(); + this.loader = new CompiledClassesClassLoader(); + + StandardJavaFileManager standardJavaFileManager = compiler + .getStandardFileManager(listener, null, null); + + this.fileManager = new CompiledJavaFileManager(standardJavaFileManager, loader); + this.showDiagnostic = showDiagnostic; + } + + @Override + public Array> compileByUrls(Array urls) { + return compile( + Array.empty(), + urls + .stream() + .map(JavaFileSource::new) + .collect(ArrayCollectors.toArray(JavaFileObject.class))); + } + + @Override + public Array> compileFiles(Array files) { + return compile( + Array.empty(), + files + .stream() + .map(JavaFileSource::new) + .collect(ArrayCollectors.toArray(JavaFileObject.class))); + } + + @Override + public Array> compileDirectories(Array directories) { + + Array files = Array.ofType(Path.class); + + for (Path directory : directories) { + if (!Files.exists(directory) || !Files.isDirectory(directory)) { + continue; + } + + FileUtils.addFilesTo(files, directory, false, Compiler.SOURCE_EXTENSION); + } + + if (files.isEmpty()) { + return Array.empty(); + } + + return compile( + Array.empty(), + files + .stream() + .map(JavaFileSource::new) + .collect(ArrayCollectors.toArray(JavaFileObject.class))); + } + + protected synchronized Array> compile( + @Nullable Array options, + Array sources) { + + JavaCompiler compiler = compiler(); + CompiledJavaFileManager fileManager = fileManager(); + CompileEventListener listener = listener(); + CompiledClassesClassLoader loader = loader(); + try { + + CompilationTask task = compiler.getTask(null, fileManager, listener, options, null, sources); + task.call(); + + Array> diagnostics = listener.diagnostics(); + if (showDiagnostic() && !diagnostics.isEmpty()) { + LOGGER.warning("Compilation messages:"); + for (Diagnostic diagnostic : diagnostics) { + LOGGER.warning(String.valueOf(diagnostic)); + } + } + + Array> result = Array.ofType(Class.class); + String[] classNames = fileManager.classNames(); + + for (String className : classNames) { + try { + Class klass = Class.forName(className, false, loader); + result.add(klass); + } catch (ClassNotFoundException e) { + LOGGER.warning(e); + } + } + + return result; + } finally { + listener.clear(); + fileManager.clear(); + } + } +} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/compiler/package-info.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/package-info.java similarity index 58% rename from rlib-common/src/main/java/javasabr/rlib/common/compiler/package-info.java rename to rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/package-info.java index 742de599..2c70bc08 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/compiler/package-info.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/package-info.java @@ -1,4 +1,4 @@ @NullMarked -package javasabr.rlib.common.compiler; +package javasabr.rlib.compiler.impl; import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/package-info.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/package-info.java similarity index 56% rename from rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/package-info.java rename to rlib-compiler/src/main/java/javasabr/rlib/compiler/package-info.java index 8ef935d3..1e6358e7 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/compiler/impl/package-info.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/package-info.java @@ -1,4 +1,4 @@ @NullMarked -package javasabr.rlib.common.compiler.impl; +package javasabr.rlib.compiler; import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-compiler/src/test/java/javasabr/rlib/compiler/CompilerTests.java b/rlib-compiler/src/test/java/javasabr/rlib/compiler/CompilerTests.java new file mode 100644 index 00000000..21057f40 --- /dev/null +++ b/rlib-compiler/src/test/java/javasabr/rlib/compiler/CompilerTests.java @@ -0,0 +1,79 @@ +package javasabr.rlib.compiler; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.RecordComponent; +import java.net.URISyntaxException; +import javasabr.rlib.common.util.ClassUtils; +import javasabr.rlib.common.util.array.Array; +import javasabr.rlib.logger.api.LoggerLevel; +import javasabr.rlib.logger.api.LoggerManager; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author JavaSaBr + */ +public class CompilerTests { + + static { + LoggerManager.enable(Compiler.class, LoggerLevel.DEBUG); + } + + @Test + void compileTest() + throws URISyntaxException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, + InstantiationException { + + // given: + var javaSources = Array.of( + getClass().getResource("/java/source/TestCompileDependency.java").toURI(), + getClass().getResource("/java/source/TestCompileJavaSource.java").toURI(), + getClass().getResource("/java/source/TestCompileRecord.java").toURI()); + + // when: + var compiler = CompilerFactory.newDefaultCompiler(); + var compiledClasses = compiler.compileByUrls(javaSources); + + // then: + Assertions.assertEquals(3, compiledClasses.size()); + + compiledClasses.sort((left, right) -> left.getName().compareTo(right.getName())); + + Assertions.assertEquals("TestCompileDependency", compiledClasses.get(0).getName()); + Assertions.assertEquals("TestCompileJavaSource", compiledClasses.get(1).getName()); + Assertions.assertEquals("TestCompileRecord", compiledClasses.get(2).getName()); + + // when: + var instance1 = ClassUtils.newInstance(compiledClasses.get(0)); + var method = instance1 + .getClass() + .getMethod("calcInteger"); + var result = method.invoke(instance1); + + // then: + Assertions.assertEquals(5, result); + + // when: + var instance2 = ClassUtils.newInstance(compiledClasses.get(1)); + method = instance2 + .getClass() + .getMethod("makeString"); + result = method.invoke(instance2); + + // then: + Assertions.assertEquals("testString", result); + + // when: + Record instance3 = (Record) ClassUtils + .tryGetConstructor(compiledClasses.get(2), compiledClasses.get(0), String.class) + .newInstance(instance1, "recordString"); + + // then: + RecordComponent[] recordComponents = instance3 + .getClass() + .getRecordComponents(); + + Assertions.assertEquals(instance1, recordComponents[0].getAccessor().invoke(instance3)); + Assertions.assertEquals("recordString", recordComponents[1].getAccessor().invoke(instance3)); + } +} diff --git a/rlib-compiler/src/test/resources/java/source/TestCompileDependency.java b/rlib-compiler/src/test/resources/java/source/TestCompileDependency.java new file mode 100644 index 00000000..cf3699c9 --- /dev/null +++ b/rlib-compiler/src/test/resources/java/source/TestCompileDependency.java @@ -0,0 +1,5 @@ +public class TestCompileDependency { + public int calcInteger() { + return 5; + } +} diff --git a/rlib-common/src/test/resources/java/source/TestCompileJavaSource.java b/rlib-compiler/src/test/resources/java/source/TestCompileJavaSource.java similarity index 100% rename from rlib-common/src/test/resources/java/source/TestCompileJavaSource.java rename to rlib-compiler/src/test/resources/java/source/TestCompileJavaSource.java diff --git a/rlib-compiler/src/test/resources/java/source/TestCompileRecord.java b/rlib-compiler/src/test/resources/java/source/TestCompileRecord.java new file mode 100644 index 00000000..8065fdd4 --- /dev/null +++ b/rlib-compiler/src/test/resources/java/source/TestCompileRecord.java @@ -0,0 +1 @@ +public record TestCompileRecord(TestCompileDependency dependency, String rawString) {} diff --git a/settings.gradle b/settings.gradle index 21ccd467..17c639bb 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,4 +12,5 @@ include ':rlib-logger-impl' include ':rlib-logger-slf4j' include ':rlib-plugin-system' include ':rlib-geometry' -include ':rlib-classpath' \ No newline at end of file +include ':rlib-classpath' +include ':rlib-compiler' \ No newline at end of file From 7725e5b75f1d8c125c36988494b868b2af8738d9 Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 10 Aug 2025 14:48:33 +0200 Subject: [PATCH 2/6] fix package for classpath module --- .../rlib/{common => }/classpath/ClassPathScanner.java | 4 ++-- .../{common => }/classpath/ClassPathScannerFactory.java | 6 +++--- .../{common => }/classpath/impl/ClassPathScannerImpl.java | 4 ++-- .../classpath/impl/ManifestClassPathScannerImpl.java | 2 +- .../{common/classpath => classpath/impl}/package-info.java | 2 +- .../{common/classpath/impl => classpath}/package-info.java | 2 +- .../rlib/{common => }/classpath/ClasspathScannerTests.java | 2 +- .../network/packet/registry/ReadablePacketRegistry.java | 4 ++-- .../java/javasabr/rlib/plugin/system/PluginContainer.java | 2 +- .../javasabr/rlib/plugin/system/impl/BasePluginSystem.java | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) rename rlib-classpath/src/main/java/javasabr/rlib/{common => }/classpath/ClassPathScanner.java (95%) rename rlib-classpath/src/main/java/javasabr/rlib/{common => }/classpath/ClassPathScannerFactory.java (86%) rename rlib-classpath/src/main/java/javasabr/rlib/{common => }/classpath/impl/ClassPathScannerImpl.java (99%) rename rlib-classpath/src/main/java/javasabr/rlib/{common => }/classpath/impl/ManifestClassPathScannerImpl.java (98%) rename rlib-classpath/src/main/java/javasabr/rlib/{common/classpath => classpath/impl}/package-info.java (58%) rename rlib-classpath/src/main/java/javasabr/rlib/{common/classpath/impl => classpath}/package-info.java (55%) rename rlib-classpath/src/test/java/javasabr/rlib/{common => }/classpath/ClasspathScannerTests.java (95%) diff --git a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScanner.java b/rlib-classpath/src/main/java/javasabr/rlib/classpath/ClassPathScanner.java similarity index 95% rename from rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScanner.java rename to rlib-classpath/src/main/java/javasabr/rlib/classpath/ClassPathScanner.java index 988a762f..9410a4b4 100644 --- a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScanner.java +++ b/rlib-classpath/src/main/java/javasabr/rlib/classpath/ClassPathScanner.java @@ -1,10 +1,10 @@ -package javasabr.rlib.common.classpath; +package javasabr.rlib.classpath; import java.lang.annotation.Annotation; import java.net.URL; import java.net.URLClassLoader; import java.util.function.Predicate; -import javasabr.rlib.common.classpath.impl.ClassPathScannerImpl; +import javasabr.rlib.classpath.impl.ClassPathScannerImpl; import javasabr.rlib.common.util.array.Array; import org.jspecify.annotations.Nullable; diff --git a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScannerFactory.java b/rlib-classpath/src/main/java/javasabr/rlib/classpath/ClassPathScannerFactory.java similarity index 86% rename from rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScannerFactory.java rename to rlib-classpath/src/main/java/javasabr/rlib/classpath/ClassPathScannerFactory.java index ae863e39..10fa17c4 100644 --- a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScannerFactory.java +++ b/rlib-classpath/src/main/java/javasabr/rlib/classpath/ClassPathScannerFactory.java @@ -1,7 +1,7 @@ -package javasabr.rlib.common.classpath; +package javasabr.rlib.classpath; -import javasabr.rlib.common.classpath.impl.ClassPathScannerImpl; -import javasabr.rlib.common.classpath.impl.ManifestClassPathScannerImpl; +import javasabr.rlib.classpath.impl.ClassPathScannerImpl; +import javasabr.rlib.classpath.impl.ManifestClassPathScannerImpl; /** * @author JavaSaBr diff --git a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ClassPathScannerImpl.java b/rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/ClassPathScannerImpl.java similarity index 99% rename from rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ClassPathScannerImpl.java rename to rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/ClassPathScannerImpl.java index ac100cd0..f8a1925c 100644 --- a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ClassPathScannerImpl.java +++ b/rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/ClassPathScannerImpl.java @@ -1,4 +1,4 @@ -package javasabr.rlib.common.classpath.impl; +package javasabr.rlib.classpath.impl; import static java.lang.reflect.Modifier.isAbstract; import static javasabr.rlib.common.util.ClassUtils.unsafeNNCast; @@ -14,7 +14,7 @@ import java.util.function.Predicate; import java.util.jar.JarInputStream; import java.util.zip.ZipException; -import javasabr.rlib.common.classpath.ClassPathScanner; +import javasabr.rlib.classpath.ClassPathScanner; import javasabr.rlib.common.io.impl.ReuseBytesInputStream; import javasabr.rlib.common.io.impl.ReuseBytesOutputStream; import javasabr.rlib.common.util.ArrayUtils; diff --git a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ManifestClassPathScannerImpl.java b/rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/ManifestClassPathScannerImpl.java similarity index 98% rename from rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ManifestClassPathScannerImpl.java rename to rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/ManifestClassPathScannerImpl.java index 4ddcc931..e56143cc 100644 --- a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ManifestClassPathScannerImpl.java +++ b/rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/ManifestClassPathScannerImpl.java @@ -1,4 +1,4 @@ -package javasabr.rlib.common.classpath.impl; +package javasabr.rlib.classpath.impl; import java.io.InputStream; import java.net.URL; diff --git a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/package-info.java b/rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/package-info.java similarity index 58% rename from rlib-classpath/src/main/java/javasabr/rlib/common/classpath/package-info.java rename to rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/package-info.java index 7b11faaf..9b426ac0 100644 --- a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/package-info.java +++ b/rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/package-info.java @@ -1,4 +1,4 @@ @NullMarked -package javasabr.rlib.common.classpath; +package javasabr.rlib.classpath.impl; import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/package-info.java b/rlib-classpath/src/main/java/javasabr/rlib/classpath/package-info.java similarity index 55% rename from rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/package-info.java rename to rlib-classpath/src/main/java/javasabr/rlib/classpath/package-info.java index ce23c2a1..5c187863 100644 --- a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/package-info.java +++ b/rlib-classpath/src/main/java/javasabr/rlib/classpath/package-info.java @@ -1,4 +1,4 @@ @NullMarked -package javasabr.rlib.common.classpath.impl; +package javasabr.rlib.classpath; import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-classpath/src/test/java/javasabr/rlib/common/classpath/ClasspathScannerTests.java b/rlib-classpath/src/test/java/javasabr/rlib/classpath/ClasspathScannerTests.java similarity index 95% rename from rlib-classpath/src/test/java/javasabr/rlib/common/classpath/ClasspathScannerTests.java rename to rlib-classpath/src/test/java/javasabr/rlib/classpath/ClasspathScannerTests.java index 4130ef73..7254d6aa 100644 --- a/rlib-classpath/src/test/java/javasabr/rlib/common/classpath/ClasspathScannerTests.java +++ b/rlib-classpath/src/test/java/javasabr/rlib/classpath/ClasspathScannerTests.java @@ -1,4 +1,4 @@ -package javasabr.rlib.common.classpath; +package javasabr.rlib.classpath; import java.util.Collection; import javasabr.rlib.common.util.array.Array; diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadablePacketRegistry.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadablePacketRegistry.java index 9ff97213..b463b55d 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadablePacketRegistry.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadablePacketRegistry.java @@ -1,7 +1,7 @@ package javasabr.rlib.network.packet.registry; -import javasabr.rlib.common.classpath.ClassPathScanner; -import javasabr.rlib.common.classpath.ClassPathScannerFactory; +import javasabr.rlib.classpath.ClassPathScanner; +import javasabr.rlib.classpath.ClassPathScannerFactory; import javasabr.rlib.common.util.array.Array; import javasabr.rlib.common.util.array.ArrayCollectors; import javasabr.rlib.network.annotation.PacketDescription; diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/PluginContainer.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/PluginContainer.java index 87df056e..d5ccbe27 100644 --- a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/PluginContainer.java +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/PluginContainer.java @@ -2,7 +2,7 @@ import java.net.URLClassLoader; import java.nio.file.Path; -import javasabr.rlib.common.classpath.ClassPathScanner; +import javasabr.rlib.classpath.ClassPathScanner; import javasabr.rlib.plugin.system.annotation.PluginDescription; import lombok.AccessLevel; import lombok.Getter; diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/BasePluginSystem.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/BasePluginSystem.java index 6c0bcb38..44a4ccb9 100644 --- a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/BasePluginSystem.java +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/BasePluginSystem.java @@ -23,7 +23,7 @@ import java.util.concurrent.ForkJoinPool; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import javasabr.rlib.common.classpath.ClassPathScannerFactory; +import javasabr.rlib.classpath.ClassPathScannerFactory; import javasabr.rlib.common.util.ClassUtils; import javasabr.rlib.common.util.FileUtils; import javasabr.rlib.common.util.Utils; From 0f233ff224df395663e28b385334fdb1b36704ee Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 10 Aug 2025 15:34:36 +0200 Subject: [PATCH 3/6] upgrade logger api and refactor compiler module --- .../rlib/classpath/ClasspathScannerTests.java | 2 +- .../{ByteCode.java => CompiledClassData.java} | 4 +- .../java/javasabr/rlib/compiler/Compiler.java | 2 + .../compiler/impl/CompileEventListener.java | 2 +- .../impl/CompiledClassesClassLoader.java | 31 +++++++----- .../impl/CompiledJavaFileManager.java | 4 +- .../rlib/compiler/impl/JdkCompiler.java | 9 +++- ...Code.java => SimpleCompiledClassData.java} | 11 +++-- .../javasabr/rlib/compiler/CompilerTests.java | 2 +- .../java/javasabr/rlib/logger/api/Logger.java | 35 +++++++++---- .../rlib/logger/api/LoggerManager.java | 36 +++++++++++--- .../rlib/logger/api/LoggerService.java | 33 +++++++++++++ .../rlib/logger/impl/DefaultLogger.java | 41 ++++++++++------ ...Factory.java => DefaultLoggerService.java} | 49 ++++++++++++++++--- .../javasabr.rlib.logger.api.LoggerFactory | 2 +- 15 files changed, 200 insertions(+), 63 deletions(-) rename rlib-compiler/src/main/java/javasabr/rlib/compiler/{ByteCode.java => CompiledClassData.java} (66%) rename rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/{CompiledByteCode.java => SimpleCompiledClassData.java} (76%) create mode 100644 rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerService.java rename rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/{DefaultLoggerFactory.java => DefaultLoggerService.java} (68%) diff --git a/rlib-classpath/src/test/java/javasabr/rlib/classpath/ClasspathScannerTests.java b/rlib-classpath/src/test/java/javasabr/rlib/classpath/ClasspathScannerTests.java index 7254d6aa..69ccde92 100644 --- a/rlib-classpath/src/test/java/javasabr/rlib/classpath/ClasspathScannerTests.java +++ b/rlib-classpath/src/test/java/javasabr/rlib/classpath/ClasspathScannerTests.java @@ -14,7 +14,7 @@ public class ClasspathScannerTests { static { - LoggerManager.enable(ClassPathScanner.class, LoggerLevel.DEBUG); + LoggerManager.configureDefault(LoggerLevel.DEBUG, true); } @Test diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/ByteCode.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/CompiledClassData.java similarity index 66% rename from rlib-compiler/src/main/java/javasabr/rlib/compiler/ByteCode.java rename to rlib-compiler/src/main/java/javasabr/rlib/compiler/CompiledClassData.java index d62be4f3..350ed19b 100644 --- a/rlib-compiler/src/main/java/javasabr/rlib/compiler/ByteCode.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/CompiledClassData.java @@ -3,9 +3,11 @@ /** * @author JavaSaBr */ -public interface ByteCode { +public interface CompiledClassData { byte[] byteCode(); + int size(); + String name(); } diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/Compiler.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/Compiler.java index 38ce00e9..6d2aa47d 100644 --- a/rlib-compiler/src/main/java/javasabr/rlib/compiler/Compiler.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/Compiler.java @@ -13,6 +13,8 @@ public interface Compiler { String CLASS_EXTENSION = ".class"; Array> compileByUrls(Array urls); + Array> compileFiles(Array files); + Array> compileDirectories(Array directories); } diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompileEventListener.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompileEventListener.java index aaa3b346..a2bfc702 100644 --- a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompileEventListener.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompileEventListener.java @@ -21,7 +21,7 @@ public class CompileEventListener implements DiagnosticListener Array> diagnostics; public CompileEventListener() { - this.diagnostics = ArrayFactory.newArray(Diagnostic.class); + this.diagnostics = Array.ofType(Diagnostic.class); } public void clear() { diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledClassesClassLoader.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledClassesClassLoader.java index ea88000e..5a2ed949 100644 --- a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledClassesClassLoader.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledClassesClassLoader.java @@ -1,9 +1,10 @@ package javasabr.rlib.compiler.impl; -import javasabr.rlib.compiler.ByteCode; +import javasabr.rlib.compiler.CompiledClassData; import javasabr.rlib.common.util.Utils; import javasabr.rlib.common.util.array.Array; -import javasabr.rlib.common.util.array.ArrayFactory; +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerManager; import lombok.AccessLevel; import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; @@ -14,30 +15,36 @@ @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) public class CompiledClassesClassLoader extends ClassLoader { - Array byteCode; + private static final Logger LOGGER = LoggerManager.getLogger(CompiledClassesClassLoader.class); + + Array compiledClassData; public CompiledClassesClassLoader() { - this.byteCode = ArrayFactory.newArray(ByteCode.class); + this.compiledClassData = Array.ofType(CompiledClassData.class); } /** * Add a new compiled class. */ - public synchronized void addByteCode(ByteCode byteCode) { - this.byteCode.add(byteCode); + public synchronized void registerClassData(CompiledClassData classData) { + LOGGER.debug(classData.name(), "Register compiled class data:[%s]"::formatted); + compiledClassData.add(classData); } @Override - protected synchronized @Nullable Class findClass(String name) { + protected synchronized @Nullable Class findClass(String className) { - if (byteCode.isEmpty()) { + if (compiledClassData.isEmpty()) { return null; } - for (ByteCode byteCode : this.byteCode) { - if (name.equals(byteCode.name())) { - byte[] content = byteCode.byteCode(); - return Utils.uncheckedGet(() -> defineClass(name, content, 0, content.length)); + LOGGER.debug(className, "Try to find compiled class data for class:[%s]"::formatted); + + for (CompiledClassData classData : this.compiledClassData) { + if (className.equals(classData.name())) { + LOGGER.debug(classData.size(), className, "Loading bytecode:[%s] for class:[%s]..."::formatted); + byte[] content = classData.byteCode(); + return Utils.uncheckedGet(() -> defineClass(className, content, 0, content.length)); } } diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledJavaFileManager.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledJavaFileManager.java index c28e8561..fa076913 100644 --- a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledJavaFileManager.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledJavaFileManager.java @@ -44,9 +44,9 @@ public JavaFileObject getJavaFileForOutput( Kind kind, FileObject sibling) { - CompiledByteCode byteCode = new CompiledByteCode(name); + SimpleCompiledClassData byteCode = new SimpleCompiledClassData(name); - classLoader.addByteCode(byteCode); + classLoader.registerClassData(byteCode); classNames.add(name); return byteCode; diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java index 21bcf893..b37176b9 100644 --- a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java @@ -29,7 +29,7 @@ @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) public class JdkCompiler implements Compiler { - private static final Logger LOGGER = LoggerManager.getLogger(Compiler.class); + private static final Logger LOGGER = LoggerManager.getLogger(JdkCompiler.class); private static final Class[] EMPTY_CLASSES = new Class[0]; @@ -40,7 +40,7 @@ public class JdkCompiler implements Compiler { boolean showDiagnostic; - public JdkCompiler(final boolean showDiagnostic) { + public JdkCompiler(boolean showDiagnostic) { this.compiler = ToolProvider.getSystemJavaCompiler(); this.listener = new CompileEventListener(); this.loader = new CompiledClassesClassLoader(); @@ -101,6 +101,8 @@ protected synchronized Array> compile( @Nullable Array options, Array sources) { + LOGGER.debug(sources.size(), "Start compiling [%s] source files..."::formatted); + JavaCompiler compiler = compiler(); CompiledJavaFileManager fileManager = fileManager(); CompileEventListener listener = listener(); @@ -121,7 +123,10 @@ protected synchronized Array> compile( Array> result = Array.ofType(Class.class); String[] classNames = fileManager.classNames(); + LOGGER.debug(classNames.length, "Got [%s] compiled class names"::formatted); + for (String className : classNames) { + LOGGER.debug(className, "Try to load class:[%s]"::formatted); try { Class klass = Class.forName(className, false, loader); result.add(klass); diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledByteCode.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/SimpleCompiledClassData.java similarity index 76% rename from rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledByteCode.java rename to rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/SimpleCompiledClassData.java index c69b61c2..d2dc1832 100644 --- a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledByteCode.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/SimpleCompiledClassData.java @@ -3,7 +3,7 @@ import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.net.URI; -import javasabr.rlib.compiler.ByteCode; +import javasabr.rlib.compiler.CompiledClassData; import javasabr.rlib.compiler.Compiler; import javax.tools.SimpleJavaFileObject; import lombok.AccessLevel; @@ -16,14 +16,14 @@ */ @Accessors(fluent = true) @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) -public class CompiledByteCode extends SimpleJavaFileObject implements ByteCode { +public class SimpleCompiledClassData extends SimpleJavaFileObject implements CompiledClassData { ByteArrayOutputStream outputStream; @Getter String name; - public CompiledByteCode(String name) { + public SimpleCompiledClassData(String name) { super(URI.create("byte:///" + name.replace('/', '.') + Compiler.CLASS_EXTENSION), Kind.CLASS); this.outputStream = new ByteArrayOutputStream(); this.name = name; @@ -35,6 +35,11 @@ public byte[] byteCode() { return outputStream.toByteArray(); } + @Override + public int size() { + return outputStream.size(); + } + @Override public OutputStream openOutputStream() { return outputStream; diff --git a/rlib-compiler/src/test/java/javasabr/rlib/compiler/CompilerTests.java b/rlib-compiler/src/test/java/javasabr/rlib/compiler/CompilerTests.java index 21057f40..f969ae02 100644 --- a/rlib-compiler/src/test/java/javasabr/rlib/compiler/CompilerTests.java +++ b/rlib-compiler/src/test/java/javasabr/rlib/compiler/CompilerTests.java @@ -16,7 +16,7 @@ public class CompilerTests { static { - LoggerManager.enable(Compiler.class, LoggerLevel.DEBUG); + LoggerManager.configureDefault(LoggerLevel.DEBUG, true); } @Test diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java index 3264d670..bdd0248d 100644 --- a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java @@ -24,12 +24,19 @@ interface N1Factory { } @FunctionalInterface - interface IntN1Factory { + interface IntFactory { @NonNull String make(int arg1); } + @FunctionalInterface + interface IntN1Factory { + + @NonNull + String make(int arg1, F arg2); + } + @FunctionalInterface interface N2Factory { @@ -74,7 +81,7 @@ default void debug(@NonNull String message) { print(LoggerLevel.DEBUG, message); } - default void debug(int arg1, @NonNull IntN1Factory factory) { + default void debug(int arg1, @NonNull IntFactory factory) { print(LoggerLevel.DEBUG, arg1, factory); } @@ -82,6 +89,10 @@ default void debug(T arg1, @NonNull N1Factory factory) { print(LoggerLevel.DEBUG, arg1, factory); } + default void debug(int arg1, F arg2, @NonNull IntN1Factory factory) { + print(LoggerLevel.DEBUG, arg1, arg2, factory); + } + default void debug(F arg1, S arg2, @NonNull N2Factory factory) { print(LoggerLevel.DEBUG, arg1, arg2, factory); } @@ -132,16 +143,12 @@ default boolean enabled(@NonNull LoggerLevel level) { /** * Override the enabling status of the logger level. */ - default boolean overrideEnabled(@NonNull LoggerLevel level, boolean enabled) { - return false; - } + default void overrideEnabled(@NonNull LoggerLevel level, boolean enabled) {} /** * Remove overriding of enabling status if the logger level. */ - default boolean resetToDefault(@NonNull LoggerLevel level) { - return false; - } + default void resetToDefault(@NonNull LoggerLevel level) {} default void warning(@NonNull String message) { print(LoggerLevel.WARNING, message); @@ -178,12 +185,22 @@ default void print(@NonNull LoggerLevel level, T arg1, @NonNull N1Factory } } - default void print(@NonNull LoggerLevel level, int arg1, @NonNull IntN1Factory factory) { + default void print(@NonNull LoggerLevel level, int arg1, @NonNull IntFactory factory) { if (enabled(level)) { print(level, factory.make(arg1)); } } + default void print( + @NonNull LoggerLevel level, + int arg1, + F arg2, + @NonNull IntN1Factory factory) { + if (enabled(level)) { + print(level, factory.make(arg1, arg2)); + } + } + default void print( @NonNull LoggerLevel level, F arg1, diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerManager.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerManager.java index fa8fd9cc..500291f4 100644 --- a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerManager.java +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerManager.java @@ -62,26 +62,50 @@ public static Logger getLogger(String id) { } public static void addListener(LoggerListener listener) { - LOGGER_FACTORY.addListener(listener); + if (LOGGER_FACTORY instanceof LoggerService ls) { + ls.addListener(listener); + } } public static void removeListener(LoggerListener listener) { - LOGGER_FACTORY.removeListener(listener); + if (LOGGER_FACTORY instanceof LoggerService ls) { + ls.removeListener(listener); + } } public static void addWriter(Writer writer) { - LOGGER_FACTORY.addWriter(writer); + if (LOGGER_FACTORY instanceof LoggerService ls) { + ls.addWriter(writer); + } } public static void removeWriter(Writer writer) { - LOGGER_FACTORY.removeWriter(writer); + if (LOGGER_FACTORY instanceof LoggerService ls) { + ls.removeWriter(writer); + } + } + + public static void configureDefault(LoggerLevel level, boolean def) { + if (LOGGER_FACTORY instanceof LoggerService ls) { + ls.configureDefault(level, def); + } + } + + public static void removeDefault(LoggerLevel level) { + if (LOGGER_FACTORY instanceof LoggerService ls) { + ls.removeDefault(level); + } } public static void enable(Class cs, LoggerLevel level) { - getLogger(cs).overrideEnabled(level, true); + if (LOGGER_FACTORY instanceof LoggerService ls) { + ls.enable(cs, level); + } } public static void disable(Class cs, LoggerLevel level) { - getLogger(cs).overrideEnabled(level, false); + if (LOGGER_FACTORY instanceof LoggerService ls) { + ls.disable(cs, level); + } } } diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerService.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerService.java new file mode 100644 index 00000000..feba132a --- /dev/null +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerService.java @@ -0,0 +1,33 @@ +package javasabr.rlib.logger.api; + +import java.io.Writer; + +public interface LoggerService { + + int NOT_CONFIGURE = -1; + int DISABLED = 0; + int ENABLED = 1; + + void addListener(LoggerListener listener); + + void removeListener(LoggerListener listener); + + void addWriter(Writer writer); + + void removeWriter(Writer writer); + + void enable(Class cs, LoggerLevel level); + + void disable(Class cs, LoggerLevel level); + + void configureDefault(LoggerLevel level, boolean def); + + void removeDefault(LoggerLevel level); + + /** + * @return {@link #NOT_CONFIGURE} or {@link #ENABLED} or {@link #DISABLED} + */ + int enabled(LoggerLevel level); + + void write(LoggerLevel level, String loggerName, String logMessage); +} diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java index c5d38cec..db37c3ff 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java @@ -1,9 +1,12 @@ package javasabr.rlib.logger.impl; +import java.util.Arrays; import java.util.Objects; import javasabr.rlib.common.util.StringUtils; +import javasabr.rlib.common.util.array.Array; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; +import javasabr.rlib.logger.api.LoggerService; import lombok.AccessLevel; import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; @@ -16,45 +19,51 @@ public final class DefaultLogger implements Logger { private static final LoggerLevel[] VALUES = LoggerLevel.values(); - @Nullable Boolean[] override; + int[] override; String name; - DefaultLoggerFactory loggerFactory; + LoggerService loggerService; - public DefaultLogger(String name, DefaultLoggerFactory loggerFactory) { + public DefaultLogger(String name, LoggerService loggerService) { this.name = name; - this.loggerFactory = loggerFactory; - this.override = new Boolean[VALUES.length]; + this.loggerService = loggerService; + this.override = new int[DefaultLoggerService.LOGGER_LEVELS.length]; + Arrays.fill(override, LoggerService.NOT_CONFIGURE); } @Override public boolean enabled(LoggerLevel level) { - var value = override[level.ordinal()]; - return Objects.requireNonNullElse(value, level.enabled()); + int value = override[level.ordinal()]; + if (value != LoggerService.NOT_CONFIGURE) { + return value == LoggerService.ENABLED; + } + value = loggerService.enabled(level); + if (value != LoggerService.NOT_CONFIGURE) { + return value == LoggerService.ENABLED; + } + return level.enabled(); } @Override - public boolean overrideEnabled(LoggerLevel level, boolean enabled) { - override[level.ordinal()] = enabled; - return true; + public void overrideEnabled(LoggerLevel level, boolean enabled) { + override[level.ordinal()] = enabled ? LoggerService.ENABLED : LoggerService.DISABLED; } @Override - public boolean resetToDefault(LoggerLevel level) { - override[level.ordinal()] = null; - return true; + public void resetToDefault(LoggerLevel level) { + override[level.ordinal()] = LoggerService.NOT_CONFIGURE; } @Override - public void print(LoggerLevel level, String message) { + public void print(LoggerLevel level, String logMessage) { if (enabled(level)) { - loggerFactory.write(level, name, message); + loggerService.write(level, name, logMessage); } } @Override public void print(LoggerLevel level, Throwable exception) { if (enabled(level)) { - loggerFactory.write(level, name, StringUtils.toString(exception)); + loggerService.write(level, name, StringUtils.toString(exception)); } } } diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerFactory.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerService.java similarity index 68% rename from rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerFactory.java rename to rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerService.java index d5fd6ba8..be5eb0c9 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerFactory.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerService.java @@ -6,6 +6,7 @@ import java.io.Writer; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.Arrays; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javasabr.rlib.common.util.array.Array; @@ -14,6 +15,7 @@ import javasabr.rlib.logger.api.LoggerFactory; import javasabr.rlib.logger.api.LoggerLevel; import javasabr.rlib.logger.api.LoggerListener; +import javasabr.rlib.logger.api.LoggerService; import lombok.AccessLevel; import lombok.experimental.FieldDefaults; @@ -23,7 +25,9 @@ * @author JavaSaBr */ @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) -public class DefaultLoggerFactory implements LoggerFactory { +public class DefaultLoggerService implements LoggerFactory, LoggerService { + + static final LoggerLevel[] LOGGER_LEVELS = LoggerLevel.values(); ConcurrentMap loggers; Array listeners; @@ -31,13 +35,16 @@ public class DefaultLoggerFactory implements LoggerFactory { Logger logger; DateTimeFormatter timeFormatter; + int[] override; - public DefaultLoggerFactory() { + public DefaultLoggerService() { this.loggers = new ConcurrentHashMap<>(); this.logger = new DefaultLogger("", this); this.timeFormatter = DateTimeFormatter.ofPattern("d.MM.yyyy HH:mm:ss:SSS"); this.listeners = ArrayFactory.newCopyOnModifyArray(LoggerListener.class); this.writers = ArrayFactory.newCopyOnModifyArray(Writer.class); + this.override = new int[LOGGER_LEVELS.length]; + Arrays.fill(override, NOT_CONFIGURE); } @Override @@ -80,18 +87,44 @@ public void removeWriter(Writer writer) { writers.remove(writer); } - void write(LoggerLevel level, String name, String message) { + @Override + public void enable(Class cs, LoggerLevel level) { + make(cs).overrideEnabled(level, true); + } + + @Override + public void disable(Class cs, LoggerLevel level) { + make(cs).overrideEnabled(level, false); + } + + @Override + public void configureDefault(LoggerLevel level, boolean def) { + override[level.ordinal()] = def ? ENABLED : DISABLED; + } + + @Override + public void removeDefault(LoggerLevel level) { + override[level.ordinal()] = NOT_CONFIGURE; + } + + @Override + public int enabled(LoggerLevel level) { + return override[level.ordinal()]; + } + + @Override + public void write(LoggerLevel level, String loggerName, String logMessage) { - var timeStamp = timeFormatter.format(LocalDateTime.now()); - var result = level.title() + level.offset() + ' ' + timeStamp + ' ' + name + ": " + message; + var timestamp = timeFormatter.format(LocalDateTime.now()); + var resultMessage = level.title() + level.offset() + ' ' + timestamp + ' ' + loggerName + ": " + logMessage; - write(level, result); + write(level, resultMessage); } private void write(LoggerLevel level, String resultMessage) { listeners.forEachR(resultMessage, LoggerListener::println); - writers.forEachR(resultMessage, DefaultLoggerFactory::append); + writers.forEachR(resultMessage, DefaultLoggerService::append); switch (level) { case INFO, DEBUG -> System.out.println(resultMessage); @@ -103,7 +136,7 @@ private void write(LoggerLevel level, String resultMessage) { } listeners.forEach(LoggerListener::flush); - writers.forEach(DefaultLoggerFactory::flush); + writers.forEach(DefaultLoggerService::flush); } private static void append(Writer writer, String toWrite) { diff --git a/rlib-logger-impl/src/main/resources/META-INF/services/javasabr.rlib.logger.api.LoggerFactory b/rlib-logger-impl/src/main/resources/META-INF/services/javasabr.rlib.logger.api.LoggerFactory index 2b061257..05a43c4d 100644 --- a/rlib-logger-impl/src/main/resources/META-INF/services/javasabr.rlib.logger.api.LoggerFactory +++ b/rlib-logger-impl/src/main/resources/META-INF/services/javasabr.rlib.logger.api.LoggerFactory @@ -1 +1 @@ -javasabr.rlib.logger.impl.DefaultLoggerFactory \ No newline at end of file +javasabr.rlib.logger.impl.DefaultLoggerService \ No newline at end of file From 546760267107a5ad2e051bf50bb30a47c0cadb42 Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 10 Aug 2025 16:20:22 +0200 Subject: [PATCH 4/6] work on extracting io module --- .../classpath/impl/ClassPathScannerImpl.java | 4 +- .../javasabr/rlib/common/util/VarTable.java | 1 - .../rlib/common/util/random/Random.java | 2 - .../common/util/random/RandomFactory.java | 2 - .../compiler/impl/CompileEventListener.java | 1 - .../impl/CompiledClassesClassLoader.java | 2 +- .../rlib/compiler/impl/JdkCompiler.java | 2 +- rlib-io/build.gradle | 5 + .../javasabr/rlib}/io/ReusableStream.java | 13 +- .../io/impl/RedirectImageOutputStream.java | 45 +- .../rlib}/io/impl/ReuseBytesInputStream.java | 48 +- .../rlib}/io/impl/ReuseBytesOutputStream.java | 60 +- .../javasabr/rlib/io/impl/package-info.java | 4 + .../java/javasabr/rlib/io/package-info.java | 4 + .../javasabr/rlib/io}/util/FileUtils.java | 540 ++++-------------- .../java/javasabr/rlib/io/util/IoUtils.java | 54 +- .../javasabr/rlib/io/util/package-info.java | 4 + .../rlib/logger/impl/DefaultLogger.java | 3 - settings.gradle | 3 +- 19 files changed, 201 insertions(+), 596 deletions(-) create mode 100644 rlib-io/build.gradle rename {rlib-common/src/main/java/javasabr/rlib/common => rlib-io/src/main/java/javasabr/rlib}/io/ReusableStream.java (52%) rename {rlib-common/src/main/java/javasabr/rlib/common => rlib-io/src/main/java/javasabr/rlib}/io/impl/RedirectImageOutputStream.java (53%) rename {rlib-common/src/main/java/javasabr/rlib/common => rlib-io/src/main/java/javasabr/rlib}/io/impl/ReuseBytesInputStream.java (65%) rename {rlib-common/src/main/java/javasabr/rlib/common => rlib-io/src/main/java/javasabr/rlib}/io/impl/ReuseBytesOutputStream.java (68%) create mode 100644 rlib-io/src/main/java/javasabr/rlib/io/impl/package-info.java create mode 100644 rlib-io/src/main/java/javasabr/rlib/io/package-info.java rename {rlib-common/src/main/java/javasabr/rlib/common => rlib-io/src/main/java/javasabr/rlib/io}/util/FileUtils.java (59%) rename rlib-common/src/main/java/javasabr/rlib/common/util/IOUtils.java => rlib-io/src/main/java/javasabr/rlib/io/util/IoUtils.java (63%) create mode 100644 rlib-io/src/main/java/javasabr/rlib/io/util/package-info.java diff --git a/rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/ClassPathScannerImpl.java b/rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/ClassPathScannerImpl.java index f8a1925c..be89a64a 100644 --- a/rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/ClassPathScannerImpl.java +++ b/rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/ClassPathScannerImpl.java @@ -15,8 +15,8 @@ import java.util.jar.JarInputStream; import java.util.zip.ZipException; import javasabr.rlib.classpath.ClassPathScanner; -import javasabr.rlib.common.io.impl.ReuseBytesInputStream; -import javasabr.rlib.common.io.impl.ReuseBytesOutputStream; +import javasabr.rlib.io.impl.ReuseBytesInputStream; +import javasabr.rlib.io.impl.ReuseBytesOutputStream; import javasabr.rlib.common.util.ArrayUtils; import javasabr.rlib.common.util.IOUtils; import javasabr.rlib.common.util.array.Array; diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/VarTable.java b/rlib-common/src/main/java/javasabr/rlib/common/util/VarTable.java index 7eb1daea..2a950028 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/VarTable.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/VarTable.java @@ -1,6 +1,5 @@ package javasabr.rlib.common.util; -import static java.lang.Float.parseFloat; import static javasabr.rlib.common.util.ObjectUtils.notNull; import javasabr.rlib.common.util.dictionary.DictionaryFactory; diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/random/Random.java b/rlib-common/src/main/java/javasabr/rlib/common/util/random/Random.java index 0291bc5b..066bdcd3 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/random/Random.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/random/Random.java @@ -1,7 +1,5 @@ package javasabr.rlib.common.util.random; -import org.jspecify.annotations.NullMarked; - /** * The interface to implement a random. * diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/random/RandomFactory.java b/rlib-common/src/main/java/javasabr/rlib/common/util/random/RandomFactory.java index 3d2c3c42..960c2ca3 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/random/RandomFactory.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/random/RandomFactory.java @@ -1,7 +1,5 @@ package javasabr.rlib.common.util.random; -import org.jspecify.annotations.NullMarked; - /** * The factory of randoms implementations. * diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompileEventListener.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompileEventListener.java index a2bfc702..6e14463b 100644 --- a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompileEventListener.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompileEventListener.java @@ -1,7 +1,6 @@ package javasabr.rlib.compiler.impl; import javasabr.rlib.common.util.array.Array; -import javasabr.rlib.common.util.array.ArrayFactory; import javax.tools.Diagnostic; import javax.tools.DiagnosticListener; import javax.tools.JavaFileObject; diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledClassesClassLoader.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledClassesClassLoader.java index 5a2ed949..0ecfb855 100644 --- a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledClassesClassLoader.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/CompiledClassesClassLoader.java @@ -1,8 +1,8 @@ package javasabr.rlib.compiler.impl; -import javasabr.rlib.compiler.CompiledClassData; import javasabr.rlib.common.util.Utils; import javasabr.rlib.common.util.array.Array; +import javasabr.rlib.compiler.CompiledClassData; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerManager; import lombok.AccessLevel; diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java index b37176b9..d551b69d 100644 --- a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java @@ -4,9 +4,9 @@ import java.nio.file.Files; import java.nio.file.Path; import javasabr.rlib.common.util.FileUtils; -import javasabr.rlib.compiler.Compiler; import javasabr.rlib.common.util.array.Array; import javasabr.rlib.common.util.array.ArrayCollectors; +import javasabr.rlib.compiler.Compiler; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerManager; import javax.tools.Diagnostic; diff --git a/rlib-io/build.gradle b/rlib-io/build.gradle new file mode 100644 index 00000000..f8325ab9 --- /dev/null +++ b/rlib-io/build.gradle @@ -0,0 +1,5 @@ + +dependencies { + api projects.rlibCommon + testImplementation projects.rlibLoggerImpl +} \ No newline at end of file diff --git a/rlib-common/src/main/java/javasabr/rlib/common/io/ReusableStream.java b/rlib-io/src/main/java/javasabr/rlib/io/ReusableStream.java similarity index 52% rename from rlib-common/src/main/java/javasabr/rlib/common/io/ReusableStream.java rename to rlib-io/src/main/java/javasabr/rlib/io/ReusableStream.java index 3dc3a257..ab74de83 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/io/ReusableStream.java +++ b/rlib-io/src/main/java/javasabr/rlib/io/ReusableStream.java @@ -1,25 +1,16 @@ -package javasabr.rlib.common.io; +package javasabr.rlib.io; import java.io.IOException; -import org.jspecify.annotations.NullMarked; /** - * The interface to implement a reusable streams. - * * @author JavaSaBr */ -@NullMarked public interface ReusableStream { - /** - * Reset this stream. - * - * @throws IOException the io exception - */ void reset() throws IOException; /** - * Initialize this string using the buffer. + * Initialize this stream to use the buffer. * * @param buffer the buffer data. * @param offset the offset. diff --git a/rlib-common/src/main/java/javasabr/rlib/common/io/impl/RedirectImageOutputStream.java b/rlib-io/src/main/java/javasabr/rlib/io/impl/RedirectImageOutputStream.java similarity index 53% rename from rlib-common/src/main/java/javasabr/rlib/common/io/impl/RedirectImageOutputStream.java rename to rlib-io/src/main/java/javasabr/rlib/io/impl/RedirectImageOutputStream.java index 16dea634..94e693a3 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/io/impl/RedirectImageOutputStream.java +++ b/rlib-io/src/main/java/javasabr/rlib/io/impl/RedirectImageOutputStream.java @@ -1,33 +1,28 @@ -package javasabr.rlib.common.io.impl; +package javasabr.rlib.io.impl; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.imageio.stream.ImageOutputStreamImpl; -import org.jspecify.annotations.NullMarked; +import lombok.AccessLevel; +import lombok.Setter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; /** - * The implementation of a redirector image input stream. - * * @author JavaSaBr */ -@NullMarked +@Setter +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED) public class RedirectImageOutputStream extends ImageOutputStreamImpl { - /** - * The output stream. - */ - private @Nullable OutputStream out; - - /** - * The input stream. - */ - private @Nullable InputStream in; + @Nullable OutputStream out; + @Nullable InputStream in; @Override - public void close() throws IOException { - } + public void close() throws IOException {} @Override public int read() throws IOException { @@ -39,24 +34,6 @@ public int read(byte[] b, int off, int len) throws IOException { return in.read(b, off, len); } - /** - * Sets in. - * - * @param in the input stream. - */ - public void setIn(InputStream in) { - this.in = in; - } - - /** - * Sets out. - * - * @param out the output stream. - */ - public void setOut(OutputStream out) { - this.out = out; - } - @Override public void write(byte[] b, int off, int len) throws IOException { out.write(b, off, len); diff --git a/rlib-common/src/main/java/javasabr/rlib/common/io/impl/ReuseBytesInputStream.java b/rlib-io/src/main/java/javasabr/rlib/io/impl/ReuseBytesInputStream.java similarity index 65% rename from rlib-common/src/main/java/javasabr/rlib/common/io/impl/ReuseBytesInputStream.java rename to rlib-io/src/main/java/javasabr/rlib/io/impl/ReuseBytesInputStream.java index 955d7dba..55cfa96f 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/io/impl/ReuseBytesInputStream.java +++ b/rlib-io/src/main/java/javasabr/rlib/io/impl/ReuseBytesInputStream.java @@ -1,32 +1,20 @@ -package javasabr.rlib.common.io.impl; +package javasabr.rlib.io.impl; import java.io.InputStream; -import javasabr.rlib.common.io.ReusableStream; import javasabr.rlib.common.util.ArrayUtils; -import org.jspecify.annotations.NullMarked; +import javasabr.rlib.io.ReusableStream; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; /** - * The implementation of reusable input stream. - * * @author JavaSaBr */ -@NullMarked +@FieldDefaults(level = AccessLevel.PROTECTED) public final class ReuseBytesInputStream extends InputStream implements ReusableStream { - /** - * The data buffer. - */ - protected byte[] buffer; - - /** - * The position. - */ - protected int pos; - - /** - * The count bytes. - */ - protected int count; + byte[] buffer; + int position; + int count; public ReuseBytesInputStream() { this.buffer = ArrayUtils.EMPTY_BYTE_ARRAY; @@ -34,26 +22,26 @@ public ReuseBytesInputStream() { public ReuseBytesInputStream(byte buffer[]) { this.buffer = buffer; - this.pos = 0; + this.position = 0; this.count = buffer.length; } public ReuseBytesInputStream(byte[] buffer, int offset, int length) { this.buffer = buffer; - this.pos = offset; + this.position = offset; this.count = Math.min(offset + length, buffer.length); } @Override public void initFor(byte[] buffer, int offset, int length) { this.buffer = buffer; - this.pos = offset; + this.position = offset; this.count = length; } @Override public synchronized int read() { - return (pos < count) ? (buffer[pos++] & 0xff) : -1; + return (position < count) ? (buffer[position++] & 0xff) : -1; } @Override @@ -63,11 +51,11 @@ public synchronized int read(byte[] buffer, int offset, int length) { throw new IndexOutOfBoundsException(); } - if (pos >= count) { + if (position >= count) { return -1; } - int available = count - pos; + int available = count - position; if (length > available) { length = available; @@ -77,15 +65,15 @@ public synchronized int read(byte[] buffer, int offset, int length) { return 0; } - System.arraycopy(this.buffer, pos, buffer, offset, length); - pos += length; + System.arraycopy(this.buffer, position, buffer, offset, length); + position += length; return length; } @Override public synchronized int available() { - return count - pos; + return count - position; } @Override @@ -93,6 +81,6 @@ public void close() {} @Override public synchronized void reset() { - this.pos = 0; + this.position = 0; } } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/io/impl/ReuseBytesOutputStream.java b/rlib-io/src/main/java/javasabr/rlib/io/impl/ReuseBytesOutputStream.java similarity index 68% rename from rlib-common/src/main/java/javasabr/rlib/common/io/impl/ReuseBytesOutputStream.java rename to rlib-io/src/main/java/javasabr/rlib/io/impl/ReuseBytesOutputStream.java index a3dd12e1..d06083b1 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/io/impl/ReuseBytesOutputStream.java +++ b/rlib-io/src/main/java/javasabr/rlib/io/impl/ReuseBytesOutputStream.java @@ -1,28 +1,24 @@ -package javasabr.rlib.common.io.impl; +package javasabr.rlib.io.impl; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.Arrays; -import javasabr.rlib.common.io.ReusableStream; -import org.jspecify.annotations.NullMarked; +import javasabr.rlib.io.ReusableStream; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; /** - * The implementation of reusable output stream. - * * @author JavaSaBr */ -@NullMarked +@Getter +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED) public final class ReuseBytesOutputStream extends OutputStream implements ReusableStream { - /** - * The data buffer. - */ - protected byte[] data; - - /** - * The size of stream. - */ - protected int size; + byte[] data; + int size; public ReuseBytesOutputStream() { this(32); @@ -46,11 +42,6 @@ public void initFor(byte[] buffer, int offset, int length) { this.size = length; } - /** - * Check needing resizing the buffer. - * - * @param minCapacity the min capacity. - */ private void checkLength(int minCapacity) { if (minCapacity - data.length > 0) { resizeData(minCapacity); @@ -58,28 +49,13 @@ private void checkLength(int minCapacity) { } @Override - public void close() { - } - - /** - * Get the wrapped data array. - * - * @return the wrapped data array. - */ - public byte[] getData() { - return data; - } + public void close() {} @Override public void reset() { size = 0; } - /** - * Resize the data buffer. - * - * @param minCapacity the min capacity. - */ private void resizeData(int minCapacity) { int oldCapacity = data.length; @@ -101,11 +77,6 @@ private void resizeData(int minCapacity) { data = Arrays.copyOf(data, newCapacity); } - /** - * Get the current size. - * - * @return the current size. - */ public int size() { return size; } @@ -115,13 +86,6 @@ public String toString() { return new String(data, 0, size); } - /** - * To string string. - * - * @param charsetName the charset name - * @return the string - * @throws UnsupportedEncodingException the unsupported encoding exception - */ public String toString(String charsetName) throws UnsupportedEncodingException { return new String(data, 0, size, charsetName); } diff --git a/rlib-io/src/main/java/javasabr/rlib/io/impl/package-info.java b/rlib-io/src/main/java/javasabr/rlib/io/impl/package-info.java new file mode 100644 index 00000000..6164e276 --- /dev/null +++ b/rlib-io/src/main/java/javasabr/rlib/io/impl/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.io.impl; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-io/src/main/java/javasabr/rlib/io/package-info.java b/rlib-io/src/main/java/javasabr/rlib/io/package-info.java new file mode 100644 index 00000000..f0181b5b --- /dev/null +++ b/rlib-io/src/main/java/javasabr/rlib/io/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.io; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/FileUtils.java b/rlib-io/src/main/java/javasabr/rlib/io/util/FileUtils.java similarity index 59% rename from rlib-common/src/main/java/javasabr/rlib/common/util/FileUtils.java rename to rlib-io/src/main/java/javasabr/rlib/io/util/FileUtils.java index 883d8b85..fca12ce6 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/FileUtils.java +++ b/rlib-io/src/main/java/javasabr/rlib/io/util/FileUtils.java @@ -1,15 +1,12 @@ -package javasabr.rlib.common.util; +package javasabr.rlib.io.util; import static javasabr.rlib.common.util.ObjectUtils.notNull; -import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.UncheckedIOException; import java.net.URI; import java.net.URL; -import java.nio.CharBuffer; import java.nio.file.DirectoryStream; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; @@ -26,24 +23,20 @@ import java.nio.file.attribute.FileTime; import java.util.Collection; import java.util.Enumeration; -import java.util.Objects; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Stream; import java.util.zip.ZipInputStream; +import javasabr.rlib.common.util.ArrayUtils; +import javasabr.rlib.common.util.StringUtils; +import javasabr.rlib.common.util.Utils; import javasabr.rlib.common.util.array.Array; import javasabr.rlib.common.util.array.ArrayComparator; import javasabr.rlib.common.util.array.ArrayFactory; -import javasabr.rlib.common.util.array.UnsafeArray; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerManager; import org.jspecify.annotations.Nullable; /** - * The utility class. - * * @author JavaSaBr */ public class FileUtils { @@ -99,13 +92,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO private static final Path[] EMPTY_PATHS = new Path[0]; - /** - * Check a string on valid file name. - * - * @param filename the file name. - * @return true if the file name is valid. - */ - public static boolean isValidName(@Nullable String filename) { + public static boolean isValidFileName(@Nullable String filename) { if (StringUtils.isEmpty(filename)) { return false; @@ -117,10 +104,7 @@ public static boolean isValidName(@Nullable String filename) { } /** - * Normalize the file name to a valid file name. - * - * @param filename the string with file name. - * @return normalized file name. + * Normalize the file name to an invalid file name. */ public static String normalizeName(@Nullable String filename) { @@ -133,7 +117,66 @@ public static String normalizeName(@Nullable String filename) { .replaceAll("_"); } - public static void addFilesTo( + + + public static Array getFiles(Path directory, String @Nullable ... extensions) { + return getFiles(directory, false, extensions); + } + + public static Array getFiles( + Path directory, + boolean includeDirectoriesToResult, + String @Nullable ... extensions) { + Array result = ArrayFactory.newArray(Path.class); + collectFilesTo(result, directory, includeDirectoriesToResult, extensions); + return result; + } + + public static Path[] getFiles(Package pckg, String @Nullable ... extensions) { + + ClassLoader classLoader = Thread + .currentThread() + .getContextClassLoader(); + + Enumeration urls = null; + try { + urls = classLoader.getResources(pckg + .getName() + .replace('.', '/')); + } catch (IOException exc) { + LoggerManager + .getDefaultLogger() + .warning(exc); + } + + if (urls == null) { + return EMPTY_PATHS; + } + + var files = Array.ofType(Path.class); + + while (urls.hasMoreElements()) { + + var next = urls.nextElement(); + var path = next.getFile(); + + if (path.contains("%20")) { + path = path.replaceAll("%20", " "); + } + + var file = Paths.get(path); + + if (Files.isDirectory(file)) { + files.addAll(getFiles(file, extensions)); + } else if (extensions == null || extensions.length < 1 || hasExtensions(path, extensions)) { + files.add(file); + } + } + + return files.toArray(Path.class); + } + + public static void collectFilesTo( Array container, Path directory, boolean includeDirectoriesToResult, @@ -153,7 +196,7 @@ public static void addFilesTo( try (DirectoryStream stream = Files.newDirectoryStream(directory)) { for (Path file : stream) { if (Files.isDirectory(file)) { - addFilesTo(container, file, includeDirectoriesToResult, extensions); + collectFilesTo(container, file, includeDirectoriesToResult, extensions); continue; } @@ -167,86 +210,51 @@ public static void addFilesTo( } } + @Nullable public static String fileName(Path file) { - return file.getFileName().toString(); + Path fileName = file.getFileName(); + return fileName == null ? null : fileName.toString(); } public static boolean hasExtension(Path file, String extension) { - return fileName(file).endsWith(extension); + String fileName = fileName(file); + return fileName != null && fileName.endsWith(extension); } - public static boolean hasExtensions(Path fileName, String @Nullable [] extensions) { - return hasExtensions(fileName.toString(), extensions); + public static boolean hasExtensions(Path file, String @Nullable [] extensions) { + return hasExtensions(file.toString(), extensions); } - public static boolean hasExtensions(String fileName, String @Nullable [] extensions) { - return ArrayUtils.anyMatchR(extensions, fileName, String::endsWith); + public static boolean hasExtensions(Path file, @Nullable Array extensions) { + return hasExtensions(file.toString(), extensions); } - /** - * Check the extensions of the file. - * - * @param extensions the checked extensions. - * @param path the file. - * @return true if the file has a checked extension. - */ - public static boolean hasExtensions(@Nullable Array extensions, Path path) { - return hasExtensions(extensions, path.toString()); + public static boolean hasExtensions(Path file, @Nullable Collection extensions) { + return hasExtensions(file.toString(), extensions); } - /** - * Check the extensions of the path. - * - * @param extensions the checked extensions. - * @param path the path. - * @return true if the path has a checked extension. - */ - public static boolean hasExtensions(@Nullable Array extensions, String path) { - return extensions != null && extensions.anyMatchR(path, String::endsWith); + public static boolean hasExtensions(String path, String @Nullable [] extensions) { + return ArrayUtils.anyMatchR(extensions, path, String::endsWith); } - /** - * Check the extensions of the file. - * - * @param extensions the checked extensions. - * @param path the file. - * @return true if the file has a checked extension. - */ - public static boolean hasExtensions(@Nullable Collection extensions, Path path) { - return hasExtensions(extensions, path.toString()); + public static boolean hasExtensions(String path, @Nullable Array extensions) { + return extensions != null && extensions.anyMatchR(path, String::endsWith); } - /** - * Check the extensions of the path. - * - * @param extensions the checked extensions. - * @param path the path. - * @return true if the path has a checked extension. - */ - public static boolean hasExtensions(@Nullable Collection extensions, String path) { + public static boolean hasExtensions(String path, @Nullable Collection extensions) { return extensions != null && extensions .stream() .anyMatch(path::endsWith); } - /** - * Delete the file. - * - * @param path the file to delete. - */ - public static void delete(Path path) { + public static void delete(Path file) { try { - deleteImpl(path); + deleteImpl(file); } catch (IOException e) { throw new UncheckedIOException(e); } } - /** - * Delete the file or the folder. - * - * @param path the file or folder. - */ private static void deleteImpl(Path path) throws IOException { if (!Files.isDirectory(path)) { Files.delete(path); @@ -255,66 +263,47 @@ private static void deleteImpl(Path path) throws IOException { } } - /** - * Get an extension of the path. - * - * @param path the path. - * @return the extension or the path if the path doesn't have an extension. - */ - public static String getExtension(@Nullable String path) { - return getExtension(path, false); - } - - /** - * Check the path about existing an extension. - * - * @param path the path. - * @return true if the path contains any extension. - */ public static boolean hasExtension(@Nullable String path) { if (StringUtils.isEmpty(path)) { return false; } - var index = path.lastIndexOf('.'); - + int index = path.lastIndexOf('.'); if (index == -1) { return false; } var separatorIndex = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\')); - return separatorIndex < index; } /** - * Get an extension of the path. - * - * @param path the path. - * @param toLowerCase true if need that extension was only in lower case. - * @return the extension or empty string. + * Get an extension of the path or empty string. */ + @Nullable + public static String getExtension(@Nullable String path) { + return getExtension(path, false); + } + + @Nullable public static String getExtension(@Nullable String path, boolean toLowerCase) { if (StringUtils.isEmpty(path)) { - return StringUtils.EMPTY; + return null; } - var index = path.lastIndexOf('.'); - + int index = path.lastIndexOf('.'); if (index == -1) { - return StringUtils.EMPTY; + return null; } - var separatorIndex = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\')); - + int separatorIndex = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\')); if (separatorIndex > index) { - return StringUtils.EMPTY; + return null; } - var result = path.substring(index + 1); - + String result = path.substring(index + 1); if (toLowerCase) { return result.toLowerCase(); } @@ -322,250 +311,65 @@ public static String getExtension(@Nullable String path, boolean toLowerCase) { return result; } - /** - * Get an extension of the file. - * - * @param file the file. - * @return the extension or empty string. - */ + @Nullable public static String getExtension(Path file) { if (Files.isDirectory(file)) { - return StringUtils.EMPTY; + return null; } - return getExtension(Objects.toString(file.getFileName())); + return getExtension(fileName(file)); } - /** - * Get an extension of the file. - * - * @param file the file. - * @param toLowerCase true if need that extension was only in lower case. - * @return the extension or empty string. - */ + @Nullable public static String getExtension(Path file, boolean toLowerCase) { if (Files.isDirectory(file)) { - return StringUtils.EMPTY; - } - - return getExtension(Objects.toString(file.getFileName()), toLowerCase); - } - - /** - * Recursive get all files of the folder. - * - * @param dir the folder. - * @param extensions the extension filter. - * @return the list of all files. - */ - public static Array getFiles(Path dir, String @Nullable ... extensions) { - return getFiles(dir, false, extensions); - } - - /** - * Recursive get all files of the folder. - * - * @param dir the folder. - * @param withFolders need include folders. - * @param extensions the extension filter. - * @return the list of all files. - */ - public static Array getFiles(Path dir, boolean withFolders, String @Nullable ... extensions) { - - Array result = ArrayFactory.newArray(Path.class); - - addFilesTo(result, dir, withFolders, extensions); - - UnsafeArray unsafeArray = result.asUnsafe(); - unsafeArray.trimToSize(); - - return result; - } - - /** - * Get all files in the package. - * - * @param pckg the package. - * @param extensions the extensions filter. - * @return the array of files. - */ - public static Path[] getFiles(Package pckg, String @Nullable ... extensions) { - - ClassLoader classLoader = Thread - .currentThread() - .getContextClassLoader(); - - Enumeration urls = null; - try { - urls = classLoader.getResources(pckg - .getName() - .replace('.', '/')); - } catch (IOException exc) { - LoggerManager - .getDefaultLogger() - .warning(exc); - } - - if (urls == null) { - return EMPTY_PATHS; - } - - var files = Array.ofType(Path.class); - - while (urls.hasMoreElements()) { - - var next = urls.nextElement(); - var path = next.getFile(); - - if (path.contains("%20")) { - path = path.replaceAll("%20", " "); - } - - var file = Paths.get(path); - - if (Files.isDirectory(file)) { - files.addAll(getFiles(file, extensions)); - } else if (extensions == null || extensions.length < 1 || hasExtensions(path, extensions)) { - files.add(file); - } + return null; } - return files.toArray(Path.class); + return getExtension(fileName(file), toLowerCase); } - /** - * Get a file name without extension. - * - * @param filename the file name. - * @return the file name without extension. - */ - public static String getNameWithoutExtension(String filename) { + @Nullable + public static String getNameWithoutExtension(@Nullable String fileName) { - if (StringUtils.isEmpty(filename)) { - return filename; + if (StringUtils.isEmpty(fileName)) { + return fileName; } - int index = filename.lastIndexOf('.'); - + int index = fileName.lastIndexOf('.'); if (index == -1) { - return filename; + return fileName; } - return filename.substring(0, index); + return fileName.substring(0, index); } - /** - * Get a file name without extension. - * - * @param file the file. - * @return the file name without extension. - */ + @Nullable public static String getNameWithoutExtension(Path file) { - - String filename = file - .getFileName() - .toString(); - - if (StringUtils.isEmpty(filename)) { - return filename; - } - - int index = filename.lastIndexOf('.'); - - if (index == -1) { - return filename; - } - - return filename.substring(0, index); + return getNameWithoutExtension(fileName(file)); } - /** - * Read the file as a string from classpath. - * - * @param path the path to file. - * @return the string content of the file. - */ + @Nullable public static String readFromClasspath(String path) { - return read(FileUtils.class.getResourceAsStream(path)); + return readFromClasspath(FileUtils.class, path); } /** * Read the file as a string from classpath. - * - * @param cs the class to get a classloader. - * @param path the path to file. - * @return the string content of the file. */ + @Nullable public static String readFromClasspath(Class cs, String path) { - return read(cs.getResourceAsStream(path)); - } - - /** - * Read the file as a string. - * - * @param path the path to file. - * @return the string content of the file. - */ - public static String read(String path) { - try { - return read(Files.newInputStream(Paths.get(path))); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - /** - * Read the input stream as a string. - * - * @param in the input stream. - * @return the string content of the input stream. - */ - public static String read(InputStream in) { - - var content = new StringBuilder(); - - try (var reader = new BufferedReader(new InputStreamReader(in))) { - - var buffer = CharBuffer.allocate(512); - - while (reader.ready()) { - - buffer.clear(); - reader.read(buffer); - buffer.flip(); - - content.append(buffer.array(), 0, buffer.limit()); - } - - } catch (IOException e) { - throw new UncheckedIOException(e); - } - - return content.toString(); - } - - /** - * Read the file as a string. - * - * @param file the file. - * @return the string content of the file. - */ - public static String read(Path file) { - try { - return read(Files.newInputStream(file)); - } catch (IOException e) { - throw new UncheckedIOException(e); + InputStream inputStream = cs.getResourceAsStream(path); + if (inputStream != null) { + return IoUtils.toString(inputStream); } + return null; } /** * Find a first free file name in the directory. - * - * @param directory the directory. - * @param file the checked file. - * @return the first free name. */ public static String getFirstFreeName(Path directory, Path file) { @@ -606,7 +410,7 @@ public static void unzip(Path destination, Path zipFile) { String entryName = entry.getName(); Path targetFile = destination .resolve(entryName) - .normalize(); + .toRealPath(LinkOption.NOFOLLOW_LINKS); if (!targetFile.startsWith(destination)) { LOGGER.warning(entryName, "Unexpected entry name:[%s] which is outside"::formatted); @@ -639,12 +443,11 @@ public static String getName(String path, char separator) { } int index = path.lastIndexOf(separator); - if (index == -1) { return path; } - return path.substring(index + 1, path.length()); + return path.substring(index + 1); } /** @@ -661,7 +464,6 @@ public static String getParent(String path, char separator) { } int index = path.lastIndexOf(separator); - if (index == -1) { return path; } @@ -790,24 +592,6 @@ public static Path createTempFile( } } - /** - * Apply each sub-file of the directory to the consumer. - * - * @param directory the directory. - * @param consumer the consumer. - */ - public static void forEach(Path directory, Consumer consumer) { - validateDirectory(directory); - - try (var stream = Files.newDirectoryStream(directory)) { - for (var path : stream) { - consumer.accept(path); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - private static void validateDirectory(Path directory) { if (!Files.isDirectory(directory)) { throw new IllegalArgumentException("The file " + directory + " isn't a directory."); @@ -816,35 +600,7 @@ private static void validateDirectory(Path directory) { } } - /** - * Apply each sub-file of the directory to the consumer. - * - * @param directory the directory. - * @param argument the argument. - * @param consumer the consumer. - * @param the argument's type. - */ - public static void forEach( - Path directory, - T argument, - BiConsumer consumer) { - validateDirectory(directory); - - try (var stream = Files.newDirectoryStream(directory)) { - for (var path : stream) { - consumer.accept(path, argument); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - /** - * Get children's stream of the directory. - * - * @param directory the directory. - * @return children's stream of the directory. - */ public static Stream stream(Path directory) { validateDirectory(directory); @@ -858,54 +614,4 @@ public static Stream stream(Path directory) { return files.stream(); } - - /** - * Apply each sub-file of the directory to the consumer. - * - * @param directory the directory. - * @param argument the argument. - * @param consumer the consumer. - * @param the argument's type. - */ - public static void forEachR( - Path directory, - T argument, - BiConsumer consumer) { - validateDirectory(directory); - - try (var stream = Files.newDirectoryStream(directory)) { - for (var path : stream) { - consumer.accept(argument, path); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - /** - * Apply each sub-file of the directory to the consumer. - * - * @param directory the directory. - * @param argument the argument. - * @param condition the condition. - * @param consumer the consumer. - * @param the argument's type. - */ - public static void forEachR( - Path directory, - T argument, - Predicate condition, - BiConsumer consumer) { - validateDirectory(directory); - - try (var stream = Files.newDirectoryStream(directory)) { - for (var path : stream) { - if (condition.test(path)) { - consumer.accept(argument, path); - } - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/IOUtils.java b/rlib-io/src/main/java/javasabr/rlib/io/util/IoUtils.java similarity index 63% rename from rlib-common/src/main/java/javasabr/rlib/common/util/IOUtils.java rename to rlib-io/src/main/java/javasabr/rlib/io/util/IoUtils.java index ce6c4f79..cc3dba84 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/IOUtils.java +++ b/rlib-io/src/main/java/javasabr/rlib/io/util/IoUtils.java @@ -1,4 +1,4 @@ -package javasabr.rlib.common.util; +package javasabr.rlib.io.util; import static java.lang.ThreadLocal.withInitial; @@ -11,31 +11,24 @@ import java.io.UncheckedIOException; import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; -import javasabr.rlib.common.function.SafeSupplier; -import org.jspecify.annotations.NullMarked; +import java.util.function.Supplier; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; /** - * The class with utility methods. - * * @author JavaSaBr */ -@NullMarked -public final class IOUtils { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class IoUtils { private static final ThreadLocal LOCAL_CHAR_BUFFER = withInitial(() -> new char[1024]); - /** - * Close a closeable object. - * - * @param closeable the closeable object. - */ public static void close(@Nullable Closeable closeable) { - if (closeable == null) { return; } - try { closeable.close(); } catch (IOException e) { @@ -45,10 +38,6 @@ public static void close(@Nullable Closeable closeable) { /** * Convert the input stream to a string using UTF-8 encoding. - * - * @param in the input stream. - * @return the result string. - * @throws UncheckedIOException if input stream thrown an io exception. */ public static String toString(InputStream in) { @@ -65,17 +54,12 @@ public static String toString(InputStream in) { /** * Convert the input stream to a string using UTF-8 encoding. - * - * @param inFactory the input stream. - * @return the result string. - * @throws UncheckedIOException if input stream thrown an io exception. - * @throws RuntimeException if happened something wrong with the supplier. */ - public static String toString(SafeSupplier inFactory) { + public static String toString(Supplier<@NonNull InputStream> factory) { var result = new StringBuilder(); - try (var reader = new InputStreamReader(inFactory.get(), StandardCharsets.UTF_8)) { + try (var reader = new InputStreamReader(factory.get(), StandardCharsets.UTF_8)) { toString(result, reader); } catch (IOException e) { throw new UncheckedIOException(e); @@ -94,13 +78,7 @@ private static void toString(StringBuilder result, InputStreamReader reader) thr } /** - * Copy data from a source stream to a destination stream. - * - * @param in the source stream. - * @param out the destination stream. - * @param buffer the buffer. - * @param needClose true if need to close streams. - * @throws IOException the io exception + * Copy data from the source stream to the destination stream. */ public static void copy(InputStream in, OutputStream out, byte[] buffer, boolean needClose) throws IOException { @@ -116,13 +94,9 @@ public static void copy(InputStream in, OutputStream out, byte[] buffer, boolean } /** - * Read the reader to the result string. - * - * @param reader the reader. - * @return the result string. - * @throws UncheckedIOException if reader thrown an io exception. + * Read full string using thread local buffer */ - public static String toStringUsingTLB(Reader reader) { + public static String toStringUsingTlb(Reader reader) { return toString(reader, LOCAL_CHAR_BUFFER.get()); } @@ -141,8 +115,4 @@ private static String toString(Reader reader, char[] buffer) { return builder.toString(); } - - private IOUtils() { - throw new RuntimeException(); - } } diff --git a/rlib-io/src/main/java/javasabr/rlib/io/util/package-info.java b/rlib-io/src/main/java/javasabr/rlib/io/util/package-info.java new file mode 100644 index 00000000..8ded76b3 --- /dev/null +++ b/rlib-io/src/main/java/javasabr/rlib/io/util/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.io.util; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java index db37c3ff..8b7d14e5 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java @@ -1,15 +1,12 @@ package javasabr.rlib.logger.impl; import java.util.Arrays; -import java.util.Objects; import javasabr.rlib.common.util.StringUtils; -import javasabr.rlib.common.util.array.Array; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; import javasabr.rlib.logger.api.LoggerService; import lombok.AccessLevel; import lombok.experimental.FieldDefaults; -import org.jspecify.annotations.Nullable; /** * @author JavaSaBr diff --git a/settings.gradle b/settings.gradle index 17c639bb..3d135fe4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -13,4 +13,5 @@ include ':rlib-logger-slf4j' include ':rlib-plugin-system' include ':rlib-geometry' include ':rlib-classpath' -include ':rlib-compiler' \ No newline at end of file +include ':rlib-compiler' +include ':rlib-io' \ No newline at end of file From d38dd1e7150ab89c9d5ea4c3ab8970551e9bf011 Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 10 Aug 2025 18:33:43 +0200 Subject: [PATCH 5/6] extract io module --- rlib-classpath/build.gradle | 1 + .../classpath/impl/ClassPathScannerImpl.java | 6 +- .../common/data/AbstractFileDocument.java | 56 ------- .../common/data/AbstractStreamDocument.java | 137 ------------------ .../rlib/common/data/DocumentXML.java | 20 --- rlib-compiler/build.gradle | 1 + .../rlib/compiler/impl/JdkCompiler.java | 4 +- .../java/javasabr/rlib/io}/FileUtilsTest.java | 5 +- .../java/javasabr/rlib/io/IoUtilsTest.java | 23 +-- rlib-plugin-system/build.gradle | 1 + .../plugin/system/impl/BasePluginSystem.java | 2 +- 11 files changed, 23 insertions(+), 233 deletions(-) delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/data/AbstractFileDocument.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/data/AbstractStreamDocument.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/data/DocumentXML.java rename {rlib-common/src/test/java/javasabr/rlib/common/util => rlib-io/src/test/java/javasabr/rlib/io}/FileUtilsTest.java (97%) rename rlib-common/src/test/java/javasabr/rlib/common/util/IOUtilsTest.java => rlib-io/src/test/java/javasabr/rlib/io/IoUtilsTest.java (77%) diff --git a/rlib-classpath/build.gradle b/rlib-classpath/build.gradle index f8325ab9..42096151 100644 --- a/rlib-classpath/build.gradle +++ b/rlib-classpath/build.gradle @@ -1,5 +1,6 @@ dependencies { api projects.rlibCommon + api projects.rlibIo testImplementation projects.rlibLoggerImpl } \ No newline at end of file diff --git a/rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/ClassPathScannerImpl.java b/rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/ClassPathScannerImpl.java index be89a64a..14aa25d4 100644 --- a/rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/ClassPathScannerImpl.java +++ b/rlib-classpath/src/main/java/javasabr/rlib/classpath/impl/ClassPathScannerImpl.java @@ -18,9 +18,9 @@ import javasabr.rlib.io.impl.ReuseBytesInputStream; import javasabr.rlib.io.impl.ReuseBytesOutputStream; import javasabr.rlib.common.util.ArrayUtils; -import javasabr.rlib.common.util.IOUtils; import javasabr.rlib.common.util.array.Array; import javasabr.rlib.common.util.array.ArrayFactory; +import javasabr.rlib.io.util.IoUtils; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerManager; import lombok.AccessLevel; @@ -304,8 +304,8 @@ private void scanJarInputStream( if (name.endsWith(JAR_EXTENSION)) { rout.reset(); - IOUtils.copy(jin, rout, buffer, false); - rin.initFor(rout.getData(), 0, rout.size()); + IoUtils.copy(jin, rout, buffer, false); + rin.initFor(rout.data(), 0, rout.size()); scanJar(classes, resources, rin); } else if (name.endsWith(CLASS_EXTENSION)) { loadClass(null, null, name, classes); diff --git a/rlib-common/src/main/java/javasabr/rlib/common/data/AbstractFileDocument.java b/rlib-common/src/main/java/javasabr/rlib/common/data/AbstractFileDocument.java deleted file mode 100644 index c7dffb9f..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/data/AbstractFileDocument.java +++ /dev/null @@ -1,56 +0,0 @@ -package javasabr.rlib.common.data; - -import static java.nio.file.Files.newInputStream; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import org.jspecify.annotations.NullMarked; - -/** - * The file implementation of the parser of xml documents. - * - * @param the type parameter - * @author JavaSaBr - */ -@NullMarked -public abstract class AbstractFileDocument extends AbstractStreamDocument { - - /** - * The file path. - */ - protected final String filePath; - - public AbstractFileDocument(File file) { - this.filePath = file.getAbsolutePath(); - try { - setStream(new FileInputStream(file)); - } catch (FileNotFoundException e) { - throw new UncheckedIOException(e); - } - } - - public AbstractFileDocument(Path path) { - this.filePath = path - .toAbsolutePath() - .toString(); - try { - setStream(newInputStream(path, StandardOpenOption.READ)); - } catch (final IOException e) { - throw new UncheckedIOException(e); - } - } - - /** - * Get the file path. - * - * @return the file path. - */ - protected String getFilePath() { - return filePath; - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/data/AbstractStreamDocument.java b/rlib-common/src/main/java/javasabr/rlib/common/data/AbstractStreamDocument.java deleted file mode 100644 index 00bedc9a..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/data/AbstractStreamDocument.java +++ /dev/null @@ -1,137 +0,0 @@ -package javasabr.rlib.common.data; - -import static java.lang.ThreadLocal.withInitial; - -import java.io.IOException; -import java.io.InputStream; -import javasabr.rlib.common.util.IOUtils; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import lombok.AccessLevel; -import lombok.Setter; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.xml.sax.SAXException; - -/** - * The base implementation of the parser of xml documents. - * - * @author JavaSaBr - */ -@NullMarked -public abstract class AbstractStreamDocument implements DocumentXML { - - protected static final Logger LOGGER = LoggerManager.getLogger(DocumentXML.class); - - protected static final ThreadLocal LOCAL_FACTORY = withInitial(() -> { - var factory = DocumentBuilderFactory.newInstance(); - factory.setValidating(false); - factory.setIgnoringComments(true); - return factory; - }); - - /** - * The stream of xml document. - */ - @Setter(AccessLevel.PROTECTED) - protected @Nullable InputStream stream; - - /** - * the DOM model of this document. - */ - protected @Nullable Document document; - - /** - * The result of parsing. - */ - protected @Nullable C result; - - public AbstractStreamDocument() { - super(); - } - - public AbstractStreamDocument(InputStream stream) { - this.stream = stream; - } - - /** - * Create a container of the result. - * - * @return the container of the result. - */ - protected abstract C create(); - - @Override - public C parse() { - - var factory = LOCAL_FACTORY.get(); - try { - var builder = factory.newDocumentBuilder(); - document = builder.parse(stream); - } catch (SAXException | IOException | ParserConfigurationException exc) { - LOGGER.warning(exc); - throw new RuntimeException(exc); - } finally { - IOUtils.close(stream); - } - - result = create(); - try { - parse(document); - } catch (Exception exc) { - LOGGER.warning(exc); - throw new RuntimeException(exc); - } - - return result; - } - - /** - * The process of parsing this DOM model. - * - * @param document the DOM model of this document. - */ - protected void parse(Document document) { - for (var node = document.getFirstChild(); node != null; node = node.getNextSibling()) { - - if (node.getNodeType() != Node.ELEMENT_NODE) { - continue; - } - - parse(null, (Element) node); - } - } - - /** - * The process of parsing this document. - * - * @param parent the parent element. - * @param element the current element. - */ - protected void parse(@Nullable Element parent, Element element) { - handle(parent, element); - - for (var node = element.getFirstChild(); node != null; node = node.getNextSibling()) { - - if (node.getNodeType() != Node.ELEMENT_NODE) { - continue; - } - - parse(element, (Element) node); - } - } - - /** - * The process of parsing this element. - * - * @param parent the parent element. - * @param element the current element. - */ - protected void handle(@Nullable Element parent, Element element) { - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/data/DocumentXML.java b/rlib-common/src/main/java/javasabr/rlib/common/data/DocumentXML.java deleted file mode 100644 index 1df10383..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/data/DocumentXML.java +++ /dev/null @@ -1,20 +0,0 @@ -package javasabr.rlib.common.data; - -import org.jspecify.annotations.NullMarked; - -/** - * The interface to implement a parser of xml documents. - * - * @param the result type. - * @author JavaSaBr - */ -@NullMarked -public interface DocumentXML { - - /** - * Parse this document and get the result. - * - * @return the result. - */ - C parse(); -} diff --git a/rlib-compiler/build.gradle b/rlib-compiler/build.gradle index f8325ab9..42096151 100644 --- a/rlib-compiler/build.gradle +++ b/rlib-compiler/build.gradle @@ -1,5 +1,6 @@ dependencies { api projects.rlibCommon + api projects.rlibIo testImplementation projects.rlibLoggerImpl } \ No newline at end of file diff --git a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java index d551b69d..d1ae4a39 100644 --- a/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java +++ b/rlib-compiler/src/main/java/javasabr/rlib/compiler/impl/JdkCompiler.java @@ -3,10 +3,10 @@ import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; -import javasabr.rlib.common.util.FileUtils; import javasabr.rlib.common.util.array.Array; import javasabr.rlib.common.util.array.ArrayCollectors; import javasabr.rlib.compiler.Compiler; +import javasabr.rlib.io.util.FileUtils; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerManager; import javax.tools.Diagnostic; @@ -82,7 +82,7 @@ public Array> compileDirectories(Array directories) { continue; } - FileUtils.addFilesTo(files, directory, false, Compiler.SOURCE_EXTENSION); + FileUtils.collectFilesTo(files, directory, false, Compiler.SOURCE_EXTENSION); } if (files.isEmpty()) { diff --git a/rlib-common/src/test/java/javasabr/rlib/common/util/FileUtilsTest.java b/rlib-io/src/test/java/javasabr/rlib/io/FileUtilsTest.java similarity index 97% rename from rlib-common/src/test/java/javasabr/rlib/common/util/FileUtilsTest.java rename to rlib-io/src/test/java/javasabr/rlib/io/FileUtilsTest.java index 55147c7d..57c5d84a 100644 --- a/rlib-common/src/test/java/javasabr/rlib/common/util/FileUtilsTest.java +++ b/rlib-io/src/test/java/javasabr/rlib/io/FileUtilsTest.java @@ -1,15 +1,14 @@ -package javasabr.rlib.common.util; +package javasabr.rlib.io; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import javasabr.rlib.io.util.FileUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** - * The test to test file utils. - * * @author JavaSaBr */ public class FileUtilsTest { diff --git a/rlib-common/src/test/java/javasabr/rlib/common/util/IOUtilsTest.java b/rlib-io/src/test/java/javasabr/rlib/io/IoUtilsTest.java similarity index 77% rename from rlib-common/src/test/java/javasabr/rlib/common/util/IOUtilsTest.java rename to rlib-io/src/test/java/javasabr/rlib/io/IoUtilsTest.java index 4c15dc1c..3d7b73dc 100644 --- a/rlib-common/src/test/java/javasabr/rlib/common/util/IOUtilsTest.java +++ b/rlib-io/src/test/java/javasabr/rlib/io/IoUtilsTest.java @@ -1,4 +1,4 @@ -package javasabr.rlib.common.util; +package javasabr.rlib.io; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -7,13 +7,15 @@ import java.io.StringReader; import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; +import javasabr.rlib.common.util.StringUtils; +import javasabr.rlib.io.util.IoUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * @author JavaSaBr */ -class IOUtilsTest { +class IoUtilsTest { @Test void shouldConvertInputStreamToString() { @@ -21,7 +23,7 @@ void shouldConvertInputStreamToString() { var original = StringUtils.generate(2048); var source = new ByteArrayInputStream(original.getBytes(StandardCharsets.UTF_8)); - Assertions.assertEquals(original, IOUtils.toString(source), "result string should be the same"); + Assertions.assertEquals(original, IoUtils.toString(source), "result string should be the same"); } @Test @@ -31,14 +33,14 @@ void shouldConvertSupplierOfInputStreamToString() { Assertions.assertEquals( original, - IOUtils.toString(() -> new ByteArrayInputStream(original.getBytes(StandardCharsets.UTF_8))), + IoUtils.toString(() -> new ByteArrayInputStream(original.getBytes(StandardCharsets.UTF_8))), "result string should be the same"); } @Test void shouldThrowUncheckedIOExceptionDuringConvertingInputStreamToString() { Assertions.assertThrows( - UncheckedIOException.class, () -> IOUtils.toString(new InputStream() { + UncheckedIOException.class, () -> IoUtils.toString(new InputStream() { @Override public int read() throws IOException { @@ -50,7 +52,7 @@ public int read() throws IOException { @Test void shouldThrowUncheckedIOExceptionDuringConvertingSupplierOfInputStreamToString() { Assertions.assertThrows( - UncheckedIOException.class, () -> IOUtils.toString(() -> new InputStream() { + UncheckedIOException.class, () -> IoUtils.toString(() -> new InputStream() { @Override public int read() throws IOException { @@ -63,7 +65,7 @@ public int read() throws IOException { void shouldThrowRuntimeExceptionDuringConvertingSupplierOfInputStreamToString() { Assertions.assertThrows( RuntimeException.class, () -> { - IOUtils.toString(() -> { + IoUtils.toString(() -> { throw new RuntimeException("test"); }); }); @@ -74,22 +76,21 @@ void shouldConvertReaderToStrungUsingTLB() { var original = StringUtils.generate(2048); - Assertions.assertEquals(original, IOUtils.toStringUsingTLB(new StringReader(original))); + Assertions.assertEquals(original, IoUtils.toStringUsingTlb(new StringReader(original))); } @Test void shouldThrownUncheckedIOExceptionDuringConvertingReaderToStrungUsingTLB() { Assertions.assertThrows( - UncheckedIOException.class, () -> IOUtils.toStringUsingTLB(new Reader() { + UncheckedIOException.class, () -> IoUtils.toStringUsingTlb(new Reader() { @Override public int read(char[] cbuf, int off, int len) throws IOException { throw new IOException("test"); } @Override - public void close() { - } + public void close() {} })); } } diff --git a/rlib-plugin-system/build.gradle b/rlib-plugin-system/build.gradle index 7169d011..126f9f5d 100644 --- a/rlib-plugin-system/build.gradle +++ b/rlib-plugin-system/build.gradle @@ -1,6 +1,7 @@ dependencies { api projects.rlibCommon + api projects.rlibIo api projects.rlibClasspath testImplementation projects.rlibLoggerImpl } \ No newline at end of file diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/BasePluginSystem.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/BasePluginSystem.java index 44a4ccb9..ed85700b 100644 --- a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/BasePluginSystem.java +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/BasePluginSystem.java @@ -25,11 +25,11 @@ import java.util.concurrent.atomic.AtomicReference; import javasabr.rlib.classpath.ClassPathScannerFactory; import javasabr.rlib.common.util.ClassUtils; -import javasabr.rlib.common.util.FileUtils; import javasabr.rlib.common.util.Utils; import javasabr.rlib.common.util.array.Array; import javasabr.rlib.common.util.array.ReadOnlyArray; import javasabr.rlib.common.util.dictionary.ObjectDictionary; +import javasabr.rlib.io.util.FileUtils; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.plugin.system.ConfigurablePluginSystem; From 11c940bedfd56dbc3c627c65de69fdb8a65654ba Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 10 Aug 2025 18:35:53 +0200 Subject: [PATCH 6/6] fix test --- rlib-io/src/test/java/javasabr/rlib/io/FileUtilsTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rlib-io/src/test/java/javasabr/rlib/io/FileUtilsTest.java b/rlib-io/src/test/java/javasabr/rlib/io/FileUtilsTest.java index 57c5d84a..df312a74 100644 --- a/rlib-io/src/test/java/javasabr/rlib/io/FileUtilsTest.java +++ b/rlib-io/src/test/java/javasabr/rlib/io/FileUtilsTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import javasabr.rlib.io.util.FileUtils; @@ -56,8 +57,8 @@ void shouldGetFileExtension() { assertEquals("jpg", FileUtils.getExtension(path4)); assertEquals("TxT", FileUtils.getExtension(path5)); assertEquals("txt", FileUtils.getExtension(path5, true)); - assertEquals("", FileUtils.getExtension(path6)); - assertEquals("", FileUtils.getExtension(path7)); + assertNull(FileUtils.getExtension(path6)); + assertNull(FileUtils.getExtension(path7)); } @Test