From c66067da8c05ab100f8d134837301b3c7a928493 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Thu, 8 Jun 2023 18:25:21 +0200 Subject: [PATCH] Move builder to Core module and developed it a bit --- .../builder/EmptyCollectionException.java | 8 +++ .../toolbox/core/builder/IBuilder.java | 11 ++++ .../toolbox/core/builder/IParamBuilder.java | 24 +++++++++ .../core/builder/OptionalParamBuilder.java | 24 +++++++++ .../RequiredCollectionParameterBuilder.java | 52 +++++++++++++++++++ .../core/builder/RequiredParamBuilder.java | 30 +++++++++++ Core/src/test/java/BuilderImpl.java | 38 ++++++++++++++ Core/src/test/java/BuilderResult.java | 5 ++ Core/src/test/java/BuilderTest.java | 32 ++++++++++++ Database/build.gradle | 1 + .../database/keyvalue/KeyValueBuilder.java | 35 +++++++++---- .../toolbox/database/ConnectionTest.java | 1 + settings.gradle | 2 +- 13 files changed, 251 insertions(+), 12 deletions(-) create mode 100644 Core/src/main/java/fr/altarik/toolbox/core/builder/EmptyCollectionException.java create mode 100644 Core/src/main/java/fr/altarik/toolbox/core/builder/IBuilder.java create mode 100644 Core/src/main/java/fr/altarik/toolbox/core/builder/IParamBuilder.java create mode 100644 Core/src/main/java/fr/altarik/toolbox/core/builder/OptionalParamBuilder.java create mode 100644 Core/src/main/java/fr/altarik/toolbox/core/builder/RequiredCollectionParameterBuilder.java create mode 100644 Core/src/main/java/fr/altarik/toolbox/core/builder/RequiredParamBuilder.java create mode 100644 Core/src/test/java/BuilderImpl.java create mode 100644 Core/src/test/java/BuilderResult.java create mode 100644 Core/src/test/java/BuilderTest.java diff --git a/Core/src/main/java/fr/altarik/toolbox/core/builder/EmptyCollectionException.java b/Core/src/main/java/fr/altarik/toolbox/core/builder/EmptyCollectionException.java new file mode 100644 index 0000000..798e6c3 --- /dev/null +++ b/Core/src/main/java/fr/altarik/toolbox/core/builder/EmptyCollectionException.java @@ -0,0 +1,8 @@ +package fr.altarik.toolbox.core.builder; + +public class EmptyCollectionException extends NullPointerException { + + public EmptyCollectionException(String message) { + super(message); + } +} diff --git a/Core/src/main/java/fr/altarik/toolbox/core/builder/IBuilder.java b/Core/src/main/java/fr/altarik/toolbox/core/builder/IBuilder.java new file mode 100644 index 0000000..64324a9 --- /dev/null +++ b/Core/src/main/java/fr/altarik/toolbox/core/builder/IBuilder.java @@ -0,0 +1,11 @@ +package fr.altarik.toolbox.core.builder; + +public interface IBuilder { + + /** + * Build the builders parameters into T object + * @return The created objects thanks to given parameters + * @throws Exception if any error occur during creation of the built object + */ + T build() throws Exception; +} diff --git a/Core/src/main/java/fr/altarik/toolbox/core/builder/IParamBuilder.java b/Core/src/main/java/fr/altarik/toolbox/core/builder/IParamBuilder.java new file mode 100644 index 0000000..ffa1b5a --- /dev/null +++ b/Core/src/main/java/fr/altarik/toolbox/core/builder/IParamBuilder.java @@ -0,0 +1,24 @@ +package fr.altarik.toolbox.core.builder; + +/** + * Builder parameter, for more flexibility + * @param the parameter type + * @see OptionalParamBuilder + * @see RequiredParamBuilder + * @see RequiredCollectionParameterBuilder + */ +public interface IParamBuilder { + + /** + * Get the given object, may return {@link NullPointerException} depending on the policy of implemented class + * @return the parameter given by {@link IParamBuilder#set(Object)} + * @throws NullPointerException may throw this error depending on the policy of implemented class + */ + T get() throws NullPointerException; + + /** + * Change/insert the value of the parameter + * @param parameter the given parameter + */ + void set(T parameter); +} diff --git a/Core/src/main/java/fr/altarik/toolbox/core/builder/OptionalParamBuilder.java b/Core/src/main/java/fr/altarik/toolbox/core/builder/OptionalParamBuilder.java new file mode 100644 index 0000000..fa60979 --- /dev/null +++ b/Core/src/main/java/fr/altarik/toolbox/core/builder/OptionalParamBuilder.java @@ -0,0 +1,24 @@ +package fr.altarik.toolbox.core.builder; + +/** + * Doesn't throw a {@link NullPointerException} when using {@link IParamBuilder#get()} in any case + * @param the returned type + * @see IParamBuilder + */ +public class OptionalParamBuilder implements IParamBuilder { + + private T parameter; + + public OptionalParamBuilder(T param) { + this.parameter = param; + } + @Override + public T get() throws NullPointerException { + return parameter; + } + + @Override + public void set(T parameter) { + this.parameter = parameter; + } +} diff --git a/Core/src/main/java/fr/altarik/toolbox/core/builder/RequiredCollectionParameterBuilder.java b/Core/src/main/java/fr/altarik/toolbox/core/builder/RequiredCollectionParameterBuilder.java new file mode 100644 index 0000000..8a828bd --- /dev/null +++ b/Core/src/main/java/fr/altarik/toolbox/core/builder/RequiredCollectionParameterBuilder.java @@ -0,0 +1,52 @@ +package fr.altarik.toolbox.core.builder; + +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Objects; + +/** + * Mostly same as {@link RequiredParamBuilder} but for list + * @param The type contained in the collection + * @param The returned type + */ +public class RequiredCollectionParameterBuilder> implements IParamBuilder { + + private final T collection; + private final boolean canBeEmpty; + + public RequiredCollectionParameterBuilder(@NotNull T collection, boolean canBeEmpty) { + this.collection = Objects.requireNonNull(collection); + this.canBeEmpty = canBeEmpty; + } + + /** + *

Return the list, if not empty

+ *

If empty, return the collection if {@code canBeEmpty} if true, otherwise throw a {@link NullPointerException}

+ * @return the collection + * @throws NullPointerException if collection is empty and {@code canBeEmpty} is false + */ + @Override + public T get() throws NullPointerException { + if(canBeEmpty) { + return collection; + } else if(!collection.isEmpty()) { + return collection; + } else { + throw new EmptyCollectionException("Collection cannot be empty"); + } + } + + @Override + public void set(T parameter) { + throw new UnsupportedOperationException("Use `add` in place of `set` for RequiredCollectionParameterBuilder"); + } + + /** + * Add an element to the collection + * @param element element to add to the list + */ + public void add(E element) { + collection.add(element); + } +} diff --git a/Core/src/main/java/fr/altarik/toolbox/core/builder/RequiredParamBuilder.java b/Core/src/main/java/fr/altarik/toolbox/core/builder/RequiredParamBuilder.java new file mode 100644 index 0000000..7d45fdc --- /dev/null +++ b/Core/src/main/java/fr/altarik/toolbox/core/builder/RequiredParamBuilder.java @@ -0,0 +1,30 @@ +package fr.altarik.toolbox.core.builder; + +import java.util.Objects; + +/** + * Throw a {@link NullPointerException} when using {@link IParamBuilder#get()} if the parameter doesn't have been initialized + * @param the returned type + */ +public class RequiredParamBuilder implements IParamBuilder { + + private T parameter; + + public RequiredParamBuilder(T parameter) { + this.parameter = parameter; + } + + public RequiredParamBuilder() { + this(null); + } + + @Override + public T get() { + return Objects.requireNonNull(parameter); + } + + @Override + public void set(T parameter) { + this.parameter = parameter; + } +} diff --git a/Core/src/test/java/BuilderImpl.java b/Core/src/test/java/BuilderImpl.java new file mode 100644 index 0000000..a5a8850 --- /dev/null +++ b/Core/src/test/java/BuilderImpl.java @@ -0,0 +1,38 @@ +import fr.altarik.toolbox.core.builder.IBuilder; +import fr.altarik.toolbox.core.builder.RequiredCollectionParameterBuilder; +import fr.altarik.toolbox.core.builder.RequiredParamBuilder; + +import java.util.ArrayList; +import java.util.List; + +public class BuilderImpl implements IBuilder { + + private final RequiredCollectionParameterBuilder> collection; + private final RequiredParamBuilder numberOfSentences; + + private BuilderImpl(boolean canBeEmpty) { + this.collection = new RequiredCollectionParameterBuilder<>(new ArrayList<>(), canBeEmpty); + this.numberOfSentences = new RequiredParamBuilder<>(); + } + + public BuilderImpl addSentence(String sentence) { + collection.add(sentence); + return this; + } + + public BuilderImpl numberOfSentence(int i) { + this.numberOfSentences.set(i); + return this; + } + + public static BuilderImpl builder(boolean canBeEmpty) { + return new BuilderImpl(canBeEmpty); + } + + + + @Override + public BuilderResult build() throws Exception { + return new BuilderResult(collection.get(), numberOfSentences.get()); + } +} diff --git a/Core/src/test/java/BuilderResult.java b/Core/src/test/java/BuilderResult.java new file mode 100644 index 0000000..3952469 --- /dev/null +++ b/Core/src/test/java/BuilderResult.java @@ -0,0 +1,5 @@ +import java.util.List; + +public record BuilderResult(List sentences, int numberOfSentences) { + +} diff --git a/Core/src/test/java/BuilderTest.java b/Core/src/test/java/BuilderTest.java new file mode 100644 index 0000000..148efe2 --- /dev/null +++ b/Core/src/test/java/BuilderTest.java @@ -0,0 +1,32 @@ +import fr.altarik.toolbox.core.builder.EmptyCollectionException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +public class BuilderTest { + + + @Test + void builderTest() throws Exception { + BuilderImpl builder = BuilderImpl.builder(true); + builder.addSentence("First sentence"); + builder.addSentence("Second sentence"); + builder.numberOfSentence(2); + BuilderResult res = builder.build(); + Assertions.assertEquals(Arrays.asList("First sentence", "Second sentence"), res.sentences()); + Assertions.assertEquals(res.numberOfSentences(), 2); + + BuilderImpl builder1 = BuilderImpl.builder(false); + builder1.numberOfSentence(3); + Assertions.assertThrowsExactly(EmptyCollectionException.class, builder1::build); + + BuilderImpl builder2 = BuilderImpl.builder(true); + builder2.numberOfSentence(3); + Assertions.assertDoesNotThrow(builder2::build); + + BuilderImpl builder3 = BuilderImpl.builder(true); + Assertions.assertThrowsExactly(NullPointerException.class, builder3::build); + } + +} diff --git a/Database/build.gradle b/Database/build.gradle index 1c29a69..9aa1fc3 100644 --- a/Database/build.gradle +++ b/Database/build.gradle @@ -1,6 +1,7 @@ dependencies { implementation 'org.postgresql:postgresql:42.5.0' testImplementation 'com.google.code.gson:gson:2.10' + implementation project(':Core') } test { diff --git a/Database/src/main/java/fr/altarik/toolbox/database/keyvalue/KeyValueBuilder.java b/Database/src/main/java/fr/altarik/toolbox/database/keyvalue/KeyValueBuilder.java index a665599..c802d67 100644 --- a/Database/src/main/java/fr/altarik/toolbox/database/keyvalue/KeyValueBuilder.java +++ b/Database/src/main/java/fr/altarik/toolbox/database/keyvalue/KeyValueBuilder.java @@ -1,5 +1,8 @@ package fr.altarik.toolbox.database.keyvalue; +import fr.altarik.toolbox.core.builder.IBuilder; +import fr.altarik.toolbox.core.builder.RequiredCollectionParameterBuilder; +import fr.altarik.toolbox.core.builder.RequiredParamBuilder; import fr.altarik.toolbox.database.SqlConnection; import net.minecraft.util.Pair; import org.jetbrains.annotations.NotNull; @@ -11,20 +14,30 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; -public class KeyValueBuilder { +public class KeyValueBuilder implements IBuilder { - private final String tableName; - private final List additionalColumns; - private final SqlConnection connection; + private final RequiredParamBuilder tableName; + private final RequiredCollectionParameterBuilder> additionalColumns; + private final RequiredParamBuilder connection; - private KeyValueBuilder(SqlConnection connection, String tableName) { - this.connection = connection; - this.tableName = tableName; - this.additionalColumns = new ArrayList<>(); + private KeyValueBuilder() { + this.tableName = new RequiredParamBuilder<>(); + this.connection = new RequiredParamBuilder<>(); + this.additionalColumns = new RequiredCollectionParameterBuilder<>(new ArrayList<>(), true); } - public static KeyValueBuilder builder(@NotNull SqlConnection connection, @NotNull String tableName) { - return new KeyValueBuilder(connection, tableName); + public static KeyValueBuilder builder() { + return new KeyValueBuilder(); + } + + public KeyValueBuilder setConnection(@NotNull SqlConnection connection) { + this.connection.set(connection); + return this; + } + + public KeyValueBuilder setTableName(@NotNull String tableName) { + this.tableName.set(tableName); + return this; } public KeyValueBuilder addColumn(AdditionalColumn additionalColumn) { @@ -33,7 +46,7 @@ public class KeyValueBuilder { } public KeyValueConnection build() throws SQLException { - return new KeyValueConnection(connection, tableName, additionalColumns); + return new KeyValueConnection(connection.get(), tableName.get(), additionalColumns.get()); } public record AdditionalColumn(@NotNull String columnName, @NotNull JDBCType type, boolean notNull, @Nullable AdditionalColumnReference reference) { diff --git a/Database/src/test/java/fr/altarik/toolbox/database/ConnectionTest.java b/Database/src/test/java/fr/altarik/toolbox/database/ConnectionTest.java index 955151d..94759a5 100644 --- a/Database/src/test/java/fr/altarik/toolbox/database/ConnectionTest.java +++ b/Database/src/test/java/fr/altarik/toolbox/database/ConnectionTest.java @@ -30,6 +30,7 @@ class ConnectionTest { try(PreparedStatement statement = connection.getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS toolbox(id SERIAL, PRIMARY KEY (id));")) { statement.executeUpdate(); } + connection.close(); }); } diff --git a/settings.gradle b/settings.gradle index 3f9b534..4a814ce 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,4 +10,4 @@ pluginManagement { } rootProject.name = 'Toolbox' -include(':Tasks', ':Database', ':Pagination') +include(':Tasks', ':Database', ':Pagination', ':Core')