> enclosingClasses = new ArrayList<>();
+
+ Class> current = clazz;
+ do {
+ enclosingClasses.add(0, current);
+ current = current.getEnclosingClass();
+ } while (current != null);
+
+ return enclosingClasses;
+ }
}
diff --git a/src/main/java/io/github/daniloarcidiacono/commons/lang/StringCommons.java b/src/main/java/io/github/daniloarcidiacono/commons/lang/StringCommons.java
index 59434c0..d896313 100644
--- a/src/main/java/io/github/daniloarcidiacono/commons/lang/StringCommons.java
+++ b/src/main/java/io/github/daniloarcidiacono/commons/lang/StringCommons.java
@@ -7,8 +7,6 @@
* This class delivers some simple functionality that should really be
* provided by the core Java {@link String} and {@link StringBuilder}
* classes.
- *
- * @author Danilo Arcidiacono
*/
public abstract class StringCommons {
/**
@@ -85,4 +83,16 @@ public static String listToString(final Iterable collection) {
sb.append(" }");
return sb.toString();
}
+
+ public static String singleQuote(final String str) {
+ return quote(str,"'");
+ }
+
+ public static String doubleQuote(final String str) {
+ return quote(str,"\"");
+ }
+
+ public static String quote(final String str, final String quote) {
+ return quote + str + quote;
+ }
}
diff --git a/src/main/java/io/github/daniloarcidiacono/commons/lang/patterns/Composite.java b/src/main/java/io/github/daniloarcidiacono/commons/lang/patterns/Composite.java
new file mode 100644
index 0000000..2284a54
--- /dev/null
+++ b/src/main/java/io/github/daniloarcidiacono/commons/lang/patterns/Composite.java
@@ -0,0 +1,161 @@
+package io.github.daniloarcidiacono.commons.lang.patterns;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Base class for an object which aggregates a list of elements.
+ * @param type of the component
+ */
+public class Composite {
+ protected List components = new ArrayList<>();
+
+ public Composite() {
+ }
+
+ public Composite(final Collection component) {
+ components.addAll(component);
+ }
+
+ public Composite(final T ...component) {
+ Collections.addAll(components, component);
+ }
+
+ public Composite add(final T component) {
+ components.add(component);
+ return this;
+ }
+
+ public Composite add(final T ...component) {
+ Collections.addAll(components, component);
+ return this;
+ }
+
+ /**
+ * Adds a component before the specified one.
+ * If the specified component is not found, the component is not added.
+ *
+ * @param before the component to search for
+ * @param component the component to add
+ * @return the class instance, for chaining calls
+ */
+ public Composite addBefore(final T before, final T component) {
+ final int index = components.indexOf(before);
+ if (index != -1) {
+ components.add(index, component);
+ }
+
+ return this;
+ }
+
+ /**
+ * Adds a component after the specified one.
+ * If the specified component is not found, the component is not added.
+ *
+ * @param after the component to search for
+ * @param component the component to add
+ * @return the class instance, for chaining calls
+ */
+ public Composite addAfter(final T after, final T component) {
+ final int index = components.indexOf(after);
+ if (index != -1) {
+ components.add(index + 1, component);
+ }
+
+ return this;
+ }
+
+ /**
+ * Multi-component variant of {@link #addBefore(Object, Object)}
+ * @param before the component to search for
+ * @param component the components to add
+ * @return the class instance, for chaining calls
+ */
+ public Composite addBefore(final T before, final T ...component) {
+ int index = components.indexOf(before);
+ if (index != -1) {
+ for (T t : component) {
+ components.add(index, t);
+ index++;
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Multi-component variant of {@link #addAfter(Object, Object)}
+ * @param after the component to search for
+ * @param component the components to add
+ * @return the class instance, for chaining calls
+ */
+ public Composite addAfter(final T after, final T ...component) {
+ int index = components.indexOf(after);
+ if (index != -1) {
+ for (T t : component) {
+ components.add(index + 1, t);
+ index++;
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Removes every component.
+ * @return the class instance, for chaining calls
+ */
+ public Composite removeAll() {
+ components.clear();
+ return this;
+ }
+
+ /**
+ * Removes the specified component.
+ * @param component the component to remove.
+ * @return the class instance, for chaining calls
+ */
+ public Composite remove(final T component) {
+ components.remove(component);
+ return this;
+ }
+
+ /**
+ * Removes a set of components.
+ * @param component the components to remoev
+ * @return the class instance, for chaining calls
+ */
+ public Composite remove(final T ...component) {
+ for (T t : component) {
+ components.remove(t);
+ }
+
+ return this;
+ }
+
+ /**
+ * Searches for the component having the specified type.
+ * @param clazz the return type class
+ * @param the return type
+ * @return the first component having the specified type, or null if it is not found.
+ */
+ public U get(final Class clazz) {
+ for (T component : components) {
+ if (component != null && component.getClass().equals(clazz)) {
+ return (U)component;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the list of components.
+ * @return the list of components.
+ */
+ public List getComponents() {
+ return components;
+ }
+}
diff --git a/src/test/java/io/github/daniloarcidiacono/commons/lang/FileCommonsTest.java b/src/test/java/io/github/daniloarcidiacono/commons/lang/FileCommonsTest.java
new file mode 100644
index 0000000..dbb0374
--- /dev/null
+++ b/src/test/java/io/github/daniloarcidiacono/commons/lang/FileCommonsTest.java
@@ -0,0 +1,80 @@
+package io.github.daniloarcidiacono.commons.lang;
+
+import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.nio.file.*;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Tests for {@link FileCommons} class.
+ * @see jdk8u-jdk: CreateFileTree utility class
+ */
+class FileCommonsTest {
+ @Test
+ void deleteFolder() throws IOException {
+ try (final FileSystem fs = MemoryFileSystemBuilder.newEmpty().build()) {
+ // Try to delete a non existing folder (must do nothing)
+ FileCommons.deleteFolder(fs.getPath("not_existing"));
+
+ // Create the folder that will be deleted
+ final Path testFolder = fs.getPath("/test");
+ Files.createDirectories(testFolder);
+ Files.createFile(fs.getPath("/test/file1.txt"));
+ Files.createFile(fs.getPath("/test/file2.txt"));
+ Files.createFile(fs.getPath("/test/file3.txt"));
+
+ // Create another folder
+ final Path otherFolder = fs.getPath("/other");
+ Files.createDirectories(otherFolder);
+ Files.createFile(fs.getPath("/other/file1.txt"));
+
+ // Create some symbolic links
+ Files.createSymbolicLink(fs.getPath("/test/file1_link.txt"), fs.getPath("/other/file1.txt"));
+ Files.createSymbolicLink(fs.getPath("/test/other_link"), fs.getPath("/other"));
+
+ // Delete the folder
+ FileCommons.deleteFolder(testFolder);
+
+ // Try to delete a file (must do nothing)
+ FileCommons.deleteFolder(fs.getPath("/other/file1.txt"));
+
+ // https://docs.oracle.com/javase/tutorial/essential/io/walk.html
+ // By default, walkFileTree does not follow symbolic links.
+ final List paths = new ArrayList<>();
+ Files.walkFileTree(fs.getPath("/"), new SimpleFileVisitor() {
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ paths.add(file.toString());
+ return FileVisitResult.CONTINUE;
+ }
+
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ paths.add(dir.toString());
+ return FileVisitResult.CONTINUE;
+ }
+ });
+
+ assertEquals(
+ Arrays.asList("/", "/other", "/other/file1.txt"),
+ paths,
+ "Symbolic links should not be followed"
+ );
+ }
+ }
+
+ @Test
+ void loadResource() {
+ assertEquals("test file content", FileCommons.loadResource("test.txt"));
+ assertEquals("", FileCommons.loadResource("test_empty.txt"));
+ assertEquals(null, FileCommons.loadResource("test_not_existing.txt"));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/io/github/daniloarcidiacono/commons/lang/ReflectiveCommonsTest.java b/src/test/java/io/github/daniloarcidiacono/commons/lang/ReflectiveCommonsTest.java
index 91d7eb7..417d3a7 100644
--- a/src/test/java/io/github/daniloarcidiacono/commons/lang/ReflectiveCommonsTest.java
+++ b/src/test/java/io/github/daniloarcidiacono/commons/lang/ReflectiveCommonsTest.java
@@ -4,15 +4,15 @@
import java.lang.annotation.*;
import java.lang.reflect.Method;
+import java.util.Arrays;
import java.util.List;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Tests for {@link ReflectiveCommons} class.
- *
- * @author Danilo Arcidiacono
*/
class ReflectiveCommonsTest {
@Retention(RetentionPolicy.RUNTIME)
@@ -70,4 +70,12 @@ void getMethodsAnnotatedWith() throws NoSuchMethodException {
"Methods without the specified annotation are not picked"
);
}
+
+ @Test
+ void getEnclosingClasses() {
+ assertEquals(
+ Arrays.asList(ReflectiveCommonsTest.class, Base.class),
+ ReflectiveCommons.getEnclosingClasses(Base.class)
+ );
+ }
}
\ No newline at end of file
diff --git a/src/test/java/io/github/daniloarcidiacono/commons/lang/StringCommonsTest.java b/src/test/java/io/github/daniloarcidiacono/commons/lang/StringCommonsTest.java
index 2289b1c..23ceaea 100644
--- a/src/test/java/io/github/daniloarcidiacono/commons/lang/StringCommonsTest.java
+++ b/src/test/java/io/github/daniloarcidiacono/commons/lang/StringCommonsTest.java
@@ -8,8 +8,6 @@
/**
* Tests for {@link StringCommons} class.
- *
- * @author Danilo Arcidiacono
*/
class StringCommonsTest {
@Test
@@ -39,4 +37,11 @@ void listToString() {
assertEquals(StringCommons.listToString(Arrays.asList( "first" )), "{ first }");
assertEquals(StringCommons.listToString(Arrays.asList( "first", "second" )), "{ first, second }");
}
+
+ @Test
+ void quotes() {
+ assertEquals(StringCommons.singleQuote("test"), "'test'");
+ assertEquals(StringCommons.doubleQuote("test"), "\"test\"");
+ assertEquals(StringCommons.quote("test", "*"), "*test*");
+ }
}
\ No newline at end of file
diff --git a/src/test/java/io/github/daniloarcidiacono/commons/lang/patterns/CompositeTest.java b/src/test/java/io/github/daniloarcidiacono/commons/lang/patterns/CompositeTest.java
new file mode 100644
index 0000000..59020c3
--- /dev/null
+++ b/src/test/java/io/github/daniloarcidiacono/commons/lang/patterns/CompositeTest.java
@@ -0,0 +1,108 @@
+package io.github.daniloarcidiacono.commons.lang.patterns;
+
+import org.junit.jupiter.api.Test;
+import java.util.Arrays;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Tests for {@link Composite} class.
+ */
+class CompositeTest {
+ @Test
+ public void testAddBefore() {
+ final Composite composite = new Composite<>();
+ composite.add(2);
+ composite.add(3);
+ composite.addBefore(2, 1);
+ composite.addBefore(1000, 10);
+
+ assertEquals(
+ Arrays.asList(1, 2, 3),
+ composite.getComponents()
+ );
+
+ composite.addBefore(1, -3, -2, -1, 0);
+ composite.addBefore(1000, -3, -2, -1, 0);
+
+ assertEquals(
+ Arrays.asList(-3, -2, -1, 0, 1, 2, 3),
+ composite.getComponents()
+ );
+ }
+
+ @Test
+ public void testAddAfter() {
+ final Composite composite = new Composite<>();
+ composite.add(1);
+ composite.add(2);
+ composite.add(10);
+ composite.addAfter(2, 3);
+ composite.addAfter(1000, 10);
+
+ assertEquals(
+ Arrays.asList(1, 2, 3, 10),
+ composite.getComponents()
+ );
+
+ composite.addAfter(3, 4, 5, 6, 7, 8, 9);
+ composite.addAfter(1000, 4, 5, 6, 7, 8, 9);
+
+ assertEquals(
+ Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
+ composite.getComponents()
+ );
+ }
+
+ @Test
+ public void testRemove() {
+ final Composite composite = new Composite<>();
+ composite.add(1, 2, 3);
+ composite.remove(2);
+
+ assertEquals(
+ Arrays.asList(1, 3),
+ composite.getComponents()
+ );
+
+ composite.removeAll();
+ assertTrue(composite.getComponents().isEmpty());
+ }
+
+ @Test
+ public void testMultiRemove() {
+ final Composite composite = new Composite<>(
+ Arrays.asList(1, 2, 3, 4, 5)
+ );
+
+ composite.remove(2, 4);
+ assertEquals(
+ Arrays.asList(1, 3, 5),
+ composite.getComponents()
+ );
+ }
+
+ private static class Base {
+ }
+
+ private static class DerivedA extends Base {
+ }
+
+ private static class DerivedB extends Base {
+ }
+
+ private static class DerivedC extends Base {
+ }
+
+ @Test
+ public void testGet() {
+ final Base a = new Base();
+ final Base b = new DerivedA();
+ final Base c = new DerivedB();
+ final Composite composite = new Composite<>(a, b, c, null);
+
+ assertEquals(composite.get(Base.class), a);
+ assertEquals(composite.get(DerivedA.class), b);
+ assertEquals(composite.get(DerivedB.class), c);
+ assertEquals(composite.get(DerivedC.class), null);
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/test.txt b/src/test/resources/test.txt
new file mode 100644
index 0000000..2211df3
--- /dev/null
+++ b/src/test/resources/test.txt
@@ -0,0 +1 @@
+test file content
\ No newline at end of file
diff --git a/src/test/resources/test_empty.txt b/src/test/resources/test_empty.txt
new file mode 100644
index 0000000..e69de29