- * notes :
- *
ON : Feb 27, 2021
+ *
+ * Simple annotation to indicate the class is meant to contain only utilities.
+ *
*
* @author Stijn Dejongh
+ * @version 1.0.0
+ * @created 25.03.21, Thursday
+ * @since 1.0.0
*/
-public class UtilityClass {
-
- @SneakyThrows
- private UtilityClass() {
- utilityClassConstructor();
- }
+@Utility
+public @interface Constants {
}
diff --git a/commons/src/main/java/be/sddevelopment/commons/access/Utility.java b/commons-kernel/src/main/java/be/sddevelopment/commons/annotations/Utility.java
similarity index 85%
rename from commons/src/main/java/be/sddevelopment/commons/access/Utility.java
rename to commons-kernel/src/main/java/be/sddevelopment/commons/annotations/Utility.java
index f058164..38910f1 100755
--- a/commons/src/main/java/be/sddevelopment/commons/access/Utility.java
+++ b/commons-kernel/src/main/java/be/sddevelopment/commons/annotations/Utility.java
@@ -21,22 +21,13 @@
* #L%
*/
-package be.sddevelopment.commons.access;
+package be.sddevelopment.commons.annotations;
/**
*
* Simple annotation to indicate the class is meant to be a utility class.
*
*
- * Example usage
- *
- *
- * // No example available yet
- *
- *
- *
- * References
- *
* @author Stijn Dejongh
* @version 1.0.0
* @created 25.03.21, Thursday
diff --git a/commons-testing/pom.xml b/commons-testing/pom.xml
index cdd9d37..4f6fbf1 100755
--- a/commons-testing/pom.xml
+++ b/commons-testing/pom.xml
@@ -6,7 +6,7 @@
4.0.0
- be.sddevelopment
+ be.sddevelopment.commons
code-utils
1.0.0-SNAPSHOT
@@ -19,6 +19,10 @@
+
+ be.sddevelopment.commons
+ commons-kernel
+
org.projectlombok
lombok
@@ -38,6 +42,15 @@
org.apache.commons
commons-lang3
+
+ com.tngtech.archunit
+ archunit-junit5-api
+
+
+ com.tngtech.archunit
+ archunit-junit5-engine
+ ${archunit.version}
+
@@ -45,11 +58,6 @@
junit-jupiter-engine
test
-
- com.tngtech.archunit
- archunit-junit5-api
- test
-
\ No newline at end of file
diff --git a/commons-testing/src/main/java/be/sddevelopment/commons/testing/conventions/CodeConventions.java b/commons-testing/src/main/java/be/sddevelopment/commons/testing/conventions/CodeConventions.java
new file mode 100755
index 0000000..cddeb54
--- /dev/null
+++ b/commons-testing/src/main/java/be/sddevelopment/commons/testing/conventions/CodeConventions.java
@@ -0,0 +1,125 @@
+/*-
+ * #%L
+ * commons-testing
+ * %%
+ * Copyright (C) 2020 - 2024 SD Development
+ * %%
+ * Licensed under the EUPL, Version 1.1 or – as soon they will be
+ * approved by the European Commission - subsequent versions of the
+ * EUPL (the "Licence");
+ *
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ *
+ * http://ec.europa.eu/idabc/eupl5
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ * #L%
+ */
+
+package be.sddevelopment.commons.testing.conventions;
+
+import static com.tngtech.archunit.lang.SimpleConditionEvent.satisfied;
+import static com.tngtech.archunit.lang.SimpleConditionEvent.violated;
+import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
+import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS;
+import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS;
+import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_USE_FIELD_INJECTION;
+import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_USE_JAVA_UTIL_LOGGING;
+import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_USE_JODATIME;
+import static org.junit.platform.commons.util.ReflectionUtils.makeAccessible;
+
+import be.sddevelopment.commons.annotations.Constants;
+import be.sddevelopment.commons.annotations.Utility;
+import com.tngtech.archunit.core.domain.JavaClass;
+import com.tngtech.archunit.core.domain.JavaConstructor;
+import com.tngtech.archunit.core.domain.JavaModifier;
+import com.tngtech.archunit.junit.ArchTest;
+import com.tngtech.archunit.lang.ArchCondition;
+import com.tngtech.archunit.lang.ArchRule;
+import com.tngtech.archunit.lang.ConditionEvents;
+import com.tngtech.archunit.lang.syntax.elements.GivenClassesConjunction;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import org.junit.jupiter.api.DisplayName;
+
+
+@DisplayName("Complies with code conventions")
+public interface CodeConventions {
+
+ @ArchTest
+ ArchRule CLASSES_DO_NOT_ACCESS_STANDARD_STREAMS = NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS;
+
+ @ArchTest
+ ArchRule NO_CLASSES_USE_FIELD_INJECTION = NO_CLASSES_SHOULD_USE_FIELD_INJECTION;
+
+ @ArchTest
+ ArchRule NO_GENERIC_EXCEPTION = NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS;
+
+ @ArchTest
+ ArchRule NO_JAVA_UTIL_LOGGING = NO_CLASSES_SHOULD_USE_JAVA_UTIL_LOGGING;
+
+ @ArchTest
+ ArchRule NO_JODATIME = NO_CLASSES_SHOULD_USE_JODATIME;
+
+ @ArchTest
+ ArchRule UTILITY_CLASSES_CAN_NOT_BE_INSTANTIATED = utilityClasses()
+ .should(notBeInstantiatable())
+ .because(
+ "Utility classes should not be instantiated")
+ .allowEmptyShould(true);
+
+ @ArchTest
+ ArchRule UTILITY_CLASSES_ARE_FINAL = utilityClasses()
+ .should()
+ .haveModifier(JavaModifier.FINAL)
+ .because("Utility classes should be final")
+ .allowEmptyShould(true);
+
+ private static GivenClassesConjunction utilityClasses() {
+ return classes().that().areAnnotatedWith(Utility.class).and().areNotAnnotations();
+ }
+
+ private static GivenClassesConjunction constantClasses() {
+ return classes().that().areAnnotatedWith(Constants.class).and().areNotAnnotations();
+ }
+
+ static ArchCondition super JavaClass> notBeInstantiatable() {
+ return new ArchCondition<>("not be instantiatable") {
+ @Override
+ public void check(JavaClass item, ConditionEvents events) {
+ if (isInstantiatable(item)) {
+ events.add(violated(item, "Class " + item.getName() + " is instantiatable"));
+ } else {
+ events.add(satisfied(item, "Class " + item.getName() + " is not instantiatable"));
+ }
+ }
+ };
+ }
+
+ static boolean isInstantiatable(JavaClass classToCheck) {
+
+ try {
+ if (classToCheck
+ .getConstructors()
+ .stream()
+ .map(JavaConstructor::getParameters)
+ .anyMatch(List::isEmpty)) {
+ var constructor = classToCheck.getConstructor().reflect();
+ makeAccessible(constructor);
+ constructor.newInstance();
+ return true;
+ } else {
+ return false;
+ }
+ } catch (UnsupportedOperationException | InstantiationException | IllegalAccessException |
+ InvocationTargetException e) {
+ return false;
+ }
+ }
+
+}
diff --git a/commons-testing/src/main/java/be/sddevelopment/commons/testing/ReplaceUnderscoredCamelCasing.java b/commons-testing/src/main/java/be/sddevelopment/commons/testing/naming/ReplaceUnderscoredCamelCasing.java
similarity index 97%
rename from commons-testing/src/main/java/be/sddevelopment/commons/testing/ReplaceUnderscoredCamelCasing.java
rename to commons-testing/src/main/java/be/sddevelopment/commons/testing/naming/ReplaceUnderscoredCamelCasing.java
index 4c838db..0e6a165 100755
--- a/commons-testing/src/main/java/be/sddevelopment/commons/testing/ReplaceUnderscoredCamelCasing.java
+++ b/commons-testing/src/main/java/be/sddevelopment/commons/testing/naming/ReplaceUnderscoredCamelCasing.java
@@ -21,7 +21,7 @@
* #L%
*/
-package be.sddevelopment.commons.testing;
+package be.sddevelopment.commons.testing.naming;
import java.lang.reflect.Method;
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
diff --git a/commons-testing/src/test/java/be/sddevelopment/commons/testing/ConventionsAdherenceTests.java b/commons-testing/src/test/java/be/sddevelopment/commons/testing/ConventionsAdherenceTests.java
new file mode 100755
index 0000000..8ad53a1
--- /dev/null
+++ b/commons-testing/src/test/java/be/sddevelopment/commons/testing/ConventionsAdherenceTests.java
@@ -0,0 +1,32 @@
+/*-
+ * #%L
+ * commons
+ * %%
+ * Copyright (C) 2020 - 2024 SD Development
+ * %%
+ * Licensed under the EUPL, Version 1.1 or – as soon they will be
+ * approved by the European Commission - subsequent versions of the
+ * EUPL (the "Licence");
+ *
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ *
+ * http://ec.europa.eu/idabc/eupl5
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ * #L%
+ */
+
+package be.sddevelopment.commons.testing;
+
+import be.sddevelopment.commons.testing.conventions.CodeConventions;
+import com.tngtech.archunit.junit.AnalyzeClasses;
+
+@AnalyzeClasses(packages = "be.sddevelopment.commons.testing")
+public class ConventionsAdherenceTests implements CodeConventions {
+
+}
diff --git a/commons-testing/src/test/java/be/sddevelopment/commons/testing/ReflectionAssertionUtilsTest.java b/commons-testing/src/test/java/be/sddevelopment/commons/testing/ReflectionAssertionUtilsTest.java
index dc8bd2e..feb15c1 100755
--- a/commons-testing/src/test/java/be/sddevelopment/commons/testing/ReflectionAssertionUtilsTest.java
+++ b/commons-testing/src/test/java/be/sddevelopment/commons/testing/ReflectionAssertionUtilsTest.java
@@ -26,6 +26,7 @@
import static be.sddevelopment.commons.testing.ReflectionAssertionUtils.assertPrivateMember;
import static be.sddevelopment.commons.testing.ReflectionAssertionUtils.assertPrivateMemberReflectionProtection;
+import be.sddevelopment.commons.testing.naming.ReplaceUnderscoredCamelCasing;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
diff --git a/commons-testing/src/test/java/be/sddevelopment/commons/testing/TextualAssertionsTest.java b/commons-testing/src/test/java/be/sddevelopment/commons/testing/TextualAssertionsTest.java
index b1cbf21..97ddaa1 100755
--- a/commons-testing/src/test/java/be/sddevelopment/commons/testing/TextualAssertionsTest.java
+++ b/commons-testing/src/test/java/be/sddevelopment/commons/testing/TextualAssertionsTest.java
@@ -27,6 +27,7 @@
import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
+import be.sddevelopment.commons.testing.naming.ReplaceUnderscoredCamelCasing;
import java.util.Optional;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DisplayNameGeneration;
diff --git a/commons/pom.xml b/commons/pom.xml
index 4179223..999c279 100755
--- a/commons/pom.xml
+++ b/commons/pom.xml
@@ -5,7 +5,7 @@
4.0.0
- be.sddevelopment
+ be.sddevelopment.commons
code-utils
1.0.0-SNAPSHOT
@@ -29,6 +29,10 @@
commons-lang3
3.12.0
+
+ be.sddevelopment.commons
+ commons-kernel
+
@@ -55,9 +59,9 @@
test
- be.sddevelopment
+ be.sddevelopment.commons
commons-testing
- ${parent.version}
+ test
diff --git a/commons/src/main/java/be/sddevelopment/commons/access/AccessProtectionUtils.java b/commons/src/main/java/be/sddevelopment/commons/access/AccessProtectionUtils.java
index f63e700..f1d59f8 100755
--- a/commons/src/main/java/be/sddevelopment/commons/access/AccessProtectionUtils.java
+++ b/commons/src/main/java/be/sddevelopment/commons/access/AccessProtectionUtils.java
@@ -26,6 +26,8 @@
import static be.sddevelopment.commons.access.AccessProtectionUtils.AccessProtectionConstants.UTILITY_CLASS;
import static java.lang.String.format;
+import be.sddevelopment.commons.annotations.Utility;
+
/**
* Shortcodes for class access restrictions and common error codes
*
diff --git a/commons/src/main/java/be/sddevelopment/commons/constants/Strings.java b/commons/src/main/java/be/sddevelopment/commons/constants/Strings.java
index 874ad66..bea39ca 100755
--- a/commons/src/main/java/be/sddevelopment/commons/constants/Strings.java
+++ b/commons/src/main/java/be/sddevelopment/commons/constants/Strings.java
@@ -23,7 +23,9 @@
package be.sddevelopment.commons.constants;
-import be.sddevelopment.commons.access.AccessProtectionUtils;
+import static be.sddevelopment.commons.access.AccessProtectionUtils.utilityClassConstructor;
+
+import be.sddevelopment.commons.annotations.Constants;
/**
@@ -45,12 +47,14 @@
* @created 01.11.20, Sunday
* @since 1.0.0
*/
+@Constants
public final class Strings {
public static final String EMPTY_STRING = "";
public static final String NON_EMPTY_STRING = "Non empty String";
private Strings() {
- AccessProtectionUtils.utilityClassConstructor();
+ utilityClassConstructor();
}
+
}
diff --git a/commons/src/main/java/be/sddevelopment/commons/exceptions/ExceptionSuppressor.java b/commons/src/main/java/be/sddevelopment/commons/exceptions/ExceptionSuppressor.java
index 735bc37..c7bf9e4 100755
--- a/commons/src/main/java/be/sddevelopment/commons/exceptions/ExceptionSuppressor.java
+++ b/commons/src/main/java/be/sddevelopment/commons/exceptions/ExceptionSuppressor.java
@@ -24,7 +24,7 @@
package be.sddevelopment.commons.exceptions;
import be.sddevelopment.commons.access.AccessProtectionUtils;
-import be.sddevelopment.commons.access.Utility;
+import be.sddevelopment.commons.annotations.Utility;
import java.util.Optional;
import java.util.function.Function;
@@ -43,7 +43,8 @@
* more fluent way,
* and to facilitate designs based on throwing Unchecked {@link Exception}s from various
* architectural levels in your codebase.
- * See
* and the documentation of Lombok's @SneakyThrows implementation.
diff --git a/commons/src/test/java/be/sddevelopment/commons/ConventionsAdherenceTests.java b/commons/src/test/java/be/sddevelopment/commons/ConventionsAdherenceTests.java
new file mode 100755
index 0000000..e88a725
--- /dev/null
+++ b/commons/src/test/java/be/sddevelopment/commons/ConventionsAdherenceTests.java
@@ -0,0 +1,32 @@
+/*-
+ * #%L
+ * commons
+ * %%
+ * Copyright (C) 2020 - 2024 SD Development
+ * %%
+ * Licensed under the EUPL, Version 1.1 or – as soon they will be
+ * approved by the European Commission - subsequent versions of the
+ * EUPL (the "Licence");
+ *
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ *
+ * http://ec.europa.eu/idabc/eupl5
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ * #L%
+ */
+
+package be.sddevelopment.commons;
+
+import be.sddevelopment.commons.testing.conventions.CodeConventions;
+import com.tngtech.archunit.junit.AnalyzeClasses;
+
+@AnalyzeClasses(packages = "be.sddevelopment.commons")
+public class ConventionsAdherenceTests implements CodeConventions {
+
+}
diff --git a/commons/src/test/java/be/sddevelopment/commons/access/AccessProtectionUtilsTest.java b/commons/src/test/java/be/sddevelopment/commons/access/AccessProtectionUtilsTest.java
index 0727ad9..d1b80d9 100755
--- a/commons/src/test/java/be/sddevelopment/commons/access/AccessProtectionUtilsTest.java
+++ b/commons/src/test/java/be/sddevelopment/commons/access/AccessProtectionUtilsTest.java
@@ -23,11 +23,11 @@
package be.sddevelopment.commons.access;
+import static be.sddevelopment.commons.testing.ReflectionAssertionUtils.assertPrivateMemberReflectionProtection;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import be.sddevelopment.commons.testing.ReflectionAssertionUtils;
-import be.sddevelopment.commons.testing.ReplaceUnderscoredCamelCasing;
-import org.junit.jupiter.api.BeforeEach;
+import be.sddevelopment.commons.testing.naming.ReplaceUnderscoredCamelCasing;
+import java.lang.reflect.Constructor;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.Test;
@@ -43,31 +43,22 @@
@DisplayNameGeneration(ReplaceUnderscoredCamelCasing.class)
class AccessProtectionUtilsTest {
- private Class> classToTest;
-
- @BeforeEach
- void setUp() throws ClassNotFoundException {
- classToTest = utilityClass();
- }
-
/**
* @created: 27/02/2021
* @reasoning: a private constructor can still be called using Java's Reflection API.
*/
@Test
- void givenAUtilityClassWithAPrivateDefaultConstructor_whenInstantiatingAndOverwritingAccessModifier_anExceptionIsThrown() {
- ReflectionAssertionUtils.assertPrivateMemberReflectionProtection(
- classToTest.getDeclaredConstructors()[0]);
+ void isAUtilityClass() throws NoSuchMethodException {
+ Constructor> constructor = AccessProtectionUtils.class.getDeclaredConstructor();
+
+ assertPrivateMemberReflectionProtection(constructor);
}
@Test
- void givenAUtilityClassWithAPrivateConstructor_whenInstantiating_anIllegalExceptionIsThrown() {
- assertThatThrownBy(() -> classToTest.getDeclaredConstructor().newInstance()).isInstanceOf(
- IllegalAccessException.class);
- }
+ void constantsAreAUtilityClass() throws NoSuchMethodException {
+ Constructor> constructor = AccessProtectionUtils.AccessProtectionConstants.class.getDeclaredConstructor();
- private Class> utilityClass() throws ClassNotFoundException {
- return Class.forName("be.sddevelopment.commons.access.UtilityClass");
+ assertPrivateMemberReflectionProtection(constructor);
}
}
diff --git a/commons/src/test/java/be/sddevelopment/commons/exceptions/ExceptionSuppressorTest.java b/commons/src/test/java/be/sddevelopment/commons/exceptions/ExceptionSuppressorTest.java
index 0142177..b1293c4 100755
--- a/commons/src/test/java/be/sddevelopment/commons/exceptions/ExceptionSuppressorTest.java
+++ b/commons/src/test/java/be/sddevelopment/commons/exceptions/ExceptionSuppressorTest.java
@@ -29,7 +29,7 @@
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import be.sddevelopment.commons.constants.Strings;
-import be.sddevelopment.commons.testing.ReplaceUnderscoredCamelCasing;
+import be.sddevelopment.commons.testing.naming.ReplaceUnderscoredCamelCasing;
import java.net.MalformedURLException;
import java.util.Optional;
import org.assertj.core.api.Condition;
diff --git a/docs/javadoc/be/sddevelopment/commons/access/class-use/Utility.html b/docs/javadoc/be/sddevelopment/commons/access/class-use/Utility.html
index 2ac9b64..8fa7fbf 100755
--- a/docs/javadoc/be/sddevelopment/commons/access/class-use/Utility.html
+++ b/docs/javadoc/be/sddevelopment/commons/access/class-use/Utility.html
@@ -3,7 +3,7 @@
-Uses of Class be.sddevelopment.commons.access.Utility (code-utils 1.0.0-SNAPSHOT API)
+Uses of Class be.sddevelopment.commons.annotations.Utility (code-utils 1.0.0-SNAPSHOT API)
@@ -21,7 +21,7 @@