From 266d370cc43a9ef437f244fc8cf947fd7c22df47 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Thu, 4 Nov 2021 17:24:38 +0300 Subject: [PATCH 01/59] build: set version to `1.0.0-SNAPSHOT` for `development` --- java-commons/pom.xml | 2 +- padla-bom/pom.xml | 8 ++++---- pom.xml | 2 +- reflector/pom.xml | 2 +- tools/pom.xml | 2 +- tools/unsafe-methods-access-generator/pom.xml | 2 +- ultimate-messenger/pom.xml | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/java-commons/pom.xml b/java-commons/pom.xml index 0723bab8..d244edbe 100644 --- a/java-commons/pom.xml +++ b/java-commons/pom.xml @@ -6,7 +6,7 @@ ru.progrm-jarvis padla - 1.0.0-rc.7 + 1.0.0-SNAPSHOT java-commons diff --git a/padla-bom/pom.xml b/padla-bom/pom.xml index 49d3a5ca..f9c59a21 100644 --- a/padla-bom/pom.xml +++ b/padla-bom/pom.xml @@ -6,7 +6,7 @@ ru.progrm-jarvis padla - 1.0.0-rc.7 + 1.0.0-SNAPSHOT padla-bom pom @@ -20,17 +20,17 @@ ru.progrm-jarvis java-commons - 1.0.0-rc.7 + 1.0.0-SNAPSHOT ru.progrm-jarvis reflector - 1.0.0-rc.7 + 1.0.0-SNAPSHOT ru.progrm-jarvis ultimate-messenger - 1.0.0-rc.7 + 1.0.0-SNAPSHOT diff --git a/pom.xml b/pom.xml index 44fe5017..421afcde 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 ru.progrm-jarvis padla - 1.0.0-rc.7 + 1.0.0-SNAPSHOT java-commons reflector diff --git a/reflector/pom.xml b/reflector/pom.xml index ef565307..ad2dea06 100644 --- a/reflector/pom.xml +++ b/reflector/pom.xml @@ -6,7 +6,7 @@ ru.progrm-jarvis padla - 1.0.0-rc.7 + 1.0.0-SNAPSHOT reflector diff --git a/tools/pom.xml b/tools/pom.xml index 78c34e50..32556b07 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -6,7 +6,7 @@ ru.progrm-jarvis padla - 1.0.0-rc.7 + 1.0.0-SNAPSHOT padla-tools pom diff --git a/tools/unsafe-methods-access-generator/pom.xml b/tools/unsafe-methods-access-generator/pom.xml index fcdd1484..7b750b6c 100644 --- a/tools/unsafe-methods-access-generator/pom.xml +++ b/tools/unsafe-methods-access-generator/pom.xml @@ -6,7 +6,7 @@ ru.progrm-jarvis padla-tools - 1.0.0-rc.7 + 1.0.0-SNAPSHOT unsafe-methods-access-generator diff --git a/ultimate-messenger/pom.xml b/ultimate-messenger/pom.xml index 4482fb4a..9023600c 100644 --- a/ultimate-messenger/pom.xml +++ b/ultimate-messenger/pom.xml @@ -6,7 +6,7 @@ ru.progrm-jarvis padla - 1.0.0-rc.7 + 1.0.0-SNAPSHOT ultimate-messenger From bf0794f5380292b3ad9b14b9ad9665f243e70503 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Thu, 4 Nov 2021 17:33:40 +0300 Subject: [PATCH 02/59] build: delete `tools` module --- pom.xml | 1 - tools/pom.xml | 53 ------- tools/unsafe-methods-access-generator/pom.xml | 51 ------- .../UnsafeMethodData.java | 108 --------------- .../UnsafeMethodsAccessGenerator.java | 111 --------------- .../templates/UnsafeMethodsAccess.java.vm | 130 ------------------ 6 files changed, 454 deletions(-) delete mode 100644 tools/pom.xml delete mode 100644 tools/unsafe-methods-access-generator/pom.xml delete mode 100644 tools/unsafe-methods-access-generator/src/main/java/ru/progrm_jarvis/padla/tools/unsafemethodsaccessgenerator/UnsafeMethodData.java delete mode 100644 tools/unsafe-methods-access-generator/src/main/java/ru/progrm_jarvis/padla/tools/unsafemethodsaccessgenerator/UnsafeMethodsAccessGenerator.java delete mode 100644 tools/unsafe-methods-access-generator/src/main/resources/templates/UnsafeMethodsAccess.java.vm diff --git a/pom.xml b/pom.xml index 421afcde..d21be83f 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,6 @@ java-commons reflector ultimate-messenger - tools padla-bom pom diff --git a/tools/pom.xml b/tools/pom.xml deleted file mode 100644 index 32556b07..00000000 --- a/tools/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - 4.0.0 - - ru.progrm-jarvis - padla - 1.0.0-SNAPSHOT - - padla-tools - pom - - unsafe-methods-access-generator - - - - clean package - - - - - org.apache.maven.plugins - maven-jar-plugin - 3.2.0 - - - - org.apache.maven.plugins - maven-deploy-plugin - - true - - - - - - - - - - commons-cli - commons-cli - 1.5.0 - - - org.apache.velocity - velocity - 1.7 - - - - diff --git a/tools/unsafe-methods-access-generator/pom.xml b/tools/unsafe-methods-access-generator/pom.xml deleted file mode 100644 index 7b750b6c..00000000 --- a/tools/unsafe-methods-access-generator/pom.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - 4.0.0 - - ru.progrm-jarvis - padla-tools - 1.0.0-SNAPSHOT - - unsafe-methods-access-generator - - - package - - - - maven-jar-plugin - - - - - ru.progrm_jarvis.padla.tools.unsafemethodsaccessgenerator.UnsafeMethodsAccessGenerator - - - - - - - - - - - commons-cli - commons-cli - - - org.apache.velocity - velocity - - - - org.projectlombok - lombok - - - org.jetbrains - annotations - - - diff --git a/tools/unsafe-methods-access-generator/src/main/java/ru/progrm_jarvis/padla/tools/unsafemethodsaccessgenerator/UnsafeMethodData.java b/tools/unsafe-methods-access-generator/src/main/java/ru/progrm_jarvis/padla/tools/unsafemethodsaccessgenerator/UnsafeMethodData.java deleted file mode 100644 index aebb8929..00000000 --- a/tools/unsafe-methods-access-generator/src/main/java/ru/progrm_jarvis/padla/tools/unsafemethodsaccessgenerator/UnsafeMethodData.java +++ /dev/null @@ -1,108 +0,0 @@ -package ru.progrm_jarvis.padla.tools.unsafemethodsaccessgenerator; - -import lombok.*; -import lombok.experimental.FieldDefaults; -import org.jetbrains.annotations.NotNull; - -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Locale; -import java.util.regex.Pattern; - -@Value -@AllArgsConstructor(access = AccessLevel.PRIVATE) -@FieldDefaults(level = AccessLevel.PRIVATE) -public class UnsafeMethodData { - - private static final @NotNull Locale LOCALE = Locale.ENGLISH; - private static final @NotNull Pattern CAMEL_CASE_SPLIT_PATTERN = Pattern.compile("(?=\\p{Upper})"); - - @NonNull Method method; - @NonNull String upperCamelCaseName; - @NonNull String upperCamelCaseNameWithTypeInfo; - @NonNull String[] signature; - @NonNull String returnType; - boolean returnValue; - - public static UnsafeMethodData from(final @NonNull Method method) { - val upperCamelCaseName = camelCaseToUpperSnakeCase(method.getName()); - return new UnsafeMethodData( - method, upperCamelCaseName, - appendParameterNames(upperCamelCaseName, method), getSignature(method.getParameterTypes()), - getTypeName(method.getReturnType()), - method.getReturnType() != void.class - ); - } - - private static String camelCaseToUpperSnakeCase(final @NotNull CharSequence methodName) { - val words = CAMEL_CASE_SPLIT_PATTERN.split(methodName); - - val length = words.length; - assert length != 0; - if (length == 1) return words[0].toUpperCase(LOCALE); - - val result = new StringBuilder(methodName.length() + length - 1) - .append(words[0]); - - for (var i = 1; i < length; i++) result.append('_').append(words[i]); - - return result.toString().toUpperCase(LOCALE); - } - - private static String getTypeName(@NotNull Class type) { - var depth = 0; - while (type.isArray()) { - type = type.getComponentType(); - depth++; - } - if (depth == 0) return type.getSimpleName(); - - val typeName = type.getSimpleName(); - val result = new StringBuilder(typeName.length() + depth * 2).append(typeName); - for (var i = 0; i < depth; i++) result.append('[').append(']'); - - return result.toString(); - } - - private static String[] getSignature(@SuppressWarnings("rawtypes") final @NotNull Class[] parameterTypes) { - if (true) return Arrays.stream(parameterTypes) - .map(UnsafeMethodData::getTypeName) - .toArray(String[]::new); - final int length; - val signature = new String[length = parameterTypes.length]; - for (int i = 0; i < length; i++) { - var parameterType = parameterTypes[i]; - - final StringBuilder postfix = new StringBuilder(); - while (parameterType.isArray()) { - postfix.append('[').append(']'); - parameterType = parameterType.getComponentType(); - } - signature[i] = parameterType.getSimpleName() + postfix; - } - - return signature; - } - - private static String appendParameterNames(final @NotNull String string, - final @NotNull Method method) { - final int parameterCount = method.getParameterCount(); - if (parameterCount == 0) return string; - - val result = new StringBuilder(string.length() + 1 + parameterCount * 2 /* minimal growth*/) - .append(string).append('_'); - for (var parameterType : method.getParameterTypes()) { - result.append('_'); - var depth = 0; - while (parameterType.isArray()) { - ++depth; - parameterType = parameterType.getComponentType(); - } - if (parameterType.isPrimitive()) result.append('$'); - result.append(parameterType.getSimpleName().toUpperCase(LOCALE)); - for (var i = 0; i < depth; i++) result.append('$'); - } - - return result.toString(); - } -} diff --git a/tools/unsafe-methods-access-generator/src/main/java/ru/progrm_jarvis/padla/tools/unsafemethodsaccessgenerator/UnsafeMethodsAccessGenerator.java b/tools/unsafe-methods-access-generator/src/main/java/ru/progrm_jarvis/padla/tools/unsafemethodsaccessgenerator/UnsafeMethodsAccessGenerator.java deleted file mode 100644 index 33b21db1..00000000 --- a/tools/unsafe-methods-access-generator/src/main/java/ru/progrm_jarvis/padla/tools/unsafemethodsaccessgenerator/UnsafeMethodsAccessGenerator.java +++ /dev/null @@ -1,111 +0,0 @@ -package ru.progrm_jarvis.padla.tools.unsafemethodsaccessgenerator; - -import lombok.NonNull; -import lombok.experimental.UtilityClass; -import lombok.val; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; -import org.apache.velocity.Template; -import org.apache.velocity.VelocityContext; -import org.apache.velocity.app.VelocityEngine; -import org.apache.velocity.runtime.RuntimeConstants; -import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.lang.reflect.Modifier; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; - -/** - * CLI tool used for generating accessor class for {@code Unsafe}. - */ -@UtilityClass -public final class UnsafeMethodsAccessGenerator { - - private final Options OPTIONS = new Options() - .addRequiredOption("c", "class-name", true, "Class name") - .addOption("p", "package-name", true, "Package name"); - - public void main(final @NotNull String... args) throws ParseException, IOException { - final @NotNull String className; - final @Nullable String packageName; - { - val commandLine = new DefaultParser().parse(OPTIONS, args); - - className = commandLine.getOptionValue("class-name"); - packageName = commandLine.getOptionValue('p'); - } - - val engine = new VelocityEngine(); - engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); - engine.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); - engine.init(); - - val template = engine.getTemplate("/templates/UnsafeMethodsAccess.java.vm"); - val writer = new OutputStreamWriter(System.out, StandardCharsets.UTF_8); - writeUnsafeMethodsAccessClass( - className, packageName, template, writer - ); - writer.flush(); // close shouldn't be called on System.out - } - - private void addImport(final @NotNull Collection importedClasses, - @NotNull Class possiblyImportedClass /* may be replaced with content */) { - while (possiblyImportedClass.isArray()) possiblyImportedClass = possiblyImportedClass.getComponentType(); - if (possiblyImportedClass.isPrimitive()) return; - - val className = possiblyImportedClass.getName(); - if (className.startsWith("java.lang.") && className.indexOf('.', 10) == -1) return; - - importedClasses.add(className); - } - - private void writeUnsafeMethodsAccessClass(final @NonNull String className, - final @Nullable String packageName, - final @NonNull Template template, - final @NonNull Writer output) { - final Class unsafeClass; - { - Class sunMiscUnsafeClass; - try { - sunMiscUnsafeClass = Class.forName("sun.misc.Unsafe"); - } catch (final ClassNotFoundException e) { - sunMiscUnsafeClass = null; - } - - if (sunMiscUnsafeClass == null) try { - unsafeClass = Class.forName("jdk.internal.misc.Unsafe"); - } catch (final ClassNotFoundException e) { - throw new Error("Could not find Unsafe class", e); - } else unsafeClass = sunMiscUnsafeClass; - } - - val unsafeMethods = unsafeClass.getMethods(); // we only need public Unsafe methods - val importedClasses = new HashSet(); - for (val unsafeMethod : unsafeMethods) { - addImport(importedClasses, unsafeMethod.getReturnType()); - for (val parameter : unsafeMethod.getParameterTypes()) addImport(importedClasses, parameter); - } - - val context = new VelocityContext(); - context.put("className", className); - context.put("packageName", packageName); - context.put("importedClasses", importedClasses); - context.put( - "unsafeMethods", - Arrays.stream(unsafeMethods) - .filter(method -> !Modifier.isStatic(method.getModifiers())) - .map(UnsafeMethodData::from) - .toArray(UnsafeMethodData[]::new) - ); - - template.merge(context, output); - } -} diff --git a/tools/unsafe-methods-access-generator/src/main/resources/templates/UnsafeMethodsAccess.java.vm b/tools/unsafe-methods-access-generator/src/main/resources/templates/UnsafeMethodsAccess.java.vm deleted file mode 100644 index 6dd988bd..00000000 --- a/tools/unsafe-methods-access-generator/src/main/resources/templates/UnsafeMethodsAccess.java.vm +++ /dev/null @@ -1,130 +0,0 @@ -#* @vtlvariable name="method" type="ru.progrm_jarvis.padla.tools.unsafemethodsaccessgenerator.UnsafeMethodData" *# -## @vtlvariable name="packageName" type="java.lang.String" -## @vtlvariable name="className" type="java.lang.String" -## @vtlvariable name="unsafeClassName" type="java.lang.String" -## @vtlvariable name="importedClasses" type="java.lang.String[]" -## @vtlvariable name="unsafeMethods" type="ru.progrm_jarvis.padla.tools.unsafemethodsaccessgenerator.UnsafeMethodData[]" -#if (!$packageName.blank && !$packageName.equals(""))package $packageName; - -#end## -import lombok.SneakyThrows; -import lombok.experimental.UtilityClass; -import lombok.val; -import ru.progrm_jarvis.javacommons.invoke.InvokeUtil; - -#foreach($importedClass in $importedClasses) -import $importedClass; -#end - -import java.lang.invoke.MethodHandle; - -import static java.lang.invoke.MethodType.methodType; - -@UtilityClass -public class $className { - - private final MethodHandle -#foreach($method in $unsafeMethods) - UNSAFE_${method.upperCamelCaseNameWithTypeInfo}_METHOD#if($foreach.hasNext),#else;#end - -#end - - private final boolean USE_SUN_MISC_UNSAFE; - - static { - final Class unsafeClass; - { - boolean useSunMiscUnsafe = false; - { - Class sunMiscUnsafeClass; - try { - sunMiscUnsafeClass = Class.forName("sun.misc.Unsafe"); - useSunMiscUnsafe = true; - } catch (final ClassNotFoundException e) { - sunMiscUnsafeClass = null; - } - - if (!useSunMiscUnsafe) try { - unsafeClass = Class.forName("jdk.internal.misc.Unsafe"); - useSunMiscUnsafe = false; - } catch (final ClassNotFoundException classNotFoundException) { - throw new RuntimeException("Could not find Unsafe class"); - } else unsafeClass = sunMiscUnsafeClass; - } - USE_SUN_MISC_UNSAFE = useSunMiscUnsafe; - } - val unsafeClassLookup = InvokeUtil.lookup(unsafeClass); - - try { -#foreach($unsafeMethod in $unsafeMethods) - UNSAFE_${unsafeMethod.upperCamelCaseNameWithTypeInfo}_METHOD = unsafeClassLookup.findVirtual( - unsafeClass, "$unsafeMethod.method.name", - methodType(unsafeClass## -#foreach($parameterType in $unsafeMethod.signature), ${parameterType}.class#end) - ); -#end## - } catch (final NoSuchMethodException | IllegalAccessException e) { - throw new IllegalStateException("Could not find Unsafe method", e); - } - } - -## Macro for generating `else` or `return` depending on the method -#macro(returnOrElse $method)## -#if($method.returnValue)return#{else}else#{end} -#end## -## Macro for generating `, p1, p2...` method call parameters -#macro(passTrailingParameters $method)## -#foreach($parameterType in $method.signature), p$foreach.index#end -#end## -## Macro for generating `, final T1 p1, final T2 p2...` method parameters -#macro(methodParameters $method)## -#foreach($parameterType in $method.signature), final $parameterType p$foreach.index#end -#end## -## -## Public static methods to get calles -## -#foreach($method in $unsafeMethods) - public $method.returnType ${method.method.name}(Object unsafe#methodParameters($method)) { - if (USE_SUN_MISC_UNSAFE) #if($method.returnValue)return #end## -SunMiscUnsafeWrapper.${method.method.name}(unsafe#passTrailingParameters($method)); - #returnOrElse($method) ## -JdkInternalMiscUnsafeWrapper.${method.method.name}(unsafe#passTrailingParameters($method)); - } - -#end - -## Macro for generating `UNSAFE_..._METHOD.invokeExact((UnsafeType) unsafe, ...)` -#macro(castUnsafeMethodCall $unsafeType, $method)## -UNSAFE_${method.upperCamelCaseNameWithTypeInfo}_METHOD.invokeExact## -(($unsafeType) unsafe#passTrailingParameters($method))## -#end## -## Macro for generating `return (T) ` if needed -#macro(returnCast $method) -#if($method.returnValue)return ($method.returnType) #end -#end -## -## Method callers for sun.misc.Unsafe -## - private static final class SunMiscUnsafeWrapper { -#foreach($method in $unsafeMethods) - - @SneakyThrows - public static $method.returnType ${method.method.name}(final Object unsafe#methodParameters($method)) { - #returnCast($method)#castUnsafeMethodCall("sun.misc.Unsafe", $method); - } -#end - } - -## -## Method callers for jdk.internal.misc -## - private static final class JdkInternalMiscUnsafeWrapper { -#foreach($method in $unsafeMethods) - - @SneakyThrows - public static $method.returnType ${method.method.name}(final Object unsafe#methodParameters($method)) { - #returnCast($method)#castUnsafeMethodCall("jdk.internal.misc.Unsafe", $method); - } -#end - } -} From 52e5c4d2f0c17496ca6645d48c6d2cf6a196b666 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Nov 2021 10:07:35 +0000 Subject: [PATCH 03/59] build(deps): bump xstream from 1.4.17 to 1.4.18 Bumps [xstream](https://github.com/x-stream/xstream) from 1.4.17 to 1.4.18. - [Release notes](https://github.com/x-stream/xstream/releases) - [Commits](https://github.com/x-stream/xstream/commits) --- updated-dependencies: - dependency-name: com.thoughtworks.xstream:xstream dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d21be83f..48005aff 100644 --- a/pom.xml +++ b/pom.xml @@ -207,7 +207,7 @@ com.thoughtworks.xstream xstream - 1.4.17 + 1.4.18 org.ogce From 28d0d8bef63dfa187f7d60add75915721a36b189 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Fri, 5 Nov 2021 16:14:38 +0300 Subject: [PATCH 04/59] revert: keep `xstream` version `1.4.17` Refs: c939f2a, acc712e This reverts commit c939f2a7093d926f25a37a8cb58e67ef488345db, reversing changes made to acc712e640c8eaa9e46f5fa2a9fd901891b59409. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 48005aff..d21be83f 100644 --- a/pom.xml +++ b/pom.xml @@ -207,7 +207,7 @@ com.thoughtworks.xstream xstream - 1.4.18 + 1.4.17 org.ogce From 5e13cbb9a2856452bb46db26c7b1d08ce302dc25 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Sun, 7 Nov 2021 00:59:55 +0300 Subject: [PATCH 05/59] fix(java-commons): catch `Throwable` in `Result#tryGet(..)` --- .../java/ru/progrm_jarvis/javacommons/object/Result.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java index e7e26f0f..962cafb8 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java @@ -164,13 +164,13 @@ public interface Result extends Supplier { * @return {@link #success(Object) successful result} if the supplier provides the value unexceptionally * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} otherwise */ - static Result tryGet( + static Result tryGet( final @NonNull ThrowingSupplier supplier ) { final T value; try { - value = supplier.get(); - } catch (final Exception x) { + value = supplier.getChecked(); + } catch (final Throwable x) { return error(x); } From b95e6b5c38fa9f6a84440ff00dd3f7f705afe86a Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Sun, 7 Nov 2021 01:00:42 +0300 Subject: [PATCH 06/59] style(java-commons): add missing space after `implements` section of `ThrowingRunnable` --- .../javacommons/util/function/ThrowingRunnable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/ThrowingRunnable.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/ThrowingRunnable.java index de43c06d..98c246b2 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/ThrowingRunnable.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/ThrowingRunnable.java @@ -13,7 +13,7 @@ * @param the type of the exception thrown by the function */ @FunctionalInterface -public interface ThrowingRunnable extends Runnable{ +public interface ThrowingRunnable extends Runnable { /** * Runs an action. From 3bcade1f981c0f78bafef49dcf74b321e53ca0b9 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Sun, 7 Nov 2021 01:30:48 +0300 Subject: [PATCH 07/59] feat(java-commons): add methods for type specific error handling --- .../javacommons/object/Result.java | 108 ++++++++++++- .../javacommons/object/ResultTest.java | 142 ++++++++++++++++++ 2 files changed, 246 insertions(+), 4 deletions(-) create mode 100644 java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java index 962cafb8..f79da5c9 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java @@ -8,6 +8,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import ru.progrm_jarvis.javacommons.annotation.Any; +import ru.progrm_jarvis.javacommons.util.SneakyThrower; +import ru.progrm_jarvis.javacommons.util.TypeHints; +import ru.progrm_jarvis.javacommons.util.TypeHints.TypeHint; import ru.progrm_jarvis.javacommons.util.function.ThrowingRunnable; import ru.progrm_jarvis.javacommons.util.function.ThrowingSupplier; @@ -157,15 +160,65 @@ public interface Result extends Supplier { return nullSuccess(); } + /** + * Creates a result by running the specified runnable. + * + * @param runnable function whose failure indicates the {@link #error(Object) error result} + * @param throwableType class instance representing the type of the thrown exception + * @param type of the thrown throwable + * @return {@link #nullSuccess() successful void-result} if the runnable runs unexceptionally + * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} + * if {@link Class#isAssignableFrom(Class) it is of} the expected type + * @apiNote if an unexpected exception is thrown then it will be rethrown + */ + @SuppressWarnings("unchecked") + static @NotNull Result<@Nullable Void, @NotNull X> tryRunChecked( + final @NonNull ThrowingRunnable runnable, + final @NonNull Class throwableType + ) { + //noinspection OverlyBroadCatchBlock: cannot catch generic exception type + try { + runnable.runChecked(); + } catch (final Throwable x) { + if (throwableType.isAssignableFrom(x.getClass())) return error((X) x); + + return SneakyThrower.sneakyThrow(x); + } + + return nullSuccess(); + } + + /** + * Creates a result by running the specified runnable. + * + * @param runnable function whose failure indicates the {@link #error(Object) error result} + * @param throwableTypeHint array used for throwable type discovery + * @param type of the thrown throwable + * @return {@link #nullSuccess() successful void-result} if the runnable runs unexceptionally + * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} + * if {@link Class#isAssignableFrom(Class) it is of} the expected type + * @apiNote if an unexpected exception is thrown then it will be rethrown + */ + @SafeVarargs + static @NotNull Result<@Nullable Void, @NotNull X> tryRunChecked( + final @NonNull ThrowingRunnable runnable, + @TypeHint final @Nullable X @NonNull ... throwableTypeHint + ) { + return tryRunChecked(runnable, TypeHints.resolve(throwableTypeHint)); + } + /** * Creates a result by getting the value of the specified supplier. * + * @param type of the successful result value * @param supplier provider of the result whose failure indicates the {@link #error(Object) error result} * @return {@link #success(Object) successful result} if the supplier provides the value unexceptionally - * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} otherwise + * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} + * if {@link Class#isAssignableFrom(Class) it is of} the expected type + * @apiNote if an unexpected exception is thrown then it will be rethrown */ static Result tryGet( - final @NonNull ThrowingSupplier supplier + final @NonNull ThrowingSupplier supplier ) { final T value; try { @@ -177,11 +230,58 @@ public interface Result extends Supplier { return success(value); } + /** + * Creates a result by getting the value of the specified supplier. + * + * @param supplier provider of the result whose failure indicates the {@link #error(Object) error result} + * @param throwableType class instance representing the type of the thrown exception + * @param type of the {@link #success(Object) successful result} provided by the given supplier + * @return {@link #success(Object) successful result} if the supplier provides the value unexceptionally + * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} + * if {@link Class#isAssignableFrom(Class) it is of} the expected type + * @apiNote if an unexpected exception is thrown then it will be rethrown + */ + @SuppressWarnings("unchecked") + static Result tryGetChecked( + final @NonNull ThrowingSupplier supplier, + final @NonNull Class throwableType + ) { + final T value; + //noinspection OverlyBroadCatchBlock: cannot catch generic exception type + try { + value = supplier.getChecked(); + } catch (final Throwable x) { + if (throwableType.isAssignableFrom(x.getClass())) return error((X) x); + + return SneakyThrower.sneakyThrow(x); + } + + return success(value); + } + + /** + * Creates a result by getting the value of the specified supplier. + * + * @param supplier provider of the result whose failure indicates the {@link #error(Object) error result} + * @param throwableTypeHint array used for throwable type discovery + * @param type of the thrown throwable + * @param type of the {@link #success(Object) successful result} provided by the given supplier + * @return {@link #success(Object) successful result} if the supplier provides the value unexceptionally + * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} otherwise + */ + @SafeVarargs + static Result tryGetChecked( + final @NonNull ThrowingSupplier supplier, + @TypeHint final @Nullable X @NonNull ... throwableTypeHint + ) { + return tryGetChecked(supplier, TypeHints.resolve(throwableTypeHint)); + } + /** * Creates a result by calling the specified callable. * * @param callable provider of the result whose failure indicates the {@link #error(Object) error result} - * @param type of the result provided by the given callable + * @param type of the {@link #success(Object) successful result} provided by the given supplier * @return {@link #success(Object) successful result} if the callable completes unexceptionally * or an {@link #error(Object) error result} containing the thrown {@link Exception exception} otherwise */ @@ -200,7 +300,7 @@ public interface Result extends Supplier { * Creates a result by calling the specified callable. * * @param callable provider of the result whose failure indicates the {@link #error(Object) error result} - * @param type of the result provided by the given callable + * @param type of the {@link #success(Object) successful result} provided by the given supplier * @return {@link #success(Object) successful result} if the callable completes unexceptionally * or an {@link #error(Object) error result} containing the thrown {@link Exception exception} otherwise * @deprecated in favor of {@link #tryCall(Callable)} diff --git a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java new file mode 100644 index 00000000..f66d78d9 --- /dev/null +++ b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java @@ -0,0 +1,142 @@ +package ru.progrm_jarvis.javacommons.object; + +import lombok.NonNull; +import lombok.experimental.StandardException; +import lombok.experimental.UtilityClass; +import lombok.val; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.*; + +class ResultTest { + + @Test + void test_tryRunChecked_withInferredType_success() { + assertTrue( + Result.tryRunChecked(TestMethods::voidMethodNotThrowingDeclaredIOException).isSuccess() + ); + } + + @Test + void test_tryRunChecked_withInferredType_error() { + val thrown = new IOException("Expected exception"); + assertSame(thrown, + Result.tryRunChecked(() -> TestMethods.voidMethodThrowingDeclaredIOException(thrown)).unwrapError() + ); + } + + @Test + void test_tryRunChecked_withInferredType_rethrow() { + val thrown = new RuntimeException("You didn't expect it, did you?"); + assertSame(thrown, + assertThrows(RuntimeException.class, () -> Result.tryRunChecked( + () -> TestMethods.voidMethodNotThrowingDeclaredIOExceptionButRuntimeException(thrown) + )) + ); + } + + @Test + void test_tryRunChecked_withInferredType_typeInference() { + assertTrue( + Result.tryRunChecked(() -> TestMethods.voidMethodThrowingCustomException(new CustomException())) + .peek(aVoid -> fail("Result should be an error result")) + .peekError(customError -> customError.thisIsACustomError()) + .isError() + ); + } + + @Test + void test_tryGetChecked_withInferredType_success() { + val returned = "Hello world"; + assertSame(returned, + Result.tryGetChecked(() -> TestMethods.stringMethodNotThrowingDeclaredIOException(returned)).unwrap() + ); + } + + @Test + void test_tryGetChecked_withInferredType_error() { + val thrown = new IOException("Expected exception"); + assertSame(thrown, + Result.tryGetChecked(() -> TestMethods.stringMethodThrowingDeclaredIOException(thrown)).unwrapError() + ); + } + + @Test + void test_tryGetChecked_withInferredType_rethrow() { + val thrown = new RuntimeException("You didn't expect it, did you?"); + assertSame(thrown, + assertThrows(RuntimeException.class, () -> Result.tryGetChecked( + () -> TestMethods.stringMethodNotThrowingDeclaredIOExceptionButRuntimeException(thrown) + )) + ); + } + + @Test + void test_tryGetChecked_withInferredType_typeInference() { + assertTrue( + Result.tryGetChecked(() -> TestMethods.stringMethodThrowingCustomException(new CustomException())) + .peek(string -> fail("Result should be an error result")) + .peekError(customError -> customError.thisIsACustomError()) + .isError() + ); + } + + @UtilityClass + private class TestMethods { + + @SuppressWarnings("RedundantThrows") + private void voidMethodNotThrowingDeclaredIOException() throws IOException {} + + private void voidMethodThrowingDeclaredIOException( + final @NonNull IOException thrown + ) throws IOException { + throw thrown; + } + + @SuppressWarnings("RedundantThrows") + private void voidMethodNotThrowingDeclaredIOExceptionButRuntimeException( + final @NonNull RuntimeException thrown + ) throws IOException { + throw thrown; + } + + @SuppressWarnings("RedundantThrows") + private String stringMethodNotThrowingDeclaredIOException(final String returned) throws IOException { + return returned; + } + + private String stringMethodThrowingDeclaredIOException( + final @NonNull IOException thrown + ) throws IOException { + throw thrown; + } + + @SuppressWarnings("RedundantThrows") + private String stringMethodNotThrowingDeclaredIOExceptionButRuntimeException( + final @NonNull RuntimeException thrown + ) throws IOException { + throw thrown; + } + + @SuppressWarnings("RedundantThrows") + private void voidMethodThrowingCustomException( + final @NonNull CustomException customException + ) throws CustomException { + throw customException; + } + + @SuppressWarnings("RedundantThrows") + private String stringMethodThrowingCustomException( + final @NonNull CustomException customException + ) throws CustomException { + throw customException; + } + } + + @StandardException + private final class CustomException extends Exception { + public void thisIsACustomError() {} + } +} \ No newline at end of file From 746ee7dee90005a0b93aaaf325bdb33900f0a947 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Sun, 7 Nov 2021 02:29:42 +0300 Subject: [PATCH 08/59] refactor(java-commons): use `isInstance(..)` instead of `isAssignableFrom(..)` in `Result` --- .../progrm_jarvis/javacommons/object/Result.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java index f79da5c9..2c324047 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java @@ -168,7 +168,7 @@ public interface Result extends Supplier { * @param type of the thrown throwable * @return {@link #nullSuccess() successful void-result} if the runnable runs unexceptionally * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} - * if {@link Class#isAssignableFrom(Class) it is of} the expected type + * if {@link Class#isInstance(Object) it is of} the expected type * @apiNote if an unexpected exception is thrown then it will be rethrown */ @SuppressWarnings("unchecked") @@ -180,7 +180,7 @@ public interface Result extends Supplier { try { runnable.runChecked(); } catch (final Throwable x) { - if (throwableType.isAssignableFrom(x.getClass())) return error((X) x); + if (throwableType.isInstance(x)) return error((X) x); return SneakyThrower.sneakyThrow(x); } @@ -196,7 +196,7 @@ public interface Result extends Supplier { * @param type of the thrown throwable * @return {@link #nullSuccess() successful void-result} if the runnable runs unexceptionally * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} - * if {@link Class#isAssignableFrom(Class) it is of} the expected type + * if {@link Class#isInstance(Object) it is of} the expected type * @apiNote if an unexpected exception is thrown then it will be rethrown */ @SafeVarargs @@ -214,8 +214,6 @@ public interface Result extends Supplier { * @param supplier provider of the result whose failure indicates the {@link #error(Object) error result} * @return {@link #success(Object) successful result} if the supplier provides the value unexceptionally * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} - * if {@link Class#isAssignableFrom(Class) it is of} the expected type - * @apiNote if an unexpected exception is thrown then it will be rethrown */ static Result tryGet( final @NonNull ThrowingSupplier supplier @@ -238,7 +236,8 @@ public interface Result extends Supplier { * @param type of the {@link #success(Object) successful result} provided by the given supplier * @return {@link #success(Object) successful result} if the supplier provides the value unexceptionally * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} - * if {@link Class#isAssignableFrom(Class) it is of} the expected type + * if {@link Class#isInstance(Object) it is of} the expected type + * if {@link Class#isInstance(Object) it is of} the expected type * @apiNote if an unexpected exception is thrown then it will be rethrown */ @SuppressWarnings("unchecked") @@ -251,7 +250,7 @@ public interface Result extends Supplier { try { value = supplier.getChecked(); } catch (final Throwable x) { - if (throwableType.isAssignableFrom(x.getClass())) return error((X) x); + if (throwableType.isInstance(x)) return error((X) x); return SneakyThrower.sneakyThrow(x); } @@ -268,6 +267,8 @@ public interface Result extends Supplier { * @param type of the {@link #success(Object) successful result} provided by the given supplier * @return {@link #success(Object) successful result} if the supplier provides the value unexceptionally * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} otherwise + * if {@link Class#isInstance(Object) it is of} the expected type + * @apiNote if an unexpected exception is thrown then it will be rethrown */ @SafeVarargs static Result tryGetChecked( From bf71caf6bc9a2a870ba8c58f44a496ec76061222 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Sun, 7 Nov 2021 02:35:20 +0300 Subject: [PATCH 09/59] feat(java-commons): give higher priority to type-inferred `try`-methods of `Result` --- .../javacommons/object/Result.java | 70 +++++++++---------- .../javacommons/object/ResultTest.java | 36 +++++----- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java index 2c324047..85b67161 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java @@ -141,25 +141,6 @@ public interface Result extends Supplier { return optional.>map(Result::success).orElseGet(() -> error(errorSupplier.get())); } - /** - * Creates a result by running the specified runnable. - * - * @param runnable function whose failure indicates the {@link #error(Object) error result} - * @return {@link #nullSuccess() successful void-result} if the runnable runs unexceptionally - * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} otherwise - */ - static @NotNull Result<@Nullable Void, ? extends @NotNull Throwable> tryRun( - final @NonNull ThrowingRunnable runnable - ) { - try { - runnable.runChecked(); - } catch (final Throwable x) { - return error(x); - } - - return nullSuccess(); - } - /** * Creates a result by running the specified runnable. * @@ -172,7 +153,7 @@ public interface Result extends Supplier { * @apiNote if an unexpected exception is thrown then it will be rethrown */ @SuppressWarnings("unchecked") - static @NotNull Result<@Nullable Void, @NotNull X> tryRunChecked( + static @NotNull Result<@Nullable Void, @NotNull X> tryRun( final @NonNull ThrowingRunnable runnable, final @NonNull Class throwableType ) { @@ -200,32 +181,30 @@ public interface Result extends Supplier { * @apiNote if an unexpected exception is thrown then it will be rethrown */ @SafeVarargs - static @NotNull Result<@Nullable Void, @NotNull X> tryRunChecked( + static @NotNull Result<@Nullable Void, @NotNull X> tryRun( final @NonNull ThrowingRunnable runnable, @TypeHint final @Nullable X @NonNull ... throwableTypeHint ) { - return tryRunChecked(runnable, TypeHints.resolve(throwableTypeHint)); + return tryRun(runnable, TypeHints.resolve(throwableTypeHint)); } /** - * Creates a result by getting the value of the specified supplier. + * Creates a result by running the specified runnable. * - * @param type of the successful result value - * @param supplier provider of the result whose failure indicates the {@link #error(Object) error result} - * @return {@link #success(Object) successful result} if the supplier provides the value unexceptionally - * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} + * @param runnable function whose failure indicates the {@link #error(Object) error result} + * @return {@link #nullSuccess() successful void-result} if the runnable runs unexceptionally + * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} otherwise */ - static Result tryGet( - final @NonNull ThrowingSupplier supplier + static @NotNull Result<@Nullable Void, ? extends @NotNull Throwable> tryRunCatchAny( + final @NonNull ThrowingRunnable runnable ) { - final T value; try { - value = supplier.getChecked(); + runnable.runChecked(); } catch (final Throwable x) { return error(x); } - return success(value); + return nullSuccess(); } /** @@ -241,7 +220,7 @@ public interface Result extends Supplier { * @apiNote if an unexpected exception is thrown then it will be rethrown */ @SuppressWarnings("unchecked") - static Result tryGetChecked( + static Result tryGet( final @NonNull ThrowingSupplier supplier, final @NonNull Class throwableType ) { @@ -271,11 +250,32 @@ public interface Result extends Supplier { * @apiNote if an unexpected exception is thrown then it will be rethrown */ @SafeVarargs - static Result tryGetChecked( + static Result tryGet( final @NonNull ThrowingSupplier supplier, @TypeHint final @Nullable X @NonNull ... throwableTypeHint ) { - return tryGetChecked(supplier, TypeHints.resolve(throwableTypeHint)); + return tryGet(supplier, TypeHints.resolve(throwableTypeHint)); + } + + /** + * Creates a result by getting the value of the specified supplier. + * + * @param type of the successful result value + * @param supplier provider of the result whose failure indicates the {@link #error(Object) error result} + * @return {@link #success(Object) successful result} if the supplier provides the value unexceptionally + * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} + */ + static Result tryGetCatchAny( + final @NonNull ThrowingSupplier supplier + ) { + final T value; + try { + value = supplier.getChecked(); + } catch (final Throwable x) { + return error(x); + } + + return success(value); } /** diff --git a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java index f66d78d9..391fde19 100644 --- a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java +++ b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java @@ -13,72 +13,72 @@ class ResultTest { @Test - void test_tryRunChecked_withInferredType_success() { + void test_tryRun_withInferredType_success() { assertTrue( - Result.tryRunChecked(TestMethods::voidMethodNotThrowingDeclaredIOException).isSuccess() + Result.tryRun(TestMethods::voidMethodNotThrowingDeclaredIOException).isSuccess() ); } @Test - void test_tryRunChecked_withInferredType_error() { + void test_tryRun_withInferredType_error() { val thrown = new IOException("Expected exception"); assertSame(thrown, - Result.tryRunChecked(() -> TestMethods.voidMethodThrowingDeclaredIOException(thrown)).unwrapError() + Result.tryRun(() -> TestMethods.voidMethodThrowingDeclaredIOException(thrown)).unwrapError() ); } @Test - void test_tryRunChecked_withInferredType_rethrow() { + void test_tryRun_withInferredType_rethrow() { val thrown = new RuntimeException("You didn't expect it, did you?"); assertSame(thrown, - assertThrows(RuntimeException.class, () -> Result.tryRunChecked( + assertThrows(RuntimeException.class, () -> Result.tryRun( () -> TestMethods.voidMethodNotThrowingDeclaredIOExceptionButRuntimeException(thrown) )) ); } @Test - void test_tryRunChecked_withInferredType_typeInference() { + void test_tryRun_withInferredType_typeInference() { assertTrue( - Result.tryRunChecked(() -> TestMethods.voidMethodThrowingCustomException(new CustomException())) + Result.tryRun(() -> TestMethods.voidMethodThrowingCustomException(new CustomException())) .peek(aVoid -> fail("Result should be an error result")) - .peekError(customError -> customError.thisIsACustomError()) + .peekError(CustomException::thisIsACustomError) .isError() ); } @Test - void test_tryGetChecked_withInferredType_success() { + void test_tryGet_withInferredType_success() { val returned = "Hello world"; assertSame(returned, - Result.tryGetChecked(() -> TestMethods.stringMethodNotThrowingDeclaredIOException(returned)).unwrap() + Result.tryGet(() -> TestMethods.stringMethodNotThrowingDeclaredIOException(returned)).unwrap() ); } @Test - void test_tryGetChecked_withInferredType_error() { + void test_tryGet_withInferredType_error() { val thrown = new IOException("Expected exception"); assertSame(thrown, - Result.tryGetChecked(() -> TestMethods.stringMethodThrowingDeclaredIOException(thrown)).unwrapError() + Result.tryGet(() -> TestMethods.stringMethodThrowingDeclaredIOException(thrown)).unwrapError() ); } @Test - void test_tryGetChecked_withInferredType_rethrow() { + void test_tryGet_withInferredType_rethrow() { val thrown = new RuntimeException("You didn't expect it, did you?"); assertSame(thrown, - assertThrows(RuntimeException.class, () -> Result.tryGetChecked( + assertThrows(RuntimeException.class, () -> Result.tryGet( () -> TestMethods.stringMethodNotThrowingDeclaredIOExceptionButRuntimeException(thrown) )) ); } @Test - void test_tryGetChecked_withInferredType_typeInference() { + void test_tryGet_withInferredType_typeInference() { assertTrue( - Result.tryGetChecked(() -> TestMethods.stringMethodThrowingCustomException(new CustomException())) + Result.tryGet(() -> TestMethods.stringMethodThrowingCustomException(new CustomException())) .peek(string -> fail("Result should be an error result")) - .peekError(customError -> customError.thisIsACustomError()) + .peekError(CustomException::thisIsACustomError) .isError() ); } From 1e601af23690f57f337fc666d397d791a834077b Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Sun, 7 Nov 2021 14:58:29 +0300 Subject: [PATCH 10/59] feat(java-commons): add conditional mappers to `Result.Extensions` --- .../javacommons/object/Result.java | 95 ++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java index 85b67161..2c225234 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java @@ -18,6 +18,7 @@ import java.util.concurrent.Callable; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; @@ -1230,7 +1231,7 @@ public T rethrow( * of the ability to specify {@code super}-bounds on generic parameters relative to the other ones */ @SuppressWarnings("unchecked") // Results are immutable so they are always safe to upcast - public Result upcast(final @NotNull Result result) { + public <@Any T, @Any E> Result upcast(final @NotNull Result result) { return (Result) result; } @@ -1242,7 +1243,97 @@ public Result upcast(final @NotNull Result T any(final @NotNull Result result) { - return Extensions.upcast(result).orComputeDefault(Function.identity()); + return Extensions + .upcast(result) + .orComputeDefault(Function.identity()); + } + + /** + * Conditionally maps the {@link #unwrap() successful value} otherwise applying no changes. + * + * @param result given result + * @param predicate condition on which to apply the mapping to the {@link #unwrap() successful value} + * @param mappingFunction function used to map the {@link #unwrap() successful value} + * if it matches the predicate + * @param type of the successful result value + * @param type of the error result value + * @param type of the resulting successful value, super-type of {@code } + * @return the result whose {@link #unwrap() successful value} is mapped if it matches the predicate + */ + public @NotNull Result mapIf( + final @NonNull Result result, + final @NonNull Predicate predicate, + final @NonNull Function mappingFunction + ) { + return Extensions + .upcast(result) + .map(value -> predicate.test(value) ? mappingFunction.apply(value) : value); + } + + /** + * Conditionally maps the {@link #unwrap() successful value} otherwise applying no changes. + * + * @param result given result + * @param predicate condition on which to not apply the mapping to the {@link #unwrap() successful value} + * @param mappingFunction function used to map the {@link #unwrap() successful value} + * if it does not match the predicate + * @param type of the successful result value + * @param type of the error result value + * @param type of the resulting successful value, super-type of {@code } + * @return the result whose {@link #unwrap() successful value} is mapped if it does not match the predicate + */ + public @NotNull Result mapIfNot( + final @NonNull Result result, + final @NonNull Predicate predicate, + final @NonNull Function mappingFunction + ) { + return Extensions + .upcast(result) + .map(value -> predicate.test(value) ? value : mappingFunction.apply(value)); + } + + /** + * Conditionally maps the {@link #unwrapError() error value} otherwise applying no changes. + * + * @param result given result + * @param predicate condition on which to apply the mapping to the {@link #unwrapError() error value} + * @param mappingFunction function used to map the {@link #unwrapError() error value} + * if it matches the predicate + * @param type of the successful result value + * @param type of the error result value + * @param type of the resulting error value, super-type of {@code } + * @return the result whose {@link #unwrapError() error value} is mapped if it matches the predicate + */ + public @NotNull Result mapErrorIf( + final @NonNull Result result, + final @NonNull Predicate predicate, + final @NonNull Function mappingFunction + ) { + return Extensions + .upcast(result) + .mapError(error -> predicate.test(error) ? mappingFunction.apply(error) : error); + } + + /** + * Conditionally maps the {@link #unwrapError() error value} otherwise applying no changes. + * + * @param result given result + * @param predicate condition on which to not apply the mapping to the {@link #unwrapError() error value} + * @param mappingFunction function used to map the {@link #unwrapError() error value} + * if it does not match the predicate + * @param type of the successful result value + * @param type of the error result value + * @param type of the resulting error value, super-type of {@code } + * @return the result whose {@link #unwrapError() error value} is mapped if it does not match the predicate + */ + public @NotNull Result mapErrorIfNot( + final @NonNull Result result, + final @NonNull Predicate predicate, + final @NonNull Function mappingFunction + ) { + return Extensions + .upcast(result) + .mapError(error -> predicate.test(error) ? error : mappingFunction.apply(error)); } } } From 0ba41564c5af94469b0815e39c9a7d6679a4dee8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Nov 2021 10:03:53 +0000 Subject: [PATCH 11/59] build(deps): bump annotations from 22.0.0 to 23.0.0 Bumps [annotations](https://github.com/JetBrains/java-annotations) from 22.0.0 to 23.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/22.0.0...23.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d21be83f..b586de75 100644 --- a/pom.xml +++ b/pom.xml @@ -281,7 +281,7 @@ org.jetbrains annotations - 22.0.0 + 23.0.0 provided true From 246ddf717d7e49fbc2e9fc018e03a274fd1bdc4e Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 18:08:09 +0300 Subject: [PATCH 12/59] build: enable all `javac` lints --- pom.xml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index b586de75..e78d51c9 100644 --- a/pom.xml +++ b/pom.xml @@ -80,6 +80,15 @@ org.apache.maven.plugins maven-compiler-plugin 3.8.1 + + true + ${java.version.minimal} + true + true + + -Xlint:all + + java-11 @@ -88,10 +97,10 @@ 11 + true ${project.basedir}/src/main/java11 - true @@ -101,16 +110,13 @@ 17 + true ${project.basedir}/src/main/java17 - true - - ${java.version.minimal} - org.apache.maven.plugins From cc3a17d2f42dd6a73f5c6e50eef220cd2ac00fdb Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 18:53:12 +0300 Subject: [PATCH 13/59] refactor: resolve `unchecked` warnings --- .../collection/CollectionFactory.java | 1 - .../delegate/AsmDelegateFactory.java | 5 +-- .../javacommons/invoke/InvokeFactory.java | 14 +++---- .../javacommons/invoke/InvokeUtil.java | 25 +++++------ .../invoke/SimpleInvokeFactory.java | 7 ++-- .../progrm_jarvis/javacommons/lazy/Lazy.java | 17 +++++--- .../javacommons/util/TypeHints.java | 19 +-------- .../javacommons/util/UncheckedCasts.java | 42 +++++++++++++++++++ .../format/model/AsmTextModelFactory.java | 19 +-------- .../model/JavassistTextModelFactory.java | 8 ++-- 10 files changed, 83 insertions(+), 74 deletions(-) create mode 100644 java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/UncheckedCasts.java diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/CollectionFactory.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/CollectionFactory.java index c2d8564e..3fd4ac60 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/CollectionFactory.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/CollectionFactory.java @@ -97,7 +97,6 @@ public > Set createImmutableEnumSet(final @NonNull E... val .sorted() .toArray(Enum[]::new); - //noinspection unchecked return (Set) IMMUTABLE_ENUM_SETS.get(enumValues, valuesArray -> { // val enumType = valuesArray.getClass().getComponentType(); diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/delegate/AsmDelegateFactory.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/delegate/AsmDelegateFactory.java index e33f7ecc..8d2ddb0a 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/delegate/AsmDelegateFactory.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/delegate/AsmDelegateFactory.java @@ -15,6 +15,7 @@ import ru.progrm_jarvis.javacommons.cache.Caches; import ru.progrm_jarvis.javacommons.classloading.ClassNamingStrategy; import ru.progrm_jarvis.javacommons.classloading.GcClassDefiners; +import ru.progrm_jarvis.javacommons.util.UncheckedCasts; import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; @@ -248,9 +249,7 @@ public static DelegateFactory create() { } // - //noinspection unchecked - return (Class) GcClassDefiners.getDefault() - .defineClass(LOOKUP, className, clazz.toByteArray()); + return UncheckedCasts.uncheckedClassCast(GcClassDefiners.getDefault().defineClass(LOOKUP, className, clazz.toByteArray())); } @UtilityClass diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeFactory.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeFactory.java index c3fe5b00..48caaeb3 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeFactory.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeFactory.java @@ -4,6 +4,7 @@ import lombok.SneakyThrows; import lombok.val; import org.jetbrains.annotations.Nullable; +import ru.progrm_jarvis.javacommons.util.UncheckedCasts; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -59,10 +60,10 @@ InvokeFactory implementing(@NonNull MethodType functionalInterface, * @param functionalMethodParameterTypes parameter types of the functional method * @return this invoke factory */ - default InvokeFactory implementing(@NonNull Class functionalInterface, - @NonNull String functionalMethodName, - @NonNull Class functionalMethodReturnType, - @NonNull Class... functionalMethodParameterTypes) { + default InvokeFactory implementing(final @NonNull Class functionalInterface, + final @NonNull String functionalMethodName, + final @NonNull Class functionalMethodReturnType, + final @NonNull Class... functionalMethodParameterTypes) { return implementing( methodType(functionalInterface), functionalMethodName, methodType(functionalMethodReturnType, functionalMethodParameterTypes) @@ -77,7 +78,7 @@ default InvokeFactory implementing(@NonNull Class functionalInt * @return this invoke factory * @throws IllegalArgumentException if the given class contains not 1 abstract (aka functional) method */ - default InvokeFactory implementing(@NonNull Class functionalInterface) { + default InvokeFactory implementing(final @NonNull Class functionalInterface) { if (!functionalInterface.isInterface()) throw new IllegalArgumentException( "Expected interface but got " + functionalInterface ); @@ -120,8 +121,7 @@ InvokeFactory via(@NonNull Class targetClass, * @see #via(Constructor) */ default InvokeFactory via(final @NonNull Method method) { - //noinspection unchecked - return via((Class) method.getDeclaringClass(), lookup -> { + return via(UncheckedCasts.uncheckedClassCast(method.getDeclaringClass()), lookup -> { try { return lookup.unreflect(method); } catch (final IllegalAccessException e) { diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeUtil.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeUtil.java index d0095def..c00ba30b 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeUtil.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeUtil.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.NotNull; import ru.progrm_jarvis.javacommons.cache.Cache; import ru.progrm_jarvis.javacommons.cache.Caches; +import ru.progrm_jarvis.javacommons.util.UncheckedCasts; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles.Lookup; @@ -227,11 +228,10 @@ public class InvokeUtil { val lookup = lookup(method.getDeclaringClass()); try { val methodHandle = lookup.unreflect(method); - //noinspection unchecked: generic type of returned object - return (Supplier) metafactory( + return UncheckedCasts.uncheckedObjectCast(metafactory( lookup, SUPPLIER_FUNCTIONAL_METHOD_NAME, SUPPLIER__METHOD_TYPE, OBJECT__METHOD_TYPE, methodHandle, methodHandle.type() - ).getTarget().invokeExact(); + ).getTarget().invokeExact()); } catch (final Throwable x) { throw new RuntimeException( "An exception occurred while trying to convert method " + method + " to Supplier", x @@ -256,12 +256,11 @@ public class InvokeUtil { val lookup = lookup(method.getDeclaringClass()); try { val methodHandle = lookup.unreflect(method); - //noinspection unchecked: generic type of returned object - return (Supplier) metafactory( + return UncheckedCasts.uncheckedObjectCast(metafactory( lookup, SUPPLIER_FUNCTIONAL_METHOD_NAME, SUPPLIER_OBJECT__METHOD_TYPE.changeParameterType(0, target.getClass()), OBJECT__METHOD_TYPE, methodHandle, OBJECT__METHOD_TYPE.changeReturnType(method.getReturnType()) - ).getTarget().invoke(target); + ).getTarget().invoke(target)); } catch (final Throwable x) { throw new RuntimeException( "An exception occurred while trying to convert method " + method + " to Supplier", x @@ -283,11 +282,10 @@ public class InvokeUtil { val lookup = lookup(constructor.getDeclaringClass()); try { val methodHandle = lookup.unreflectConstructor(constructor); - //noinspection unchecked: generic type of returned object - return (Supplier) metafactory( + return UncheckedCasts.uncheckedObjectCast(metafactory( lookup, SUPPLIER_FUNCTIONAL_METHOD_NAME, SUPPLIER__METHOD_TYPE, OBJECT__METHOD_TYPE, methodHandle, methodHandle.type() - ).getTarget().invokeExact(); + ).getTarget().invokeExact()); } catch (final Throwable x) { throw new RuntimeException( "An exception occurred while trying to convert constructor " + constructor + " to Supplier", x @@ -315,8 +313,7 @@ public class InvokeUtil { return () -> { try { - //noinspection unchecked - return (V) methodHandle.invoke(); + return UncheckedCasts.uncheckedObjectCast(methodHandle.invoke()); } catch (final Throwable throwable) { throw new RuntimeException(throwable); } @@ -344,8 +341,7 @@ public class InvokeUtil { return () -> { try { - //noinspection unchecked - return (V) methodHandle.invoke(); + return UncheckedCasts.uncheckedObjectCast(methodHandle.invoke()); } catch (final Throwable throwable) { throw new RuntimeException(throwable); } @@ -373,8 +369,7 @@ public class InvokeUtil { return target -> { try { - //noinspection unchecked - return (V) methodHandle.invoke(target); + return UncheckedCasts.uncheckedObjectCast(methodHandle.invoke(target)); } catch (final Throwable throwable) { throw new RuntimeException(throwable); } diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/SimpleInvokeFactory.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/SimpleInvokeFactory.java index 79223754..4e6fcacb 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/SimpleInvokeFactory.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/SimpleInvokeFactory.java @@ -4,6 +4,7 @@ import lombok.experimental.FieldDefaults; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import ru.progrm_jarvis.javacommons.util.UncheckedCasts; import java.lang.invoke.LambdaMetafactory; import java.lang.invoke.MethodHandle; @@ -128,8 +129,7 @@ public F create() throws Throwable { MethodTypeUtil.integrateTypes(methodHandle.type(), functionalMethodSignature) ).getTarget(); - //noinspection unchecked - return (F) targetMethodHandle.invoke(); + return UncheckedCasts.uncheckedObjectCast(targetMethodHandle.invoke()); } /* Bound */ @@ -141,8 +141,7 @@ public F create() throws Throwable { MethodTypeUtil.integrateTypes(methodHandle.type().dropParameterTypes(0, 1), functionalMethodSignature) ).getTarget(); - //noinspection unchecked - return (F) targetMethodHandle.invoke(target); + return UncheckedCasts.uncheckedObjectCast(targetMethodHandle.invoke(target)); } private static @NotNull T checkSet(final @Nullable T value, final @NotNull String identifier) { diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/lazy/Lazy.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/lazy/Lazy.java index cb12f303..d159d3bf 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/lazy/Lazy.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/lazy/Lazy.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.Nullable; import ru.progrm_jarvis.javacommons.object.ReferenceUtil; import ru.progrm_jarvis.javacommons.object.Result; +import ru.progrm_jarvis.javacommons.util.UncheckedCasts; import java.lang.ref.WeakReference; import java.util.Optional; @@ -433,8 +434,8 @@ public T get() { Object value; if ((value = threadLocalValue.get()) == UNSET_VALUE) threadLocalValue.set(value = valueSupplier.get()); - //noinspection unchecked: value is weakly typed - return (T) value; + // value is now known to be of type `T` + return UncheckedCasts.uncheckedObjectCast(value); } @Override @@ -445,15 +446,19 @@ public boolean isInitialized() { @Override public @Nullable T getInitializedOrNull() { final Object value; - //noinspection unchecked: value is weakly typed - return (value = threadLocalValue.get()) == UNSET_VALUE ? null : (T) value; + // value is either `UNSET_VALUE` or of type `T` + return (value = threadLocalValue.get()) == UNSET_VALUE + ? null + : UncheckedCasts.uncheckedObjectCast(value); } @Override public @NotNull Result getAsResult() { final Object value; - //noinspection unchecked: value is weakly typed - return (value = threadLocalValue.get()) == UNSET_VALUE ? Result.nullError() : Result.success((T) value); + // value is either `UNSET_VALUE` or of type `T` + return (value = threadLocalValue.get()) == UNSET_VALUE + ? Result.nullError() + : Result.success(UncheckedCasts.uncheckedObjectCast(value)); } } } diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/TypeHints.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/TypeHints.java index 7fbaf97c..85447bce 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/TypeHints.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/TypeHints.java @@ -1,7 +1,6 @@ package ru.progrm_jarvis.javacommons.util; import lombok.experimental.UtilityClass; -import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,23 +22,7 @@ public class TypeHints { */ @SuppressWarnings("unchecked") public @NotNull Class resolve(final @Nullable T... typeHint) { - return uncheckedClassCast(typeHint.getClass().getComponentType()); - } - - /** - * Casts the given class object into the specific one. - * - * @param type raw-typed class object - * @param exact wanted type of class object - * @return the provided class object with its type case to the specific one - * - * @apiNote this is effectively no-op - */ - // note: no nullability annotations are present on parameter and return type as cast of `null` is also safe - @Contract("_ -> param1") - @SuppressWarnings("unchecked") - private Class uncheckedClassCast(final Class type) { - return (Class) type; + return UncheckedCasts.uncheckedClassCast(typeHint.getClass().getComponentType()); } /** diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/UncheckedCasts.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/UncheckedCasts.java new file mode 100644 index 00000000..5d16f01d --- /dev/null +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/UncheckedCasts.java @@ -0,0 +1,42 @@ +package ru.progrm_jarvis.javacommons.util; + +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.Contract; + +/** + * Commonly used unchecked casts. + * + * @apiNote parameters can be {@code null} because casting of {@code null} is always correct + */ +@UtilityClass +@SuppressWarnings("unchecked") +public class UncheckedCasts { + + /** + * Casts the given object into the specific generic type. + * + * @param object raw-typed object + * @param exact wanted type of the object + * @return the provided object with its type cast to the specific one + * + * @apiNote this is effectively no-op + */ + @Contract("_ -> param1") + public T uncheckedObjectCast(final Object object) { + return (T) object; + } + + /** + * Casts the given class object into the specific one. + * + * @param type raw-typed class object + * @param exact wanted type of class object + * @return the provided class object with its type cast to the specific one + * + * @apiNote this is effectively no-op + */ + @Contract("_ -> param1") + public Class uncheckedClassCast(final Class type) { + return (Class) type; + } +} diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AsmTextModelFactory.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AsmTextModelFactory.java index ab7df2d6..cc8c98c1 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AsmTextModelFactory.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AsmTextModelFactory.java @@ -17,6 +17,7 @@ import ru.progrm_jarvis.javacommons.lazy.Lazy; import ru.progrm_jarvis.javacommons.object.valuestorage.SimpleValueStorage; import ru.progrm_jarvis.javacommons.object.valuestorage.ValueStorage; +import ru.progrm_jarvis.javacommons.util.UncheckedCasts; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -550,7 +551,7 @@ protected void endModification(final @NotNull StaticAsmNode staticNode) { final MethodHandle constructor; { - final Class> definedClass = uncheckedClassCast( + final Class> definedClass = UncheckedCasts.uncheckedClassCast( GcClassDefiners.getDefault() .defineClass(LOOKUP, className, clazz.toByteArray()) ); @@ -574,22 +575,6 @@ protected void endModification(final @NotNull StaticAsmNode staticNode) { } } - /** - * Casts the given class object into the specific one. - * - * @param type raw-typed class object - * @param exact wanted type of class object - * @return the provided class object with its type cast to the specific one - * - * @apiNote this is effectively no-op - */ - // note: no nullability annotations are present on parameter and return type as cast of `null` is also safe - @Contract("_ -> param1") - @SuppressWarnings("unchecked") - private static Class uncheckedClassCast(final Class type) { - return (Class) type; - } - /** * Casts the given text model into the specific one. * diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/JavassistTextModelFactory.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/JavassistTextModelFactory.java index ebff9cf1..72179303 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/JavassistTextModelFactory.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/JavassistTextModelFactory.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; +import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; @@ -214,11 +215,12 @@ protected static final class JavassistTextModelBuilder } try { - val constructor = GcClassDefiners.getDefault() + @SuppressWarnings("unchecked") val constructor = (Constructor>) GcClassDefiners + .getDefault() .defineClass(LOOKUP, clazz.getName(), clazz.toBytecode()).getDeclaredConstructor(); constructor.setAccessible(true); - // noinspection unchecked - return (TextModel) constructor.newInstance(); + + return constructor.newInstance(); } catch (final IOException | CannotCompileException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new IllegalStateException( From 7cf57d6db5215d75b2413712770b342f9f8e03e3 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 19:00:45 +0300 Subject: [PATCH 14/59] refactor(java-commons): perform minor cleanup of `LazyIteratorToCollectionWrapper` --- .../collection/LazyIteratorToCollectionWrapper.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/LazyIteratorToCollectionWrapper.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/LazyIteratorToCollectionWrapper.java index 0c2e39fc..41e4bfe3 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/LazyIteratorToCollectionWrapper.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/LazyIteratorToCollectionWrapper.java @@ -13,6 +13,7 @@ * It provides lazy access to its entries so that iteration happens only when needed. * * @param type of element stored + * @param type of target collection */ @RequiredArgsConstructor @ToString(includeFieldNames = false) @@ -59,7 +60,7 @@ public class LazyIteratorToCollectionWrapper> impleme * @return {@code true} if the element is contained in the wrapped iterator and {@code false} otherwise */ protected boolean isIteratorContaining(final Object element) { - if (iterator.hasNext()) while (iterator.hasNext()) { + while (iterator.hasNext()) { val nextElement = iterator.next(); if (Objects.equals(element, nextElement)) return true; } From 1b3a8413af354f07246ea184512bc7b34abc15b5 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 19:03:15 +0300 Subject: [PATCH 15/59] refactor(java-commons): rename `StatefulMutableImRunnable` to `StatefulImmutableRunnable` --- .../ru/progrm_jarvis/javacommons/util/function/Runnables.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/Runnables.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/Runnables.java index c57c3aac..c598f97a 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/Runnables.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/Runnables.java @@ -37,7 +37,7 @@ public class Runnables { */ public @NotNull Runnable stateful(final T initialState, final @NonNull Consumer handler) { - return new StatefulMutableImRunnable<>(handler, initialState); + return new StatefulImmutableRunnable<>(handler, initialState); } /** @@ -108,7 +108,7 @@ public class Runnables { */ @AllArgsConstructor(access = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) - private static final class StatefulMutableImRunnable implements Runnable { + private static final class StatefulImmutableRunnable implements Runnable { /** * Handler invoked on each call to {@link #run()} with the state applied to it From 75a22da669db32af3bea8621b26e434ede71752e Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 19:25:09 +0300 Subject: [PATCH 16/59] fix(java-commons): remove `UncheckedCasts#uncheckedObjectCast(..)` which is too unpredictable --- .../javacommons/invoke/InvokeUtil.java | 37 +++++++++++++------ .../invoke/SimpleInvokeFactory.java | 6 +-- .../progrm_jarvis/javacommons/lazy/Lazy.java | 14 +++---- .../javacommons/object/ValueContainer.java | 6 +++ .../javacommons/util/UncheckedCasts.java | 14 ------- 5 files changed, 41 insertions(+), 36 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeUtil.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeUtil.java index c00ba30b..d23c7917 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeUtil.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeUtil.java @@ -7,7 +7,6 @@ import org.jetbrains.annotations.NotNull; import ru.progrm_jarvis.javacommons.cache.Cache; import ru.progrm_jarvis.javacommons.cache.Caches; -import ru.progrm_jarvis.javacommons.util.UncheckedCasts; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles.Lookup; @@ -228,7 +227,7 @@ public class InvokeUtil { val lookup = lookup(method.getDeclaringClass()); try { val methodHandle = lookup.unreflect(method); - return UncheckedCasts.uncheckedObjectCast(metafactory( + return Unchecked.cast((Supplier) metafactory( lookup, SUPPLIER_FUNCTIONAL_METHOD_NAME, SUPPLIER__METHOD_TYPE, OBJECT__METHOD_TYPE, methodHandle, methodHandle.type() ).getTarget().invokeExact()); @@ -256,7 +255,7 @@ public class InvokeUtil { val lookup = lookup(method.getDeclaringClass()); try { val methodHandle = lookup.unreflect(method); - return UncheckedCasts.uncheckedObjectCast(metafactory( + return Unchecked.cast((Supplier) metafactory( lookup, SUPPLIER_FUNCTIONAL_METHOD_NAME, SUPPLIER_OBJECT__METHOD_TYPE.changeParameterType(0, target.getClass()), OBJECT__METHOD_TYPE, methodHandle, OBJECT__METHOD_TYPE.changeReturnType(method.getReturnType()) @@ -282,7 +281,7 @@ public class InvokeUtil { val lookup = lookup(constructor.getDeclaringClass()); try { val methodHandle = lookup.unreflectConstructor(constructor); - return UncheckedCasts.uncheckedObjectCast(metafactory( + return Unchecked.cast((Supplier) metafactory( lookup, SUPPLIER_FUNCTIONAL_METHOD_NAME, SUPPLIER__METHOD_TYPE, OBJECT__METHOD_TYPE, methodHandle, methodHandle.type() ).getTarget().invokeExact()); @@ -301,6 +300,7 @@ public class InvokeUtil { * @return supplier getting the value of the field * @throws IllegalArgumentException if the given field is not static */ + @SuppressWarnings("unchecked") // cast of the value public @NotNull Supplier toStaticGetterSupplier(final @NonNull Field field) { Check.isStatic(field); @@ -313,7 +313,7 @@ public class InvokeUtil { return () -> { try { - return UncheckedCasts.uncheckedObjectCast(methodHandle.invoke()); + return (V) methodHandle.invoke(); } catch (final Throwable throwable) { throw new RuntimeException(throwable); } @@ -329,6 +329,7 @@ public class InvokeUtil { * @return supplier getting the value of the field * @throws IllegalArgumentException if the given field is static */ + @SuppressWarnings("unchecked") // cast of the value public @NotNull Supplier toBoundGetterSupplier(final @NonNull Field field, final @NonNull Object target) { Check.isNotStatic(field); @@ -341,7 +342,7 @@ public class InvokeUtil { return () -> { try { - return UncheckedCasts.uncheckedObjectCast(methodHandle.invoke()); + return (V) methodHandle.invoke(); } catch (final Throwable throwable) { throw new RuntimeException(throwable); } @@ -357,6 +358,7 @@ public class InvokeUtil { * @return function getting the value of the field * @throws IllegalArgumentException if the given field is static */ + @SuppressWarnings("unchecked") // cast of the value public @NotNull Function toGetterFunction(final @NonNull Field field) { Check.isNotStatic(field); @@ -369,7 +371,7 @@ public class InvokeUtil { return target -> { try { - return UncheckedCasts.uncheckedObjectCast(methodHandle.invoke(target)); + return (V) methodHandle.invoke(target); } catch (final Throwable throwable) { throw new RuntimeException(throwable); } @@ -453,7 +455,7 @@ public class InvokeUtil { }; } - private static @NotNull MethodHandle createSetterMethodHandle(final @NonNull Field field, final int modifiers) { + private @NotNull MethodHandle createSetterMethodHandle(final @NonNull Field field, final int modifiers) { final MethodHandle methodHandle; if (Modifier.isFinal(modifiers)) { val accessible = field.isAccessible(); @@ -475,16 +477,16 @@ public class InvokeUtil { @UtilityClass @SuppressWarnings("TypeMayBeWeakened") // the error message are specific to classes - private static final class Check { + private static class Check { - private static void hasNoParameters(final @NotNull Method method) { + private void hasNoParameters(final @NotNull Method method) { final int parameterCount; if ((parameterCount = method.getParameterCount()) != 0) throw new IllegalArgumentException( "Method should have no parameters but it has " + parameterCount ); } - private static void hasNoParameters(final @NotNull Constructor constructor) { + private void hasNoParameters(final @NotNull Constructor constructor) { final int parameterCount; if ((parameterCount = constructor.getParameterCount()) != 0) throw new IllegalArgumentException( "Constructor should have no parameters but it has " + parameterCount @@ -527,4 +529,17 @@ private int isNotStatic(final @NotNull Field field) { return modifiers; } } + + @UtilityClass + @SuppressWarnings("unchecked") + private class Unchecked { + + public Supplier cast(final Supplier supplier) { + return (Supplier) supplier; + } + + public Function cast(final Function function) { + return (Function) function; + } + } } diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/SimpleInvokeFactory.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/SimpleInvokeFactory.java index 4e6fcacb..c8ad2392 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/SimpleInvokeFactory.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/SimpleInvokeFactory.java @@ -4,7 +4,6 @@ import lombok.experimental.FieldDefaults; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import ru.progrm_jarvis.javacommons.util.UncheckedCasts; import java.lang.invoke.LambdaMetafactory; import java.lang.invoke.MethodHandle; @@ -109,6 +108,7 @@ public InvokeFactory unbound() { } @Override + @SuppressWarnings("unchecked") // cast of the value to `F` public F create() throws Throwable { val lookupFactory = checkSet(this.lookupFactory, "Lookup factory"); val functionalInterface = checkSet(this.functionalInterface, "Functional interface"); @@ -129,7 +129,7 @@ public F create() throws Throwable { MethodTypeUtil.integrateTypes(methodHandle.type(), functionalMethodSignature) ).getTarget(); - return UncheckedCasts.uncheckedObjectCast(targetMethodHandle.invoke()); + return (F) targetMethodHandle.invoke(); } /* Bound */ @@ -141,7 +141,7 @@ public F create() throws Throwable { MethodTypeUtil.integrateTypes(methodHandle.type().dropParameterTypes(0, 1), functionalMethodSignature) ).getTarget(); - return UncheckedCasts.uncheckedObjectCast(targetMethodHandle.invoke(target)); + return (F) targetMethodHandle.invoke(target); } private static @NotNull T checkSet(final @Nullable T value, final @NotNull String identifier) { diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/lazy/Lazy.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/lazy/Lazy.java index d159d3bf..ca4d0a1a 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/lazy/Lazy.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/lazy/Lazy.java @@ -7,7 +7,6 @@ import org.jetbrains.annotations.Nullable; import ru.progrm_jarvis.javacommons.object.ReferenceUtil; import ru.progrm_jarvis.javacommons.object.Result; -import ru.progrm_jarvis.javacommons.util.UncheckedCasts; import java.lang.ref.WeakReference; import java.util.Optional; @@ -430,12 +429,13 @@ class ThreadLocalLazy implements Lazy { @NotNull ThreadLocal threadLocalValue; @Override + @SuppressWarnings("unchecked") public T get() { Object value; if ((value = threadLocalValue.get()) == UNSET_VALUE) threadLocalValue.set(value = valueSupplier.get()); // value is now known to be of type `T` - return UncheckedCasts.uncheckedObjectCast(value); + return (T) value; } @Override @@ -444,21 +444,19 @@ public boolean isInitialized() { } @Override + @SuppressWarnings("unchecked") public @Nullable T getInitializedOrNull() { final Object value; // value is either `UNSET_VALUE` or of type `T` - return (value = threadLocalValue.get()) == UNSET_VALUE - ? null - : UncheckedCasts.uncheckedObjectCast(value); + return (value = threadLocalValue.get()) == UNSET_VALUE ? null : (T) value; } @Override + @SuppressWarnings("unchecked") public @NotNull Result getAsResult() { final Object value; // value is either `UNSET_VALUE` or of type `T` - return (value = threadLocalValue.get()) == UNSET_VALUE - ? Result.nullError() - : Result.success(UncheckedCasts.uncheckedObjectCast(value)); + return (value = threadLocalValue.get()) == UNSET_VALUE ? Result.nullError() : Result.success((T) value); } } } diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/ValueContainer.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/ValueContainer.java index e3b64f92..0b2fb541 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/ValueContainer.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/ValueContainer.java @@ -357,6 +357,12 @@ public boolean isPresent() { @NoArgsConstructor @SuppressWarnings("PublicConstructor") class EmptyValueException extends RuntimeException { + + /** + * Version ID of this {@link java.io.Serializable} class + */ + private static final long serialVersionUID = 2021_11_17__0L; + // /** diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/UncheckedCasts.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/UncheckedCasts.java index 5d16f01d..7294b7e5 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/UncheckedCasts.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/UncheckedCasts.java @@ -12,20 +12,6 @@ @SuppressWarnings("unchecked") public class UncheckedCasts { - /** - * Casts the given object into the specific generic type. - * - * @param object raw-typed object - * @param exact wanted type of the object - * @return the provided object with its type cast to the specific one - * - * @apiNote this is effectively no-op - */ - @Contract("_ -> param1") - public T uncheckedObjectCast(final Object object) { - return (T) object; - } - /** * Casts the given class object into the specific one. * From 6740d160a425f39c254f58aa911fde8a325de4c7 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 19:27:28 +0300 Subject: [PATCH 17/59] fix(java-commons): add `serialVersionUID`s to `Throwable`s --- .../ru/progrm_jarvis/javacommons/object/Result.java | 12 ++++++++++++ .../javacommons/bytecode/asm/AsmUtilTest.java | 3 +++ .../javacommons/object/ObjectUtilTest.java | 6 +++++- .../progrm_jarvis/javacommons/object/ResultTest.java | 3 +++ .../object/extension/NullSafetyExtensionsTest.java | 5 ++++- 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java index 2c225234..73d51e57 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java @@ -1090,6 +1090,12 @@ class NullError { @NoArgsConstructor @SuppressWarnings("PublicConstructor") class NotSuccessException extends RuntimeException { + + /** + * Version ID of this {@link java.io.Serializable} class + */ + private static final long serialVersionUID = 2021_11_17__0L; + // /** @@ -1144,6 +1150,12 @@ public NotSuccessException(final String message, final Throwable cause, final bo @NoArgsConstructor @SuppressWarnings("PublicConstructor") class NotErrorException extends RuntimeException { + + /** + * Version ID of this {@link java.io.Serializable} class + */ + private static final long serialVersionUID = 2021_11_17__0L; + // /** diff --git a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/bytecode/asm/AsmUtilTest.java b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/bytecode/asm/AsmUtilTest.java index aeaee551..2b15b03d 100644 --- a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/bytecode/asm/AsmUtilTest.java +++ b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/bytecode/asm/AsmUtilTest.java @@ -121,6 +121,9 @@ public StatusSubject() throws ExpectedException { @SuppressWarnings("PublicConstructor") private static class ExpectedException extends Exception { + + private static final long serialVersionUID = 0l; + public ExpectedException() { super(null, null, true, false); } diff --git a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ObjectUtilTest.java b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ObjectUtilTest.java index 9f9c2f70..cb7b036b 100644 --- a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ObjectUtilTest.java +++ b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ObjectUtilTest.java @@ -67,7 +67,9 @@ void testMap() { throw new ExpectedRuntimeException(); })); - final class CustomException extends RuntimeException {} + final class CustomException extends RuntimeException { + private static final long serialVersionUID = 0l; + } assertThrows(CustomException.class, () -> ObjectUtil.map(null, t -> { throw new CustomException(); })); @@ -127,6 +129,8 @@ void testMapNonNullOrThrow() { private static final class ExpectedRuntimeException extends RuntimeException { + private static final long serialVersionUID = 0l; + @SuppressWarnings("PublicConstructor") public ExpectedRuntimeException() { super(null, null, true, false); diff --git a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java index 391fde19..d4256454 100644 --- a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java +++ b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java @@ -137,6 +137,9 @@ private String stringMethodThrowingCustomException( @StandardException private final class CustomException extends Exception { + + private static final long serialVersionUID = 0l; + public void thisIsACustomError() {} } } \ No newline at end of file diff --git a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/extension/NullSafetyExtensionsTest.java b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/extension/NullSafetyExtensionsTest.java index 1182bed4..c7871530 100644 --- a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/extension/NullSafetyExtensionsTest.java +++ b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/extension/NullSafetyExtensionsTest.java @@ -161,5 +161,8 @@ void _toOptional() { // this class cannot be local @NoArgsConstructor(access = AccessLevel.PRIVATE) - private static final class SuccessException extends Exception {} + private static final class SuccessException extends Exception { + + private static final long serialVersionUID = 0l; + } } \ No newline at end of file From f69a65fff3112d35c8f0c9c2a3929003959c2586 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 19:30:08 +0300 Subject: [PATCH 18/59] refactor(java-commons): deprecate `@DontOverrideEqualsAndHashCode` --- .../javacommons/annotation/DontOverrideEqualsAndHashCode.java | 3 +++ .../ru/progrm_jarvis/javacommons/invoke/LookupFactory.java | 2 -- .../format/model/DebuggingTextModelFactory.java | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/annotation/DontOverrideEqualsAndHashCode.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/annotation/DontOverrideEqualsAndHashCode.java index 4c45e573..d30251d8 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/annotation/DontOverrideEqualsAndHashCode.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/annotation/DontOverrideEqualsAndHashCode.java @@ -5,7 +5,10 @@ /** * Marker indicating that {@link Object#equals(Object)} and {@link Object#hashCode()} methods * are not overridden for this class for some reason. + * + * @deprecated this annotation is applicable by default thus it is redundant */ +@Deprecated @Inherited @Documented @Target(ElementType.TYPE) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/LookupFactory.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/LookupFactory.java index 091e173d..5cb8eb62 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/LookupFactory.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/LookupFactory.java @@ -2,7 +2,6 @@ import lombok.NonNull; import org.jetbrains.annotations.NotNull; -import ru.progrm_jarvis.javacommons.annotation.DontOverrideEqualsAndHashCode; import java.lang.invoke.MethodHandles.Lookup; import java.util.function.Function; @@ -11,7 +10,6 @@ * Factory responsible for creating full-access {@link Lookup lookups}. */ @FunctionalInterface -@DontOverrideEqualsAndHashCode public interface LookupFactory extends Function, Lookup> { @NotNull Lookup create(final @NonNull Class clazz); diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DebuggingTextModelFactory.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DebuggingTextModelFactory.java index ddfee22f..18946a38 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DebuggingTextModelFactory.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DebuggingTextModelFactory.java @@ -18,7 +18,6 @@ * * @param type of object according to which the created text models are formatted */ -@DontOverrideEqualsAndHashCode @RequiredArgsConstructor(access = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public final class DebuggingTextModelFactory implements TextModelFactory { @@ -61,7 +60,6 @@ public final class DebuggingTextModelFactory implements TextModelFactory { } @RequiredArgsConstructor - @DontOverrideEqualsAndHashCode @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) private final class DebuggingTextModelBuilder implements TextModelFactory.TextModelBuilder { From 520ace70cb51354f51c32d9da69f2183a39369fd Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 21:01:41 +0300 Subject: [PATCH 19/59] refactor: cleanup components related to Invoke API --- .../javacommons/invoke/InvokeUtil.java | 1 - .../invoke/InvokeConstructorWrapper.java | 38 ++++++------ .../invoke/InvokeDynamicFieldWrapper.java | 15 ++--- .../invoke/InvokeDynamicMethodWrapper.java | 39 ++++++------ .../invoke/InvokeStaticFieldWrapper.java | 15 +++-- .../invoke/InvokeStaticMethodWrapper.java | 62 +++++++++---------- 6 files changed, 86 insertions(+), 84 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeUtil.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeUtil.java index d23c7917..ae9aa733 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeUtil.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/InvokeUtil.java @@ -96,7 +96,6 @@ public class InvokeUtil { * @return created cached lookup for the given class */ public @NotNull Lookup lookup(final @NonNull Class clazz) { - //noinspection ConstantConditions: the result cannot be null as `create(Class)` is non-null return LOOKUPS.get(clazz, LOOKUP_FACTORY::create); } diff --git a/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeConstructorWrapper.java b/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeConstructorWrapper.java index 636f7300..28ef92c1 100644 --- a/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeConstructorWrapper.java +++ b/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeConstructorWrapper.java @@ -22,19 +22,19 @@ import java.util.function.Supplier; /** - * {@link ru.progrm_jarvis.reflector.wrapper.ConstructorWrapper} based on {@link java.lang.invoke Invoke API}. + * {@link ConstructorWrapper} based on {@link java.lang.invoke Invoke API}. * * @param type of the object instantiated by the wrapped constructor */ @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) @EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = true) -public class InvokeConstructorWrapper<@NotNull T> +public final class InvokeConstructorWrapper extends AbstractConstructorWrapper { /** * Weak cache of allocated instance of this constructor wrapper */ - protected static final @NotNull Cache<@NotNull Constructor, @NotNull ConstructorWrapper> WRAPPER_CACHE + private static final @NotNull Cache<@NotNull Constructor, @NotNull ConstructorWrapper> WRAPPER_CACHE = Caches.weakValuesCache(); /** @@ -49,9 +49,9 @@ public class InvokeConstructorWrapper<@NotNull T> * @param wrapped wrapped object * @param invoker function performing the constructor invocation */ - protected InvokeConstructorWrapper(final @NotNull Class containingClass, - final @NotNull Constructor wrapped, - final @NotNull Function<@NotNull Object[], @NotNull T> invoker) { + private InvokeConstructorWrapper(final @NotNull Class containingClass, + final @NotNull Constructor wrapped, + final @NotNull Function<@NotNull Object[], @NotNull T> invoker) { super(containingClass, wrapped); this.invoker = invoker; } @@ -69,18 +69,18 @@ protected InvokeConstructorWrapper(final @NotNull Class containingC * @return cached constructor wrapper for the given constructor */ @SuppressWarnings("unchecked") - public static <@NotNull T> @NotNull ConstructorWrapper from( + public static @NotNull ConstructorWrapper from( final @NonNull Constructor constructor ) { return (ConstructorWrapper) WRAPPER_CACHE.get(constructor, checkedConstructor -> { switch (checkedConstructor.getParameterCount()) { - case 0: return from(checkedConstructor, generateFrom( + case 0: return from(checkedConstructor, implementFunctionalInterface( Supplier.class, uncheckedConstructorCast(constructor) )); - case 1: return from(checkedConstructor, generateFrom( + case 1: return from(checkedConstructor, implementFunctionalInterface( Function.class, uncheckedConstructorCast(constructor) )); - case 2: return from(checkedConstructor, generateFrom( + case 2: return from(checkedConstructor, implementFunctionalInterface( BiFunction.class, uncheckedConstructorCast(constructor) )); default: { @@ -101,9 +101,9 @@ BiFunction.class, uncheckedConstructorCast(constructor) }); } - private static <@NotNull T> @NotNull ConstructorWrapper from( + private static @NotNull ConstructorWrapper from( final @NotNull Constructor constructor, - final @NotNull Supplier generatedSupplier + final @NotNull Supplier<@NotNull T> generatedSupplier ) { return new InvokeConstructorWrapper<>( constructor.getDeclaringClass(), constructor, @@ -115,9 +115,9 @@ BiFunction.class, uncheckedConstructorCast(constructor) ); } - private static <@NotNull T> @NotNull ConstructorWrapper from( + private static @NotNull ConstructorWrapper from( final @NotNull Constructor constructor, - final @NotNull Function generatedFunction + final @NotNull Function generatedFunction ) { return new InvokeConstructorWrapper<>( constructor.getDeclaringClass(), constructor, @@ -129,9 +129,9 @@ BiFunction.class, uncheckedConstructorCast(constructor) ); } - private static <@NotNull T> @NotNull ConstructorWrapper from( + private static @NotNull ConstructorWrapper from( final @NotNull Constructor constructor, - final @NotNull BiFunction generatedBiFunction + final @NotNull BiFunction generatedBiFunction ) { return new InvokeConstructorWrapper<>( constructor.getDeclaringClass(), constructor, @@ -144,7 +144,7 @@ BiFunction.class, uncheckedConstructorCast(constructor) } @SuppressWarnings("unchecked") - private static <@NotNull T> @NotNull ConstructorWrapper from( + private static @NotNull ConstructorWrapper from( final @NotNull Constructor constructor, final @NotNull MethodHandle methodHandle ) { @@ -170,9 +170,9 @@ private static Constructor uncheckedConstructorCast(final Constructor return (Constructor) type; } - private static <@NotNull F, @NotNull T> @NotNull F generateFrom( + private static @NotNull F implementFunctionalInterface( final @NotNull Class functionalType, - final @NotNull Constructor constructor + final @NotNull Constructor<@NotNull T> constructor ) { return InvokeUtil.invokeFactory() .implementing(functionalType) diff --git a/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeDynamicFieldWrapper.java b/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeDynamicFieldWrapper.java index cef83601..5a88e53a 100644 --- a/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeDynamicFieldWrapper.java +++ b/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeDynamicFieldWrapper.java @@ -24,19 +24,20 @@ */ @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) @EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = true) -public class InvokeDynamicFieldWrapper<@NotNull T, V> +public final class InvokeDynamicFieldWrapper extends AbstractFieldWrapper implements DynamicFieldWrapper { /** * Weak cache of allocated instance of this dynamic field wrapper */ - protected static final @NotNull Cache<@NotNull Field, @NotNull DynamicFieldWrapper> CACHE + private static final @NotNull Cache<@NotNull Field, @NotNull DynamicFieldWrapper> CACHE = Caches.weakValuesCache(); /** * Function performing the field get operation */ @NotNull Function<@NotNull T, V> getter; + /** * Bi-consumer performing the field set operation */ @@ -50,10 +51,10 @@ public class InvokeDynamicFieldWrapper<@NotNull T, V> * @param getter function performing the field get operation * @param setter bi-consumer performing the field set operation */ - protected InvokeDynamicFieldWrapper(final @NotNull Class containingClass, - final @NotNull Field wrapped, - final @NotNull Function<@NotNull T, V> getter, - final @NotNull BiConsumer<@NotNull T, V> setter) { + private InvokeDynamicFieldWrapper(final @NotNull Class containingClass, + final @NotNull Field wrapped, + final @NotNull Function<@NotNull T, V> getter, + final @NotNull BiConsumer<@NotNull T, V> setter) { super(containingClass, wrapped); this.getter = getter; this.setter = setter; @@ -68,7 +69,7 @@ protected InvokeDynamicFieldWrapper(final @NotNull Class containing * @return cached dynamic field wrapper for the given constructor */ @SuppressWarnings("unchecked") - public static <@NotNull T, V> @NotNull DynamicFieldWrapper from( + public static @NotNull DynamicFieldWrapper from( final @NonNull Field field ) { if (Modifier.isStatic(field.getModifiers())) throw new IllegalArgumentException("Field should be non-static"); diff --git a/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeDynamicMethodWrapper.java b/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeDynamicMethodWrapper.java index 961e498d..9de36c5e 100644 --- a/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeDynamicMethodWrapper.java +++ b/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeDynamicMethodWrapper.java @@ -30,7 +30,7 @@ */ @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) @EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = true) -public class InvokeDynamicMethodWrapper<@NotNull T, R> +public final class InvokeDynamicMethodWrapper extends AbstractMethodWrapper implements DynamicMethodWrapper { /** @@ -51,9 +51,9 @@ public class InvokeDynamicMethodWrapper<@NotNull T, R> * @param wrapped wrapped object * @param invoker bi-function performing the method invocation */ - protected InvokeDynamicMethodWrapper(final @NotNull Class containingClass, - final @NotNull Method wrapped, - final @NotNull BiFunction<@NotNull T, Object @NotNull [], R> invoker) { + private InvokeDynamicMethodWrapper(final @NotNull Class containingClass, + final @NotNull Method wrapped, + final @NotNull BiFunction<@NotNull T, Object @NotNull [], R> invoker) { super(containingClass, wrapped); this.invoker = invoker; } @@ -67,7 +67,7 @@ protected InvokeDynamicMethodWrapper(final @NotNull Class containin * @return cached dynamic method wrapper for the given constructor */ @SuppressWarnings("unchecked") - public static <@NotNull T, R> DynamicMethodWrapper from( + public static DynamicMethodWrapper from( final @NonNull Method method ) { if (Modifier.isStatic(method.getModifiers())) throw new IllegalArgumentException("Method should be non-static"); @@ -76,12 +76,11 @@ protected InvokeDynamicMethodWrapper(final @NotNull Class containin val noReturn = checkedMethod.getReturnType() == void.class; switch (checkedMethod.getParameterCount()) { case 0: return noReturn - ? from(checkedMethod, generateImplementation(Consumer.class, checkedMethod)) - : from(checkedMethod, generateImplementation(Function.class, checkedMethod)); + ? from(checkedMethod, implementFunctionalInterface(Consumer.class, checkedMethod)) + : from(checkedMethod, implementFunctionalInterface(Function.class, checkedMethod)); case 1: return noReturn - ? from(checkedMethod, generateImplementation(BiConsumer.class, checkedMethod)) - : from(checkedMethod, generateImplementation(BiFunction.class, checkedMethod) - ); + ? from(checkedMethod, implementFunctionalInterface(BiConsumer.class, checkedMethod)) + : from(checkedMethod, implementFunctionalInterface(BiFunction.class, checkedMethod)); default: { final MethodHandle methodHandle; { @@ -100,8 +99,8 @@ protected InvokeDynamicMethodWrapper(final @NotNull Class containin }); } - @SuppressWarnings("unchecked") - private static <@NotNull T, R> @NotNull DynamicMethodWrapper from( + @SuppressWarnings({"unchecked", "overloads"}) + private static @NotNull DynamicMethodWrapper from( final @NotNull Method method, final @NotNull Consumer generatedConsumer ) { @@ -117,8 +116,8 @@ protected InvokeDynamicMethodWrapper(final @NotNull Class containin ); } - @SuppressWarnings("unchecked") - private static <@NotNull T, R> @NotNull DynamicMethodWrapper from( + @SuppressWarnings({"unchecked", "overloads"}) + private static @NotNull DynamicMethodWrapper from( final @NotNull Method method, final @NotNull BiConsumer generatedBiConsumer ) { @@ -134,8 +133,8 @@ protected InvokeDynamicMethodWrapper(final @NotNull Class containin ); } - @SuppressWarnings("unchecked") - private static <@NotNull T, R> @NotNull DynamicMethodWrapper from( + @SuppressWarnings({"unchecked", "overloads"}) + private static @NotNull DynamicMethodWrapper from( final @NotNull Method method, final @NotNull Function generatedFunction ) { @@ -149,8 +148,8 @@ protected InvokeDynamicMethodWrapper(final @NotNull Class containin ); } - @SuppressWarnings("unchecked") - private static <@NotNull T, R> @NotNull DynamicMethodWrapper from( + @SuppressWarnings({"unchecked", "overloads"}) + private static @NotNull DynamicMethodWrapper from( final @NotNull Method method, final @NotNull BiFunction generatedBiFunction ) { @@ -165,7 +164,7 @@ protected InvokeDynamicMethodWrapper(final @NotNull Class containin } @SuppressWarnings("unchecked") - private static <@NotNull T, R> @NotNull DynamicMethodWrapper from( + private static @NotNull DynamicMethodWrapper from( final @NotNull Method method, final @NotNull MethodHandle methodHandle ) { @@ -192,7 +191,7 @@ public R invoke(final @NotNull T target, final Object @NotNull ... parameters) { return invoker.apply(target, parameters); } - private static <@NotNull F, @NotNull T> @NotNull F generateImplementation( + private static @NotNull F implementFunctionalInterface( final @NotNull Class functionalType, final @NotNull Method method ) { diff --git a/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeStaticFieldWrapper.java b/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeStaticFieldWrapper.java index 37856081..fe98cf3c 100644 --- a/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeStaticFieldWrapper.java +++ b/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeStaticFieldWrapper.java @@ -26,24 +26,27 @@ */ @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) @EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = true) -public class InvokeStaticFieldWrapper<@NotNull T, V> +public final class InvokeStaticFieldWrapper extends AbstractFieldWrapper implements StaticFieldWrapper { /** * Weak cache of allocated instance of this static field wrappers of static fields */ - protected static final @NotNull Cache<@NotNull Field, @NotNull StaticFieldWrapper> STATIC_WRAPPER_CACHE + private static final @NotNull Cache<@NotNull Field, @NotNull StaticFieldWrapper> STATIC_WRAPPER_CACHE = Caches.weakValuesCache(); + /** * Weak cache of allocated instance of this static field wrappers of non-static bound fields */ - protected static final @NotNull Cache< + private static final @NotNull Cache< @NotNull Pair<@NotNull Field, @NotNull ?>, @NotNull StaticFieldWrapper > BOUND_WRAPPER_CACHE = Caches.weakValuesCache(); + /** * Supplier performing the field get operation */ @NonNull Supplier getter; + /** * Consumer performing the field set operation */ @@ -57,9 +60,9 @@ public class InvokeStaticFieldWrapper<@NotNull T, V> * @param getter supplier performing the field get operation * @param setter consumer performing the field set operation */ - protected InvokeStaticFieldWrapper(final @NotNull Class containingClass, - final @NotNull Field wrapped, - final @NotNull Supplier getter, final @NotNull Consumer setter) { + private InvokeStaticFieldWrapper(final @NotNull Class containingClass, + final @NotNull Field wrapped, + final @NotNull Supplier getter, final @NotNull Consumer setter) { super(containingClass, wrapped); this.getter = getter; this.setter = setter; diff --git a/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeStaticMethodWrapper.java b/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeStaticMethodWrapper.java index 8b4427e0..bf312bd5 100644 --- a/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeStaticMethodWrapper.java +++ b/reflector/src/main/java/ru/progrm_jarvis/reflector/wrapper/invoke/InvokeStaticMethodWrapper.java @@ -28,18 +28,18 @@ */ @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) @EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = true) -public class InvokeStaticMethodWrapper<@NotNull T, R> +public final class InvokeStaticMethodWrapper extends AbstractMethodWrapper implements StaticMethodWrapper { /** * Weak cache of allocated instance of this static method wrappers of static methods */ - protected static final @NotNull Cache<@NotNull Method, @NotNull StaticMethodWrapper> STATIC_WRAPPER_CACHE + private static final @NotNull Cache<@NotNull Method, @NotNull StaticMethodWrapper> STATIC_WRAPPER_CACHE = Caches.weakValuesCache(); /** * Weak cache of allocated instance of this static method wrappers of non-static bound methods */ - protected static final @NotNull Cache< + private static final @NotNull Cache< @NotNull Pair<@NotNull Method, @NotNull ?>, @NotNull StaticMethodWrapper > BOUND_WRAPPER_CACHE = Caches.weakValuesCache(); @@ -55,9 +55,9 @@ public class InvokeStaticMethodWrapper<@NotNull T, R> * @param wrapped wrapped object * @param invoker function performing the method invocation */ - protected InvokeStaticMethodWrapper(final @NotNull Class containingClass, - final @NotNull Method wrapped, - final @NotNull Function invoker) { + private InvokeStaticMethodWrapper(final @NotNull Class containingClass, + final @NotNull Method wrapped, + final @NotNull Function invoker) { super(containingClass, wrapped); this.invoker = invoker; } @@ -78,19 +78,19 @@ protected InvokeStaticMethodWrapper(final @NotNull Class containing val noReturn = checkedMethod.getReturnType() == void.class; switch (checkedMethod.getParameterCount()) { case 0: return noReturn ? from( - checkedMethod, generateFrom(Runnable.class, checkedMethod) + checkedMethod, implementFunctionalInterface(Runnable.class, checkedMethod) ) : from( - checkedMethod, (Supplier) generateFrom(Supplier.class, checkedMethod) + checkedMethod, (Supplier) implementFunctionalInterface(Supplier.class, checkedMethod) ); case 1: return noReturn ? from( - checkedMethod, (Consumer) generateFrom(Consumer.class, checkedMethod) + checkedMethod, (Consumer) implementFunctionalInterface(Consumer.class, checkedMethod) ) : from( - checkedMethod, (Function) generateFrom(Function.class, checkedMethod) + checkedMethod, (Function) implementFunctionalInterface(Function.class, checkedMethod) ); case 2: return noReturn ? from( - checkedMethod, (BiConsumer) generateFrom(BiConsumer.class, checkedMethod) + checkedMethod, (BiConsumer) implementFunctionalInterface(BiConsumer.class, checkedMethod) ) : from( - checkedMethod, (BiFunction) generateFrom(BiFunction.class, checkedMethod) + checkedMethod, (BiFunction) implementFunctionalInterface(BiFunction.class, checkedMethod) ); default: { final MethodHandle methodHandle; @@ -131,14 +131,14 @@ checkedMethod, generateFrom(Runnable.class, checkedMethod) val noReturn = checkedMethod.getReturnType() == void.class; switch (checkedMethod.getParameterCount()) { case 0: return noReturn - ? from(checkedMethod, generateFrom(Runnable.class, checkedMethod, target)) - : from(checkedMethod, generateFrom(Supplier.class, checkedMethod, target)); + ? from(checkedMethod, implementFunctionalInterface(Runnable.class, checkedMethod, target)) + : from(checkedMethod, implementFunctionalInterface(Supplier.class, checkedMethod, target)); case 1: return noReturn - ? from(checkedMethod, generateFrom(Consumer.class, checkedMethod, target)) - : from(checkedMethod, generateFrom(Function.class, checkedMethod, target)); + ? from(checkedMethod, implementFunctionalInterface(Consumer.class, checkedMethod, target)) + : from(checkedMethod, implementFunctionalInterface(Function.class, checkedMethod, target)); case 2: return noReturn - ? from(checkedMethod, generateFrom(BiConsumer.class, checkedMethod, target)) - : from(checkedMethod, generateFrom(BiFunction.class, checkedMethod, target)); + ? from(checkedMethod, implementFunctionalInterface(BiConsumer.class, checkedMethod, target)) + : from(checkedMethod, implementFunctionalInterface(BiFunction.class, checkedMethod, target)); default: { final MethodHandle methodHandle; { @@ -158,7 +158,7 @@ checkedMethod, generateFrom(Runnable.class, checkedMethod) } @SuppressWarnings("unchecked") - private static <@NotNull T, R> @NotNull StaticMethodWrapper from( + private static @NotNull StaticMethodWrapper from( final @NotNull Method method, final @NotNull Runnable generatedRunnable ) { @@ -174,8 +174,8 @@ checkedMethod, generateFrom(Runnable.class, checkedMethod) ); } - @SuppressWarnings("unchecked") - private static <@NotNull T, R> @NotNull StaticMethodWrapper from( + @SuppressWarnings({"unchecked", "overloads"}) + private static @NotNull StaticMethodWrapper from( final @NotNull Method method, final @NotNull Consumer generatedConsumer ) { @@ -191,8 +191,8 @@ checkedMethod, generateFrom(Runnable.class, checkedMethod) ); } - @SuppressWarnings("unchecked") - private static <@NotNull T, R> @NotNull StaticMethodWrapper from( + @SuppressWarnings({"unchecked", "overloads"}) + private static @NotNull StaticMethodWrapper from( final @NotNull Method method, final @NotNull BiConsumer generatedBiConsumer ) { @@ -209,7 +209,7 @@ checkedMethod, generateFrom(Runnable.class, checkedMethod) } @SuppressWarnings("unchecked") - private static <@NotNull T, R> @NotNull StaticMethodWrapper from( + private static @NotNull StaticMethodWrapper from( final @NotNull Method method, final @NotNull Supplier generatedSupplier ) { @@ -223,8 +223,8 @@ checkedMethod, generateFrom(Runnable.class, checkedMethod) ); } - @SuppressWarnings("unchecked") - private static <@NotNull T, R> @NotNull StaticMethodWrapper from( + @SuppressWarnings({"unchecked", "overloads"}) + private static @NotNull StaticMethodWrapper from( final @NotNull Method method, final @NotNull Function generatedFunction ) { @@ -238,8 +238,8 @@ checkedMethod, generateFrom(Runnable.class, checkedMethod) ); } - @SuppressWarnings("unchecked") - private static <@NotNull T, R> @NotNull StaticMethodWrapper from( + @SuppressWarnings({"unchecked", "overloads"}) + private static @NotNull StaticMethodWrapper from( final @NotNull Method method, final @NotNull BiFunction generatedBiFunction ) { @@ -254,7 +254,7 @@ checkedMethod, generateFrom(Runnable.class, checkedMethod) } @SuppressWarnings("unchecked") - private static <@NotNull T, R> @NotNull StaticMethodWrapper from( + private static @NotNull StaticMethodWrapper from( final @NotNull Method method, final @NotNull MethodHandle methodHandle ) { @@ -275,7 +275,7 @@ public R invoke(final Object @NotNull ... parameters) { return invoker.apply(parameters); } - private static <@NotNull F, @NotNull T> @NotNull F generateFrom( + private static @NotNull F implementFunctionalInterface( final @NotNull Class functionalType, final @NotNull Method method ) { @@ -285,7 +285,7 @@ public R invoke(final Object @NotNull ... parameters) { .createUnsafely(); } - private static <@NotNull F, @NotNull T> @NotNull F generateFrom( + private static @NotNull F implementFunctionalInterface( final @NotNull Class functionalType, final @NotNull Method method, final T target ) { From b5a505a1dcdbbe191eaccc088a1f86a309f1d7fd Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 21:10:10 +0300 Subject: [PATCH 20/59] refactor(java-commons)!: get rid of ambiguous overloads in `Runnables` --- .../javacommons/util/function/Runnables.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/Runnables.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/Runnables.java index c598f97a..18e99b1b 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/Runnables.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/Runnables.java @@ -66,8 +66,8 @@ public class Runnables { * * @throws NullPointerException if {@code handler} is {@code null} */ - public @NotNull Runnable stateful(final int initialState, - final @NonNull IntUnaryOperator handler) { + public @NotNull Runnable intStateful(final int initialState, + final @NonNull IntUnaryOperator handler) { return new StatefulMutableIntRunnable(handler, initialState); } @@ -81,8 +81,8 @@ public class Runnables { * * @throws NullPointerException if {@code handler} is {@code null} */ - public @NotNull Runnable stateful(final long initialState, - final @NonNull LongUnaryOperator handler) { + public @NotNull Runnable longStateful(final long initialState, + final @NonNull LongUnaryOperator handler) { return new StatefulMutableLongRunnable(handler, initialState); } @@ -96,8 +96,8 @@ public class Runnables { * * @throws NullPointerException if {@code handler} is {@code null} */ - public @NotNull Runnable stateful(final double initialState, - final @NonNull DoubleUnaryOperator handler) { + public @NotNull Runnable doubleStateful(final double initialState, + final @NonNull DoubleUnaryOperator handler) { return new StatefulMutableDoubleRunnable(handler, initialState); } From bc61d354663de39a0846a5edd35bbb41b6e10326 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 21:12:44 +0300 Subject: [PATCH 21/59] refactor(java-commons)!: remove redundant `Runnables#statefule(T, Consumer)` --- .../javacommons/util/function/Runnables.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/Runnables.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/Runnables.java index 18e99b1b..9649d723 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/Runnables.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/Runnables.java @@ -25,21 +25,6 @@ public class Runnables { return () -> {}; } - /** - * Creates a stateful runnable which stores its state mutably. - * - * @param initialState initial state of the created runnable - * @param handler handler invoked on each call to {@link Runnable#run()} with the state applied to it - * @param type of stored state - * @return created stateful runnable - * - * @throws NullPointerException if {@code handler} is {@code null} - */ - public @NotNull Runnable stateful(final T initialState, - final @NonNull Consumer handler) { - return new StatefulImmutableRunnable<>(handler, initialState); - } - /** * Creates a stateful runnable which stores its state immutably. * From 956e5b267785850e2749197baf7c7ecf7afcba2c Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 21:20:46 +0300 Subject: [PATCH 22/59] build: disable `processing` lint This lint gets triggered by usage of annotations which don't require annotation processing (e.g. `org.jetbrains.*`), so it is not reasonable to keep it --- pom.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e78d51c9..2ca7d254 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,10 @@ true true - -Xlint:all + + -Xlint:all,-processing From b0254a9b8d681dcd88d21642d8d45f30fea72760 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 21:30:09 +0300 Subject: [PATCH 23/59] refactor(java-commons)!: rename `BooleanUnaryOperator#andThen(..)` -> `..#andThenPrimitive(..)` This is required because the overload is not lambda-friendly. --- .../javacommons/util/function/BooleanUnaryOperator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/BooleanUnaryOperator.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/BooleanUnaryOperator.java index 309b9bec..1ce6b8c3 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/BooleanUnaryOperator.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/function/BooleanUnaryOperator.java @@ -42,7 +42,7 @@ public interface BooleanUnaryOperator extends BooleanFunction, UnaryOpe * @return a composed operator that first applies the provided operator and then this one * @throws NullPointerException if {@code before} is {@code null} * - * @see #andThen(BooleanUnaryOperator) behaving in opposite manner + * @see #andThenPrimitive(BooleanUnaryOperator) behaving in opposite manner */ @Contract(value = "null -> fail; _ -> _", pure = true) default @NotNull BooleanUnaryOperator composePrimitive(final @NonNull BooleanUnaryOperator before) { @@ -65,7 +65,7 @@ public interface BooleanUnaryOperator extends BooleanFunction, UnaryOpe * @see #composePrimitive(BooleanUnaryOperator) behaving in opposite manner */ @Contract(value = "null -> fail; _ -> _", pure = true) - default @NotNull BooleanUnaryOperator andThen(final @NonNull BooleanUnaryOperator after) { + default @NotNull BooleanUnaryOperator andThenPrimitive(final @NonNull BooleanUnaryOperator after) { return operand -> after.applyAsBoolean(applyAsBoolean(operand)); } From e651b69487080aabb9ee2de1024a73c1b918603c Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 21:34:17 +0300 Subject: [PATCH 24/59] refactor(java-commons)!: remove `LazyIteratorToCollectionWrapper` This class has too unpredictable behaviour while not actually being used --- .../LazyIteratorToCollectionWrapper.java | 251 ------------------ 1 file changed, 251 deletions(-) delete mode 100644 java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/LazyIteratorToCollectionWrapper.java diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/LazyIteratorToCollectionWrapper.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/LazyIteratorToCollectionWrapper.java deleted file mode 100644 index 41e4bfe3..00000000 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/LazyIteratorToCollectionWrapper.java +++ /dev/null @@ -1,251 +0,0 @@ -package ru.progrm_jarvis.javacommons.collection; - -import lombok.*; -import lombok.experimental.FieldDefaults; -import lombok.experimental.NonFinal; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -/** - * A wrapper for {@link Iterator} to make it treated as a {@link Collection}. - * It provides lazy access to its entries so that iteration happens only when needed. - * - * @param type of element stored - * @param type of target collection - */ -@RequiredArgsConstructor -@ToString(includeFieldNames = false) -@EqualsAndHashCode(onlyExplicitlyIncluded = true) -@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) -public class LazyIteratorToCollectionWrapper> implements Collection { - - /** - * Iterator wrapped - */ - @EqualsAndHashCode.Include @NonNull Iterator iterator; - @NonNull C targetCollection; - - /** - * Gets the next element in the wrapped iterator - * - * @return next element in iterator if any or {@code null} if its end was reached. - */ - protected @Nullable E readNextIteratorElement() { - if (iterator.hasNext()) return iterator.next(); - - return null; - } - - /** - * Iterates the wrapped iterator until the specified element is reached. - * - * @param element element to try to reach - * @return found element reference if found and {@code null} false otherwise - */ - protected @Nullable E readIteratorUntilReached(final E element) { - if (iterator.hasNext()) while (iterator.hasNext()) { - val nextElement = iterator.next(); - if (Objects.equals(element, nextElement)) return nextElement; - } - - return null; - } - - /** - * Checks whether the wrapped iterator contains the specified element. - * - * @param element element to check for containment - * @return {@code true} if the element is contained in the wrapped iterator and {@code false} otherwise - */ - protected boolean isIteratorContaining(final Object element) { - while (iterator.hasNext()) { - val nextElement = iterator.next(); - if (Objects.equals(element, nextElement)) return true; - } - - return false; - } - - /** - * Reads all content of the wrapped iterator. - */ - protected void readIteratorFully() { - while (iterator.hasNext()) targetCollection.add(iterator.next()); - } - - @Override - public int size() { - readIteratorFully(); - - return targetCollection.size(); - } - - @Override - public boolean isEmpty() { - return targetCollection.isEmpty() && !iterator.hasNext(); - } - - @Override - public boolean contains(final Object object) { - return targetCollection.contains(object) || isIteratorContaining(object); - } - - @NotNull - @Override - public Iterator iterator() { - return new PublicIterator(); - } - - @NotNull - @Override - public Object[] toArray() { - readIteratorFully(); - - return targetCollection.toArray(); - } - - @NotNull - @Override - @SuppressWarnings({"unchecked", "SuspiciousToArrayCall"}) - public T[] toArray(final T @NotNull ... a) { - readIteratorFully(); - - return targetCollection.toArray(a); - } - - @Override - public boolean add(final E e) { - return targetCollection.add(e); - } - - @Override - public boolean remove(final Object o) { - if (targetCollection.remove(o)) return true; - if (isIteratorContaining(o)) { - iterator.remove(); - - return true; - } - return false; - } - - @Override - public boolean containsAll(@NotNull Collection valuesToFind) { - if (valuesToFind.isEmpty()) return true; - - valuesToFind = new ArrayList<>(valuesToFind); - // remove elements which are definitely contained in the read part of the iterator - //noinspection SuspiciousMethodCalls - valuesToFind.removeAll(targetCollection); - - if (valuesToFind.isEmpty()) return true; - - while (iterator.hasNext()) { - val element = readNextIteratorElement(); - valuesToFind.remove(element); - - if (valuesToFind.isEmpty()) return true; - } - - return false; - } - - @Override - public boolean addAll(final @NotNull Collection elements) { - return targetCollection.addAll(elements); - } - - @Override - public boolean removeAll(@NotNull Collection valuesToRemove) { - if (valuesToRemove.isEmpty()) return false; - - var changed = targetCollection.removeAll(valuesToRemove); - while (iterator.hasNext()) { - val element = iterator.next(); - if (valuesToRemove.contains(element)) changed = true; - else targetCollection.add(element); - } - - return changed; - } - - @Override - public boolean retainAll(final @NotNull Collection valuesToRetain) { - if (valuesToRetain.isEmpty()) { - val changed = !targetCollection.isEmpty(); - targetCollection.clear(); - - return changed; - } - - boolean changed = false; - { - val targetIterator = targetCollection.iterator(); - while (targetIterator.hasNext()) { - val element = targetIterator.next(); - if (!valuesToRetain.contains(element)) { - targetIterator.remove(); - changed = true; - } - } - } - while (iterator.hasNext()) { - val element = iterator.next(); - if (valuesToRetain.contains(element)) targetCollection.add(element); - else changed = true; - } - - return changed; - } - - @Override - public void clear() { - targetCollection.clear(); - while (iterator.hasNext()) iterator.next(); - } - - /** - * Iterator used by this {@link LazyIteratorToCollectionWrapper}. - */ - @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) - protected class PublicIterator implements Iterator { - - /** - * Iterator of the {@link #targetCollection} - */ - @NonNull Iterator collectionIterator = targetCollection.iterator(); - /** - * Flag indicating whether the last {@link Iterator#next()} was called on {@link #collectionIterator} or not - */ - @NonFinal boolean lastReadFromCollection = false; - - @Override - public boolean hasNext() { - return collectionIterator.hasNext() || iterator.hasNext(); - } - - @Override - public E next() { - if (collectionIterator.hasNext()) { - lastReadFromCollection = true; - - return collectionIterator.next(); - } - if (iterator.hasNext()) { - lastReadFromCollection = false; - - return iterator.next(); - } - - throw new NoSuchElementException("No more elements available"); - } - - @Override - public void remove() { - if (lastReadFromCollection) collectionIterator.remove(); - else iterator.remove(); - } - } -} From 601a0a0df547904eb585de7a4c178383fc2f198c Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 21:35:26 +0300 Subject: [PATCH 25/59] chore(ultimate-messenger): remove redundant import of `DebuggingTextModelFactory` --- .../format/model/DebuggingTextModelFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DebuggingTextModelFactory.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DebuggingTextModelFactory.java index 18946a38..fef196dd 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DebuggingTextModelFactory.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DebuggingTextModelFactory.java @@ -5,7 +5,6 @@ import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; import org.jetbrains.annotations.NotNull; -import ru.progrm_jarvis.javacommons.annotation.DontOverrideEqualsAndHashCode; import ru.progrm_jarvis.ultimatemessenger.format.util.StringMicroOptimizationUtil; import java.util.function.Consumer; From f5f9b40756429d0af3bd8790e3c3d718f9cf1c1b Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 21:36:47 +0300 Subject: [PATCH 26/59] chore(java-commons): suppress `varargs` warning on tricky `@SafeVarargs` usages --- .../javacommons/collection/CollectionFactory.java | 12 ++++++------ .../ru/progrm_jarvis/javacommons/object/Result.java | 2 ++ .../ru/progrm_jarvis/javacommons/range/Range.java | 10 ++++++++++ .../javacommons/util/stream/AutoEnumCollectors.java | 3 +++ .../javacommons/util/stream/EnumCollectors.java | 5 ++++- .../javacommons/util/stream/EnumCollectorsTest.java | 2 +- 6 files changed, 26 insertions(+), 8 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/CollectionFactory.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/CollectionFactory.java index 3fd4ac60..fc6404c2 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/CollectionFactory.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/CollectionFactory.java @@ -36,12 +36,12 @@ public class CollectionFactory { /** * {@link Lookup lookup} of this class. */ - private static final Lookup LOOKUP = MethodHandles.lookup(); + private final Lookup LOOKUP = MethodHandles.lookup(); /** * Class naming strategy used to allocate names for generated immutable enum set classes */ - private static final @NonNull ClassNamingStrategy IMMUTABLE_ENUM_SET_CLASS_NAMING_STRATEGY = ClassNamingStrategy + private final @NonNull ClassNamingStrategy IMMUTABLE_ENUM_SET_CLASS_NAMING_STRATEGY = ClassNamingStrategy .createPaginated(CollectionFactory.class.getName() + "$$Generated$$ImmutableEnumSet$$"); /** @@ -57,18 +57,18 @@ public class CollectionFactory { /** * {@link CtClass} representation of {@link AbstractImmutableSet} wrapped in {@link Lazy} */ - private static final @NonNull Lazy ABSTRACT_IMMUTABLE_SET_CT_CLASS = Lazy + private final @NonNull Lazy ABSTRACT_IMMUTABLE_SET_CT_CLASS = Lazy .createThreadSafe(() -> toCtClass(AbstractImmutableSet.class)); /** * Array storing single reference to {@link CtClass} representation of {@link Iterator} wrapped in {@link Lazy} */ - private static final @NonNull Lazy ITERATOR_CT_CLASS_ARRAY = Lazy + private final @NonNull Lazy ITERATOR_CT_CLASS_ARRAY = Lazy .createThreadSafe(() -> new CtClass[]{toCtClass(Iterator.class)}); /** * Empty array of {@link CtClass}es. */ - public static final @NotNull CtClass @NotNull @Unmodifiable [] EMPTY_CT_CLASS_ARRAY = new CtClass[0]; + public final @NotNull CtClass @NotNull @Unmodifiable [] EMPTY_CT_CLASS_ARRAY = new CtClass[0]; /** * Creates an immutable enum {@link Set set} from the given array of stored enum constants. @@ -83,7 +83,7 @@ public class CollectionFactory { * instanceof} and {@code switch} by {@link Enum#ordinal()} are used for containment-related checks and {@link} */ @SafeVarargs - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "varargs"}) @Deprecated // should be remade via ASM or totally removed due to specific behaviour of anonymous class referencing @UsesBytecodeModification(value = CommonBytecodeLibrary.JAVASSIST, optional = true) public > Set createImmutableEnumSet(final @NonNull E... values) { diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java index 73d51e57..1a0d407f 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java @@ -182,6 +182,7 @@ public interface Result extends Supplier { * @apiNote if an unexpected exception is thrown then it will be rethrown */ @SafeVarargs + @SuppressWarnings("varargs") static @NotNull Result<@Nullable Void, @NotNull X> tryRun( final @NonNull ThrowingRunnable runnable, @TypeHint final @Nullable X @NonNull ... throwableTypeHint @@ -251,6 +252,7 @@ public interface Result extends Supplier { * @apiNote if an unexpected exception is thrown then it will be rethrown */ @SafeVarargs + @SuppressWarnings("varargs") static Result tryGet( final @NonNull ThrowingSupplier supplier, @TypeHint final @Nullable X @NonNull ... throwableTypeHint diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/range/Range.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/range/Range.java index 3bcdf145..4505fee3 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/range/Range.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/range/Range.java @@ -100,6 +100,7 @@ default boolean includes(final T value) { * @apiNote this takes ownership over {@code values} */ @SafeVarargs + @SuppressWarnings("varargs") static @NotNull Range only(final @Own T @Own @NonNull ... values) { Arrays.sort(values); @@ -129,6 +130,7 @@ default boolean includes(final T value) { * @apiNote this copies {@code values} not preserving order */ @SafeVarargs + @SuppressWarnings("varargs") static @NotNull Range onlyCopy(final @Own T @Ref @NonNull ... values) { return only(Arrays.copyOf(values, values.length)); } @@ -190,6 +192,7 @@ default boolean includes(final T value) { * @apiNote this takes ownership over {@code values} */ @SafeVarargs + @SuppressWarnings("varargs") static @NotNull Range except(final @Own T @Own @NonNull ... values) { Arrays.sort(values); @@ -219,6 +222,7 @@ default boolean includes(final T value) { * @apiNote this copies {@code values} not preserving order */ @SafeVarargs + @SuppressWarnings("varargs") static @NotNull Range exceptCopy(final @Own T @Own @NonNull ... values) { return except(Arrays.copyOf(values, values.length)); } @@ -359,6 +363,7 @@ default boolean includes(final T value) { * @apiNote this takes ownership over {@code ranges} */ @SafeVarargs + @SuppressWarnings("varargs") static @NotNull Range anyOf(final @Ref @NotNull Range @NonNull ... ranges) { return value -> { for (val range : ranges) if (range.includes(value)) return true; @@ -394,6 +399,7 @@ default boolean includes(final T value) { * @apiNote this copies {@code ranges} preserving order */ @SafeVarargs + @SuppressWarnings("varargs") static @NotNull Range anyOfCopy(final @Ref @NotNull Range @NonNull ... ranges) { return anyOf(Arrays.copyOf(ranges, ranges.length)); } @@ -434,6 +440,7 @@ default boolean includes(final T value) { * @apiNote this takes ownership over {@code ranges} */ @SafeVarargs + @SuppressWarnings("varargs") static @NotNull Range allOf(final @Ref @NotNull Range @NonNull ... ranges) { return value -> { for (val range : ranges) if (!range.includes(value)) return false; @@ -469,6 +476,7 @@ default boolean includes(final T value) { * @apiNote this copies {@code ranges} preserving order */ @SafeVarargs + @SuppressWarnings("varargs") static @NotNull Range allOfCopy(final @Ref @NotNull Range @NonNull ... ranges) { return allOf(Arrays.copyOf(ranges, ranges.length)); } @@ -509,6 +517,7 @@ default boolean includes(final T value) { * @apiNote this takes ownership over {@code ranges} */ @SafeVarargs + @SuppressWarnings("varargs") static @NotNull Range noneOf(final @Ref @NotNull Range @NonNull ... ranges) { return value -> { for (val range : ranges) if (range.includes(value)) return false; @@ -544,6 +553,7 @@ default boolean includes(final T value) { * @apiNote this copies {@code ranges} preserving order */ @SafeVarargs + @SuppressWarnings("varargs") static @NotNull Range noneOfCopy(final @Ref @NotNull Range @NonNull ... ranges) { return noneOf(Arrays.copyOf(ranges, ranges.length)); } diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/AutoEnumCollectors.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/AutoEnumCollectors.java index 01001dc6..6df595be 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/AutoEnumCollectors.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/AutoEnumCollectors.java @@ -35,6 +35,7 @@ public class AutoEnumCollectors { * @return a collector collecting al its elements into an enum-map */ @SafeVarargs + @SuppressWarnings("varargs") public , V> @NotNull Collector> toEnumMap( final @NonNull Function keyMapper, final @NonNull Function valueMapper, @@ -55,6 +56,7 @@ public class AutoEnumCollectors { * @return a collector collecting al its elements into an enum-map */ @SafeVarargs + @SuppressWarnings("varargs") public , V> @NotNull Collector> toEnumMap( final @NonNull Function valueMapper, final @NonNull BinaryOperator merger, @@ -71,6 +73,7 @@ public class AutoEnumCollectors { * @return a collector collecting al its elements into an enum-set */ @SafeVarargs + @SuppressWarnings("varargs") public > Collector> toEnumSet(final @Nullable E @NonNull ... typeHint) { return EnumCollectors.toEnumSet(TypeHints.resolve(typeHint)); } diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/EnumCollectors.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/EnumCollectors.java index 23a7eafa..bf2b5dcd 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/EnumCollectors.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/EnumCollectors.java @@ -62,6 +62,7 @@ public class EnumCollectors { * @return a collector collecting al its elements into an enum-map */ @SafeVarargs + @SuppressWarnings("varargs") public , V> @NotNull Collector> toEnumMap( final @NonNull Function keyMapper, final @NonNull Function valueMapper, @@ -135,6 +136,7 @@ public class EnumCollectors { * @return a collector collecting al its elements into an enum-map */ @SafeVarargs + @SuppressWarnings("varargs") public , V> @NotNull Collector> toEnumMap( final @NonNull Function valueMapper, final @NonNull BinaryOperator merger, @@ -164,6 +166,7 @@ public class EnumCollectors { * @return a collector collecting al its elements into an enum-set */ @SafeVarargs + @SuppressWarnings("varargs") public > Collector> toEnumSet( @TypeHint final @Nullable E @NonNull ... typeHint ) { @@ -177,7 +180,7 @@ public class EnumCollectors { * @param type of the mapped value * @return default throwing merger */ - private static @NotNull BinaryOperator throwingMerger() { + private @NotNull BinaryOperator throwingMerger() { return (left, right) -> { throw new IllegalStateException("Duplicate elements " + left + " and " + right); }; diff --git a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/util/stream/EnumCollectorsTest.java b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/util/stream/EnumCollectorsTest.java index 68ac1e2c..028efc8f 100644 --- a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/util/stream/EnumCollectorsTest.java +++ b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/util/stream/EnumCollectorsTest.java @@ -82,7 +82,7 @@ void toEnumMap_full(final @NonNull Stream<@NotNull String> enumNames, @ParameterizedTest @MethodSource("enumNameMaps") void toEnumMap_full_viaHint(final @NonNull Stream<@NotNull String> enumNames, - final @NonNull Map<@NotNull MyEnum, @NotNull Integer> result) { + final @NonNull Map<@NotNull MyEnum, @NotNull Integer> result) { assertThat( enumNames.collect(EnumCollectors.toEnumMap( MyEnum::valueOf, From e57dfed74039503fb4caf48ceb5bb3917905da7e Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 21:48:40 +0300 Subject: [PATCH 27/59] chore: use uppercase `L` in `long` literals --- .../progrm_jarvis/javacommons/bytecode/asm/AsmUtilTest.java | 2 +- .../ru/progrm_jarvis/javacommons/object/ObjectUtilTest.java | 4 ++-- .../java/ru/progrm_jarvis/javacommons/object/ResultTest.java | 2 +- .../object/extension/NullSafetyExtensionsTest.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/bytecode/asm/AsmUtilTest.java b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/bytecode/asm/AsmUtilTest.java index 2b15b03d..2a31903d 100644 --- a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/bytecode/asm/AsmUtilTest.java +++ b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/bytecode/asm/AsmUtilTest.java @@ -122,7 +122,7 @@ public StatusSubject() throws ExpectedException { @SuppressWarnings("PublicConstructor") private static class ExpectedException extends Exception { - private static final long serialVersionUID = 0l; + private static final long serialVersionUID = 0L; public ExpectedException() { super(null, null, true, false); diff --git a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ObjectUtilTest.java b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ObjectUtilTest.java index cb7b036b..7e1178c7 100644 --- a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ObjectUtilTest.java +++ b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ObjectUtilTest.java @@ -68,7 +68,7 @@ void testMap() { })); final class CustomException extends RuntimeException { - private static final long serialVersionUID = 0l; + private static final long serialVersionUID = 0L; } assertThrows(CustomException.class, () -> ObjectUtil.map(null, t -> { throw new CustomException(); @@ -129,7 +129,7 @@ void testMapNonNullOrThrow() { private static final class ExpectedRuntimeException extends RuntimeException { - private static final long serialVersionUID = 0l; + private static final long serialVersionUID = 0L; @SuppressWarnings("PublicConstructor") public ExpectedRuntimeException() { diff --git a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java index d4256454..b73bcfbd 100644 --- a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java +++ b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/ResultTest.java @@ -138,7 +138,7 @@ private String stringMethodThrowingCustomException( @StandardException private final class CustomException extends Exception { - private static final long serialVersionUID = 0l; + private static final long serialVersionUID = 0L; public void thisIsACustomError() {} } diff --git a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/extension/NullSafetyExtensionsTest.java b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/extension/NullSafetyExtensionsTest.java index c7871530..7b70b9a8 100644 --- a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/extension/NullSafetyExtensionsTest.java +++ b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/object/extension/NullSafetyExtensionsTest.java @@ -163,6 +163,6 @@ void _toOptional() { @NoArgsConstructor(access = AccessLevel.PRIVATE) private static final class SuccessException extends Exception { - private static final long serialVersionUID = 0l; + private static final long serialVersionUID = 0L; } } \ No newline at end of file From ed67e6eb0b00c06500aef813136ea0b608fb381b Mon Sep 17 00:00:00 2001 From: PROgrm_JARvis Date: Wed, 17 Nov 2021 21:59:14 +0300 Subject: [PATCH 28/59] docs: add `SECURITY.md` This adds a simple security policy. --- SECURITY.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..f7f82f12 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,18 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------------ | ------------------ | +| [1.0.0-rc.7] | :heavy_check_mark: | +| < 1.0.0-rc.7 | :x: | + +## Reporting a Vulnerability + +In order to report a vulnerability simply create an [issues](https://github.com/JarvisCraft/padla/issues) for it. + +These are checked regularly and are the primary support channel. + + + +[1.0.0-rc.7]: https://mvnrepository.com/artifact/ru.progrm-jarvis/padla/1.0.0-rc.7 From 0e79528539ac9cc27374e4cfe61ce42ce22310d7 Mon Sep 17 00:00:00 2001 From: PROgrm_JARvis Date: Wed, 17 Nov 2021 22:12:18 +0300 Subject: [PATCH 29/59] ci: configure CodeQL --- .github/workflows/codeql-analysis.yaml | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yaml diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml new file mode 100644 index 00000000..89c03c13 --- /dev/null +++ b/.github/workflows/codeql-analysis.yaml @@ -0,0 +1,34 @@ +name: CodeQL + +on: + push: + branches: [ master, development ] + pull_request: + branches: [ master, development ] + schedule: + - cron: '00 12 * * *' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + permissions: + actions: read + contents: read + security-events: write + + steps: + - name: Checkout repository + uses: actions/checkout@v2.4.0 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v1.0.23 + with: + languages: java + + - name: Autobuild + uses: github/codeql-action/autobuild@v1.0.23 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1.0.23 From 6efa8d4383664d4cbe9135032499164494b67d0c Mon Sep 17 00:00:00 2001 From: PROgrm_JARvis Date: Wed, 17 Nov 2021 22:18:38 +0300 Subject: [PATCH 30/59] ci: setup Java explicitly and cache local Maven repository --- .github/workflows/codeql-analysis.yaml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index 89c03c13..ce99ccee 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -19,8 +19,14 @@ jobs: security-events: write steps: - - name: Checkout repository - uses: actions/checkout@v2.4.0 + - uses: actions/checkout@v2.4.0 + + - name: Set up Java 17 + uses: actions/setup-java@v2.3.1 + with: + distribution: 'zulu' + java-version: '17' + cache: 'maven' - name: Initialize CodeQL uses: github/codeql-action/init@v1.0.23 From b7042348c8c45c039ca63f557d9d92580112b72a Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 22:57:48 +0300 Subject: [PATCH 31/59] build: correctly generate javadocs *after* delombok --- pom.xml | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/pom.xml b/pom.xml index 2ca7d254..e7c08bf9 100644 --- a/pom.xml +++ b/pom.xml @@ -133,7 +133,13 @@ + + + org.projectlombok + lombok-maven-plugin + 1.18.20.0 + org.apache.drill.tools drill-fmpp-maven-plugin @@ -334,6 +340,36 @@ + + org.projectlombok + lombok-maven-plugin + + + generate-delomboked-javadoc-sources + process-sources + + delombok + + + false + ${project.build.sourceDirectory} + ${project.build.directory}/javadoc-sources + + + + generate-delomboked-javadoc-sources-for-generated-sources + process-sources + + delombok + + + false + ${project.build.directory}/generated-sources + ${project.build.directory}/javadoc-sources + + + + org.apache.maven.plugins maven-javadoc-plugin @@ -343,6 +379,9 @@ jar + + ${project.build.directory}/javadoc-sources + From 1fdfad9a2861cf122832c0cd2f8132662ac8fb6c Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 23:44:44 +0300 Subject: [PATCH 32/59] fix(java-commons): don't use BlackHole for initialization of `CaffeineCacheFactory` --- .../javacommons/cache/CaffeineCache.java | 48 ++++++++++++------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/cache/CaffeineCache.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/cache/CaffeineCache.java index 61abeb66..15c7054b 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/cache/CaffeineCache.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/cache/CaffeineCache.java @@ -7,7 +7,6 @@ import lombok.experimental.UtilityClass; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import ru.progrm_jarvis.javacommons.util.BlackHole; /** * Utilities for creation of Caffeine-based @@ -19,16 +18,16 @@ public class CaffeineCache { /** * Flag indicating whether {@link Caffeine} is available */ - private static final boolean AVAILABLE; + private final @Nullable CacheFactory CACHE_FACTORY; static { - boolean available = true; - try { // check if Caffeine class is available - BlackHole.consume(Caffeine.class); + CacheFactory cacheFactory; + try { // check if Caffeine is available + cacheFactory = new CaffeineCacheFactory(Caffeine::newBuilder); } catch (final Throwable ignored) { - available = false; + cacheFactory = null; } - AVAILABLE = available; + CACHE_FACTORY = cacheFactory; } /** @@ -38,10 +37,10 @@ public class CaffeineCache { * * @throws IllegalStateException if Caffeine is not available */ - public static @NotNull CacheFactory createFactory() { - if (AVAILABLE) return CaffeineCacheFactory.INSTANCE; + public @NotNull CacheFactory createFactory() { + if (CACHE_FACTORY == null) throw new IllegalStateException("Caffeine Cache is not available"); - throw new IllegalStateException("Caffeine Cache is not available"); + return CACHE_FACTORY; } /** @@ -49,8 +48,8 @@ public class CaffeineCache { * * @return created Caffeine Cache factory or {@code null} if it is unavailable */ - public static @Nullable CacheFactory tryCreateFactory() { - return AVAILABLE ? CaffeineCacheFactory.INSTANCE : null; + public @Nullable CacheFactory tryCreateFactory() { + return CACHE_FACTORY; } /** @@ -58,12 +57,12 @@ public class CaffeineCache { */ @RequiredArgsConstructor(access = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) - private static final class CaffeineCacheFactory implements CacheFactory { + private final class CaffeineCacheFactory implements CacheFactory { /** - * Singleton instance of this {@link CacheFactory} implementation + * Factory used for creation of {@link Caffeine} builder */ - private static final @NotNull CacheFactory INSTANCE = new CaffeineCacheFactory(); + private @NotNull CaffeineBuilderFactory factory; /** * Wraps the provided {@link com.github.benmanes.caffeine.cache.Cache Caffeine Cache} into {@link Cache}. @@ -81,17 +80,30 @@ private static final class CaffeineCacheFactory implements CacheFactory { @Override public @NotNull Cache weakKeysCache() { - return wrap(Caffeine.newBuilder().weakKeys().build()); + return wrap(factory.newBuilder().weakKeys().build()); } @Override public @NotNull Cache weakValuesCache() { - return wrap(Caffeine.newBuilder().weakValues().build()); + return wrap(factory.newBuilder().weakValues().build()); } @Override public @NotNull Cache softValuesCache() { - return wrap(Caffeine.newBuilder().softValues().build()); + return wrap(factory.newBuilder().softValues().build()); + } + + /** + * Factory responsible for creation of {@link Caffeine} builder. + */ + public interface CaffeineBuilderFactory { + + /** + * Creates a {@link Caffeine} builder. + * + * @return Caffeine builder + */ + Caffeine newBuilder(); } } } From 6f4e9ff9cc1dd00dbc6fdb4ec3413640bfca47fc Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Wed, 17 Nov 2021 23:45:55 +0300 Subject: [PATCH 33/59] fix(java-commons): disable generation of getters in `Result` --- .../java/ru/progrm_jarvis/javacommons/object/Result.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java index 1a0d407f..2251003b 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java @@ -1,9 +1,6 @@ package ru.progrm_jarvis.javacommons.object; -import lombok.NoArgsConstructor; -import lombok.NonNull; -import lombok.SneakyThrows; -import lombok.Value; +import lombok.*; import lombok.experimental.UtilityClass; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -674,6 +671,7 @@ default E errorOrElseSneakyThrow( * @param type of error result */ @Value + @Getter(AccessLevel.NONE) class Success implements Result { /** @@ -872,6 +870,7 @@ public void handle( * @param type of error result */ @Value + @Getter(AccessLevel.NONE) class Error<@Any T, E> implements Result { /** From 373bcffffabe10af5651c6f6d1c9600a6b4a307d Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Thu, 18 Nov 2021 00:30:19 +0300 Subject: [PATCH 34/59] docs: add docs for well-supported APIs --- .../classloading/ClassDefiner.java | 3 + .../javacommons/collection/MapUtil.java | 112 ++++++++--- ...tractConcurrentSizedCollectionWrapper.java | 1 - .../javacommons/data/DataSerializers.java | 183 +++++++++++++++++- .../delegate/AsmDelegateFactory.java | 5 +- .../CachingGeneratingDelegateFactory.java | 2 +- .../javacommons/invoke/LookupFactory.java | 6 + .../javacommons/object/Result.java | 3 +- ...sions.java => LegacyStreamExtensions.java} | 12 +- ...t.java => LegacyStreamExtensionsTest.java} | 4 +- .../format/model/AsmTextModelFactory.java | 3 +- .../model/JavassistTextModelFactory.java | 3 +- .../format/model/SimpleTextModelFactory.java | 10 +- .../placeholder/SimplePlaceholders.java | 37 ++-- 14 files changed, 330 insertions(+), 54 deletions(-) rename java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/extension/{LegacyCollectorExtensions.java => LegacyStreamExtensions.java} (89%) rename java-commons/src/test/java/ru/progrm_jarvis/javacommons/util/stream/extension/{LegacyCollectorExtensionsTest.java => LegacyStreamExtensionsTest.java} (95%) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/classloading/ClassDefiner.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/classloading/ClassDefiner.java index 15be5e1e..2ae1d3a5 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/classloading/ClassDefiner.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/classloading/ClassDefiner.java @@ -9,6 +9,9 @@ import java.util.List; import java.util.Map; +/** + * Object used for runtime class definition. + */ public interface ClassDefiner { /**Uns diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/MapUtil.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/MapUtil.java index eed8c60e..f41c3643 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/MapUtil.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/MapUtil.java @@ -25,8 +25,10 @@ public class MapUtil { * @param keyValuePairs key-value pairs to put to the map ordered as key1, value1, key2, value2... */ @SuppressWarnings("unchecked") - private void fillMapNoChecks(@SuppressWarnings("rawtypes") final @NonNull Map map, - final @NonNull Object... keyValuePairs) { + private void fillMapNoChecks( + @SuppressWarnings("rawtypes") final @NonNull Map map, + final @NonNull Object... keyValuePairs + ) { @SuppressWarnings("BooleanVariableAlwaysNegated") var value = true; // will get reverted for the first value Object key = null; // requires to be initialized for some reason :) @@ -40,9 +42,9 @@ private void fillMapNoChecks(@SuppressWarnings("rawtypes") final @NonNull Map ma * @param map map to fill with the values * @param keyValuePairs pairs of keys and values in order key1, value1, key2, value2, key3, value3... * @param map type + * * @return the map passed filled with key-value pairs specified * @throws IllegalArgumentException if {@code keyValuePairs}'s length is odd - * * @see #fillMap(Map, Object, Object, Object...) */ public > M fillMap(final @NonNull M map, final @NonNull Object... keyValuePairs) { @@ -67,15 +69,17 @@ private void fillMapNoChecks(@SuppressWarnings("rawtypes") final @NonNull Map ma * @param type of keys * @param type of values * @param map type + * * @return the map passed filled with key-value pairs specified * @throws IllegalArgumentException if {@code keyValuePairs}'s length is odd - * * @see #fillMap(Map, Object...) */ - public > M fillMap(final @NonNull M map, final K firstValueKey, final V firstValue, - final @NonNull Object... keyValuePairs) { + public > M fillMap( + final @NonNull M map, final K firstValueKey, final V firstValue, + final @NonNull Object... keyValuePairs + ) { val length = keyValuePairs.length; - if(length % 2 != 0) throw new IllegalArgumentException( + if (length % 2 != 0) throw new IllegalArgumentException( "Key-Value pairs array should have an even number of elements" ); @@ -93,6 +97,7 @@ public > M fillMap(final @NonNull M map, final K first * @param type of keys * @param type of values * @param map type + * * @return the map passed filled with key-value pairs specified */ @SafeVarargs @@ -110,10 +115,13 @@ public > M fillMap(final @NonNull M map, final @NonNul * @param type of keys * @param type of values * @param map type + * * @return the map passed filled with key-value pairs specified */ - public > M fillMap(final @NonNull M map, - final @NonNull Iterator> entries) { + public > M fillMap( + final @NonNull M map, + final @NonNull Iterator> entries + ) { while (entries.hasNext()) { val entry = entries.next(); map.put(entry.getFirst(), entry.getSecond()); @@ -130,10 +138,13 @@ public > M fillMap(final @NonNull M map, * @param type of keys * @param type of values * @param map type + * * @return the map passed filled with key-value pairs specified */ - public > M fillMap(final @NonNull M map, - final @NonNull Iterable> entries) { + public > M fillMap( + final @NonNull M map, + final @NonNull Iterable> entries + ) { return fillMap(map, entries.iterator()); } @@ -145,10 +156,13 @@ public > M fillMap(final @NonNull M map, * @param type of keys * @param type of values * @param map type + * * @return the map passed filled with key-value pairs specified */ - public > M fillMap(final @NonNull M map, - final @NonNull Stream> entries) { + public > M fillMap( + final @NonNull M map, + final @NonNull Stream> entries + ) { entries.forEach(entry -> map.put(entry.getFirst(), entry.getSecond())); return map; @@ -162,23 +176,60 @@ public > M fillMap(final @NonNull M map, * @param type of keys * @param type of values * @param map type + * * @return the map passed filled with key-value pairs specified */ - public > M fillMapOrdered(final @NonNull M map, - final @NonNull Stream> entries) { + public > M fillMapOrdered( + final @NonNull M map, + final @NonNull Stream> entries + ) { entries.forEachOrdered(entry -> map.put(entry.getFirst(), entry.getSecond())); return map; } - public V getOrDefault(final @NonNull Map map, final K key, final Supplier defaultValueSupplier) { + /** + * Gets the value from the map otherwise returning the value created by using the provided supplier. + * Unlike {@link Map#computeIfAbsent(Object, Function)} this does not store the newly computed value in the map. + * + * @param map map from which to try to get the value + * @param key key of the searched value + * @param defaultValueSupplier supplier of the default value + * @param the type of map's keys + * @param the type of map's values + * + * @return the value associated with the key in the map or the one produced by the supplier otherwise + */ + public V getOrDefault( + final @NonNull Map map, final K key, + final @NonNull Supplier defaultValueSupplier + ) { // the value is got from map, non-null value is surely a present one, but null may have different meanings - val value = map.get(key); - return value == null ? map.containsKey(key) ? null : defaultValueSupplier.get() : value; + final V value; + return (value = map.get(key)) == null + ? map.containsKey(key) ? null : defaultValueSupplier.get() + : value; } - public R getOrDefault(final @NonNull Map map, final K key, final Function valueTransformer, - final R defaultValue) { + /** + * Gets the value from the map applying the provided function to it + * otherwise returning the value created by using the provided supplier. + * Unlike {@link Map#computeIfAbsent(Object, Function)} this does not store the newly computed value in the map. + * + * @param map map from which to try to get the value + * @param key key of the searched value + * @param valueTransformer function used to transform map value + * @param defaultValue default value + * @param the type of map's keys + * @param the type of map's values + * @param the type of the resulting value + * + * @return the value associated with the key in the map or the one produced by the supplier otherwise + */ + public R getOrDefault( + final @NonNull Map map, final K key, final Function valueTransformer, + final R defaultValue + ) { // the value is got from map, non-null value is surely a present one, but null may have different meanings val value = map.get(key); return value == null @@ -186,8 +237,25 @@ public R getOrDefault(final @NonNull Map map, final K key, final : valueTransformer.apply(value); } - public R getOrDefault(final @NonNull Map map, final K key, final Function valueTransformer, - final Supplier defaultValueSupplier) { + /** + * Gets the value from the map applying the provided function to it + * otherwise returning the value created by using the provided supplier. + * Unlike {@link Map#computeIfAbsent(Object, Function)} this does not store the newly computed value in the map. + * + * @param map map from which to try to get the value + * @param key key of the searched value + * @param valueTransformer function used to transform map value + * @param defaultValueSupplier supplier of the default value + * @param the type of map's keys + * @param the type of map's values + * @param the type of the resulting value + * + * @return the value associated with the key in the map or the one produced by the supplier otherwise + */ + public R getOrDefault( + final @NonNull Map map, final K key, final Function valueTransformer, + final Supplier defaultValueSupplier + ) { // the value is got from map, non-null value is surely a present one, but null may have different meanings val value = map.get(key); return value == null diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/concurrent/AbstractConcurrentSizedCollectionWrapper.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/concurrent/AbstractConcurrentSizedCollectionWrapper.java index c01a2d24..05451a0b 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/concurrent/AbstractConcurrentSizedCollectionWrapper.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/concurrent/AbstractConcurrentSizedCollectionWrapper.java @@ -1,6 +1,5 @@ package ru.progrm_jarvis.javacommons.collection.concurrent; - import org.jetbrains.annotations.NotNull; import ru.progrm_jarvis.javacommons.collection.SizedCollection; diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/data/DataSerializers.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/data/DataSerializers.java index fe9a7ae1..af4cbf24 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/data/DataSerializers.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/data/DataSerializers.java @@ -20,48 +20,108 @@ public class DataSerializers { /* ********************************************** Primitive types ********************************************** */ + /** + * Creates a {@link DataSerializer data serializer} for {@link Boolean}. + * + * @return data serializer for {@link Boolean} + */ public @NotNull DataSerializer<@NotNull Boolean> booleanDataSerializer() { return BooleanDataSerializer.INSTANCE; } + /** + * Creates a {@link DataSerializer data serializer} for {@link Byte}. + * + * @return data serializer for {@link Byte} + */ public @NotNull DataSerializer<@NotNull Byte> byteDataSerializer() { return ByteDataSerializer.INSTANCE; } + /** + * Creates a {@link DataSerializer data serializer} for {@link Short}. + * + * @return data serializer for {@link Short} + */ public @NotNull DataSerializer<@NotNull Short> shortDataSerializer() { return ShortDataSerializer.INSTANCE; } + /** + * Creates a {@link DataSerializer data serializer} for {@link Character}. + * + * @return data serializer for {@link Character} + */ public @NotNull DataSerializer<@NotNull Character> charDataSerializer() { return CharDataSerializer.INSTANCE; } + /** + * Creates a {@link DataSerializer data serializer} for {@link Integer}. + * + * @return data serializer for {@link Integer} + */ public @NotNull DataSerializer<@NotNull Integer> intDataSerializer() { return IntDataSerializer.INSTANCE; } + /** + * Creates a {@link DataSerializer data serializer} for {@link Long}. + * + * @return data serializer for {@link Long} + */ public @NotNull DataSerializer<@NotNull Long> longDataSerializer() { return LongDataSerializer.INSTANCE; } + /** + * Creates a {@link DataSerializer data serializer} for {@link Float}. + * + * @return data serializer for {@link Float} + */ public @NotNull DataSerializer<@NotNull Float> floatDataSerializer() { return FloatDataSerializer.INSTANCE; } + /** + * Creates a {@link DataSerializer data serializer} for {@link Double}. + * + * @return data serializer for {@link Double} + */ public @NotNull DataSerializer<@NotNull Double> doubleDataSerializer() { return DoubleDataSerializer.INSTANCE; } + /** + * Creates a {@link DataSerializer data serializer} for {@link String}. + * + * @return data serializer for {@link String} + */ public @NotNull DataSerializer<@NotNull String> stringDataSerializer() { return StringDataSerializer.INSTANCE; } + /** + * Creates a {@link DataSerializer data serializer} for {@link UUID}. + * + * @return data serializer for {@link UUID} + */ public @NotNull DataSerializer<@NotNull UUID> uuidDataSerializer() { return UuidDataSerializer.INSTANCE; } /* ************************************************ Collections ************************************************ */ + /** + * Creates a {@link DataSerializer data serializer} for the given {@link Collection collection} type. + * + * @param collectionFactory factory used for creation of collections + * @param elementSerializer serializer used for elements' serialization + * @param the type of the collection + * @param the type of the collection's elements + * + * @return data serializer for the given {@link Collection collection} type + */ public , T> @NotNull DataSerializer<@NotNull C> collectionDataSerializer( final DataSerializers.@NonNull SizeAwareFactory collectionFactory, final @NonNull DataSerializer elementSerializer @@ -69,23 +129,63 @@ public class DataSerializers { return new CollectionDataSerializer<>(collectionFactory, elementSerializer); } + /** + * Creates a {@link DataSerializer data serializer} for {@link Collection}. + * + * @param elementSerializer serializer used for elements' serialization + * @param the type of the collection's elements + * + * @return data serializer for {@link Collection} + * @apiNote there are no specific guarantees for the given collection + */ public @NotNull DataSerializer<@NotNull Collection> collectionDataSerializer( - final @NonNull DataSerializer elementSerializer) { + final @NonNull DataSerializer elementSerializer + ) { return collectionDataSerializer(ArrayList::new, elementSerializer); } + /** + * Creates a {@link DataSerializer data serializer} for {@link List}. + * + * @param elementSerializer serializer used for elements' serialization + * @param the type of the list's elements + * + * @return data serializer for {@link List} + * @apiNote there are no specific guarantees for the given list + */ public @NotNull DataSerializer<@NotNull List> listDataSerializer( final @NonNull DataSerializer elementSerializer ) { return collectionDataSerializer(ArrayList::new, elementSerializer); } + /** + * Creates a {@link DataSerializer data serializer} for {@link Set}. + * + * @param elementSerializer serializer used for elements' serialization + * @param the type of the set's elements + * + * @return data serializer for {@link Set} + * @apiNote there are no specific guarantees for the given set + */ public @NotNull DataSerializer<@NotNull Set> setDataSerializer( final @NonNull DataSerializer elementSerializer ) { return collectionDataSerializer(HashSet::new, elementSerializer); } + /** + * Creates a {@link DataSerializer data serializer} for the given {@link Map map} type. + * + * @param mapFactory factory used for creation of maps + * @param keySerializer serializer used for keys' serialization + * @param valueSerializer serializer used for values' serialization + * @param the type of the map + * @param the type of the maps' keys + * @param the type of the maps' values + * + * @return data serializer for the given {@link Map map} type + */ public , K, V> @NotNull DataSerializer<@NotNull M> mapDataSerializer( final DataSerializers.@NonNull SizeAwareFactory mapFactory, final @NonNull DataSerializer keySerializer, @@ -94,8 +194,35 @@ public class DataSerializers { return new MapDataSerializer<>(mapFactory, keySerializer, valueSerializer); } + /** + * Creates a {@link DataSerializer data serializer} for {@link Map}. + * + * @param keySerializer serializer used for keys' serialization + * @param valueSerializer serializer used for values' serialization + * @param the type of the maps' keys + * @param the type of the maps' values + * + * @return data serializer for {@link Collection} + * @apiNote there are no specific guarantees for the given map + */ + public @NotNull DataSerializer<@NotNull Map> mapDataSerializer( + final @NonNull DataSerializer keySerializer, + final @NonNull DataSerializer valueSerializer + ) { + return mapDataSerializer(HashMap::new, keySerializer, valueSerializer); + } + /* *************************************************** Enums *************************************************** */ + /** + * Creates a {@link DataSerializer data serializer} for the given {@link Enum enum} type + * which will implement stable serialization which will rely on enum names. + * + * @param enumType class object representing the enum type + * @param the type of the enum + * + * @return {@link DataSerializer data serializer} for the given {@link Enum enum} type + */ public > DataSerializer<@NotNull E> namedEnumDataSerializer(final @NonNull Class enumType) { final E[] enumValues; final int length; @@ -108,43 +235,87 @@ public class DataSerializers { return new NamedEnumDataSerializer<>(map); } + /** + * Creates a {@link DataSerializer data serializer} for the given {@link Enum enum} type + * which will implement unstable serialization which will rely on enum ordinal. + * + * @param enumType class object representing the enum type + * @param the type of the enum + * + * @return {@link DataSerializer data serializer} for the given {@link Enum enum} type + */ public > DataSerializer<@NotNull E> ordinalEnumDataSerializer(final @NonNull Class enumType) { final E[] enumConstants; final int enumConstantsLength; if ((enumConstantsLength = (enumConstants = enumType.getEnumConstants()).length) - < 1 << 8) return new ByteOrdinalEnumDataSerializer<>(enumConstants); + < 1 << Byte.SIZE) return new ByteOrdinalEnumDataSerializer<>(enumConstants); if (enumConstantsLength - < 1 << 16) return new ShortOrdinalEnumDataSerializer<>(enumConstants); + < 1 << Short.SIZE) return new ShortOrdinalEnumDataSerializer<>(enumConstants); return new IntOrdinalEnumDataSerializer<>(enumConstants); } /* ************************************************ Date & Time ************************************************ */ + /** + * Creates a {@link DataSerializer data serializer} for {@link LocalDateTime}. + * + * @param zoneOffset zone offset used for local time management + * + * @return data serializer for {@link LocalDateTime} + */ public @NotNull DataSerializer<@NotNull LocalDateTime> localDateTimeDataSerializer( final @NotNull ZoneOffset zoneOffset ) { return new LocalDateTimeDataSerializer(zoneOffset); } + /** + * Creates a {@link DataSerializer data serializer} for {@link LocalDate}. + * + * @return data serializer for {@link LocalDate} + */ public @NotNull DataSerializer<@NotNull LocalDate> localDateDataSerializer() { return LocalDateDataSerializer.INSTANCE; } + /** + * Creates a {@link DataSerializer data serializer} for {@link LocalTime}. + * + * @return data serializer for {@link LocalTime} + */ public @NotNull DataSerializer<@NotNull LocalTime> localTimeDataSerializer() { return LocalTimeDataSerializer.INSTANCE; } + /** + * Creates a {@link DataSerializer data serializer} for {@link Instant}. + * + * @return data serializer for {@link Instant} + */ public @NotNull DataSerializer<@NotNull Instant> instantDataSerializer() { return InstantDataSerializer.INSTANCE; } /* ******************************************* Functional interfaces ******************************************* */ + /** + * Factory which creates something based on the size parameter. + * + * @param type of created object + */ @FunctionalInterface public interface SizeAwareFactory { - @NotNull C create(int initialSize); + + /** + * Creates an object based on the size. + * + * @param size size used for object creation + * + * @return created object + */ + @NotNull C create(int size); } /* ********************************************** Implementations ********************************************** */ @@ -561,8 +732,8 @@ public E read(final @NotNull DataInputStream in) throws IOException { final E value; { final String name; - if ((value = enumsByNames.get(name = in.readUTF())) - == null) throw new IOException("Invalid enum constant name: " + name); + if ((value = enumsByNames.get(name = in.readUTF())) == null) + throw new IOException("Invalid enum constant name: " + name); } return value; diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/delegate/AsmDelegateFactory.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/delegate/AsmDelegateFactory.java index 8d2ddb0a..766ef029 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/delegate/AsmDelegateFactory.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/delegate/AsmDelegateFactory.java @@ -26,6 +26,9 @@ import static org.objectweb.asm.Opcodes.*; import static org.objectweb.asm.Type.*; +/** + * Implementation of {@link DelegateFactory delegate factory} which uses runtime class generation via ASM. + */ @UsesBytecodeModification(CommonBytecodeLibrary.ASM) public final class AsmDelegateFactory extends CachingGeneratingDelegateFactory { @@ -67,7 +70,7 @@ public final class AsmDelegateFactory extends CachingGeneratingDelegateFactory { */ VOID_SUPPLIER_METHOD_DESCRIPTOR = getMethodDescriptor(VOID_TYPE, SUPPLIER_TYPE); - private AsmDelegateFactory(final @NotNull Cache, DelegateWrapperFactory> factories) { + private AsmDelegateFactory(final @NotNull Cache<@NotNull Class, @NotNull DelegateWrapperFactory> factories) { super(factories); } diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/delegate/CachingGeneratingDelegateFactory.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/delegate/CachingGeneratingDelegateFactory.java index 53657d24..f6ab11ba 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/delegate/CachingGeneratingDelegateFactory.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/delegate/CachingGeneratingDelegateFactory.java @@ -18,7 +18,7 @@ public abstract class CachingGeneratingDelegateFactory implements DelegateFactor /** * Cache of {@link DelegateWrapperFactory delegate-wrapper factories} by wrapped types */ - protected final @NonNull Cache, DelegateWrapperFactory> factories; + protected final @NonNull Cache<@NotNull Class, @NotNull DelegateWrapperFactory> factories; /** * Creates a {@link DelegateWrapperFactory delegate-wrapper factory} fot the given type. diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/LookupFactory.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/LookupFactory.java index 5cb8eb62..e4bf509a 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/LookupFactory.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/invoke/LookupFactory.java @@ -12,6 +12,12 @@ @FunctionalInterface public interface LookupFactory extends Function, Lookup> { + /** + * Creates a lookup for the given class. + * + * @param clazz class for which to create a lookup + * @return lookup for the given class + */ @NotNull Lookup create(final @NonNull Class clazz); @Override diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java index 2251003b..e34c945c 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/object/Result.java @@ -212,6 +212,7 @@ public interface Result extends Supplier { * @param supplier provider of the result whose failure indicates the {@link #error(Object) error result} * @param throwableType class instance representing the type of the thrown exception * @param type of the {@link #success(Object) successful result} provided by the given supplier + * @param type of the thrown throwable * @return {@link #success(Object) successful result} if the supplier provides the value unexceptionally * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} * if {@link Class#isInstance(Object) it is of} the expected type @@ -241,8 +242,8 @@ public interface Result extends Supplier { * * @param supplier provider of the result whose failure indicates the {@link #error(Object) error result} * @param throwableTypeHint array used for throwable type discovery - * @param type of the thrown throwable * @param type of the {@link #success(Object) successful result} provided by the given supplier + * @param type of the thrown throwable * @return {@link #success(Object) successful result} if the supplier provides the value unexceptionally * or an {@link #error(Object) error result} containing the thrown {@link Throwable throwable} otherwise * if {@link Class#isInstance(Object) it is of} the expected type diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/extension/LegacyCollectorExtensions.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/extension/LegacyStreamExtensions.java similarity index 89% rename from java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/extension/LegacyCollectorExtensions.java rename to java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/extension/LegacyStreamExtensions.java index 95a3ef71..769ad7d5 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/extension/LegacyCollectorExtensions.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/stream/extension/LegacyStreamExtensions.java @@ -17,14 +17,18 @@ import static java.lang.invoke.MethodType.methodType; +/** + * Extensions to provide new {@link Stream} methods on older Java versions. + */ @UtilityClass -public class LegacyCollectorExtensions { +public class LegacyStreamExtensions { + /** * Method handle of * {@link Collectors}{@code .toList()} method * being {@code null} if this method is unavailable. */ - private static final @Nullable MethodHandle TO_LIST__METHOD_HANDLE; + private final @Nullable MethodHandle TO_LIST__METHOD_HANDLE; static { val lookup = MethodHandles.lookup(); @@ -50,7 +54,7 @@ public class LegacyCollectorExtensions { * @apiNote this method is available on {@link Stream} itself since Java 16 */ @SneakyThrows // call to `MethodHandle#invokeExact(...)` - public static @NotNull @Unmodifiable List toList(final @NotNull @Own Stream stream) { + public @NotNull @Unmodifiable List toList(final @NotNull @Own Stream stream) { if (TO_LIST__METHOD_HANDLE == null) { // all implementation rely on `toArray()` conversion final Object[] array; @@ -77,7 +81,7 @@ public class LegacyCollectorExtensions { // note: no nullability annotations are present on lists as cast of `null` is also safe @Contract("_ -> param1") @SuppressWarnings("unchecked") - private static List uncheckedListCast(final List raw) { + private List uncheckedListCast(final List raw) { return (List) raw; } } diff --git a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/util/stream/extension/LegacyCollectorExtensionsTest.java b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/util/stream/extension/LegacyStreamExtensionsTest.java similarity index 95% rename from java-commons/src/test/java/ru/progrm_jarvis/javacommons/util/stream/extension/LegacyCollectorExtensionsTest.java rename to java-commons/src/test/java/ru/progrm_jarvis/javacommons/util/stream/extension/LegacyStreamExtensionsTest.java index 25948b99..4027ed03 100644 --- a/java-commons/src/test/java/ru/progrm_jarvis/javacommons/util/stream/extension/LegacyCollectorExtensionsTest.java +++ b/java-commons/src/test/java/ru/progrm_jarvis/javacommons/util/stream/extension/LegacyStreamExtensionsTest.java @@ -17,8 +17,8 @@ import static org.hamcrest.Matchers.containsInAnyOrder; import static org.junit.jupiter.api.Assertions.assertEquals; -@ExtensionMethod(LegacyCollectorExtensions.class) -class LegacyCollectorExtensionsTest { +@ExtensionMethod(LegacyStreamExtensions.class) +class LegacyStreamExtensionsTest { static @NotNull Stream<@NotNull Arguments> provideLists() { //noinspection DynamicRegexReplaceableByCompiledPattern: called in test for diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AsmTextModelFactory.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AsmTextModelFactory.java index cc8c98c1..c23b0ff7 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AsmTextModelFactory.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AsmTextModelFactory.java @@ -32,7 +32,8 @@ import static ru.progrm_jarvis.javacommons.bytecode.asm.AsmUtil.*; /** - * Implementation of {@link TextModelFactory text model factory} which uses runtime class generation. + * Implementation of {@link TextModelFactory text model factory} + * * which uses runtime class generation via ASM. * * @param type of object according to which the created text models are formatted * @param type of configuration used by this text model factory diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/JavassistTextModelFactory.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/JavassistTextModelFactory.java index 72179303..c11f2ba9 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/JavassistTextModelFactory.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/JavassistTextModelFactory.java @@ -24,7 +24,8 @@ import java.lang.reflect.Modifier; /** - * Implementation of {@link TextModelFactory text model factory} which uses runtime class generation. + * Implementation of {@link TextModelFactory text model factory} + * which uses runtime class generation via Javasssist. */ @RequiredArgsConstructor(access = AccessLevel.PRIVATE) @UsesBytecodeModification(CommonBytecodeLibrary.JAVASSIST) diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java index 5567a51c..0e0453aa 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java @@ -48,11 +48,17 @@ public final class SimpleTextModelFactory implements TextModelFactory { */ @ToString @EqualsAndHashCode(callSuper = true) // simply, why not? :) (this also allows instance caching) - @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) - protected static class SimpleTextModelBuilder extends AbstractCachingTextModelFactoryBuilder { + @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) + private static final class SimpleTextModelBuilder extends AbstractCachingTextModelFactoryBuilder { + /** + * Elements appended to this builder. + */ @NonNull List> elements = new ArrayList<>(); + /** + * Last static text or {@code null} if there are no elements or the last element is dynamic + */ @NonFinal transient String lastStaticText; @Override diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/placeholder/SimplePlaceholders.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/placeholder/SimplePlaceholders.java index 134e8cc8..98eb7207 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/placeholder/SimplePlaceholders.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/placeholder/SimplePlaceholders.java @@ -21,8 +21,8 @@ */ @Data @Builder -@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) -public class SimplePlaceholders implements Placeholders { +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public final class SimplePlaceholders implements Placeholders { /** * Formatters used for handling placeholders which accept placeholder value and formatting target @@ -32,41 +32,54 @@ public class SimplePlaceholders implements Placeholders { /** * Prefix of placeholders */ - @Builder.Default char prefix = '{', + @Builder.Default char prefix = '{'; + /** * Suffix of placeholders */ - suffix = '}', + @Builder.Default char suffix = '}'; + /** * Delimiter separating placeholders' keys from values */ - delimiter = ':', + @Builder.Default char delimiter = ':'; + /** * Character used for escaping other characters (including itself) */ - escapeCharacter = '\\', + @Builder.Default char escapeCharacter = '\\'; + /* ********************************************* Special characters ********************************************* */ + /** * Tab character ({@code \t}) */ - tabCharacter = 't', + @Builder.Default char tabCharacter = 't'; + /** * Backspace character ({@code \b}) */ - backspaceCharacter = 'b', + @Builder.Default char backspaceCharacter = 'b'; + /** * New line character ({@code \n}) */ - newLineCharacter = 'n', + @Builder.Default char newLineCharacter = 'n'; + /** * Carriage return character ({@code \r}) */ - carriageReturnCharacter = 'r', + @Builder.Default char carriageReturnCharacter = 'r'; + /** * Form feed character ({@code \f}) */ - formFeedCharacter = 'f'; - @Builder.Default @NonNull String unknownPlaceholderReplacement = "???"; + @Builder.Default char formFeedCharacter = 'f'; + + /** + * Text used to replace occurrences of empty placeholders + */ + @Builder.Default @NonNull String unknownPlaceholderReplacement = ""; @Override public @NotNull String format(@NotNull String source, final T target) { From 2e4c24530259d57a17928e7678020a14e73a983d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Nov 2021 10:04:31 +0000 Subject: [PATCH 35/59] build(deps-dev): bump version.mockito from 4.0.0 to 4.1.0 Bumps `version.mockito` from 4.0.0 to 4.1.0. Updates `mockito-core` from 4.0.0 to 4.1.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.0.0...v4.1.0) Updates `mockito-junit-jupiter` from 4.0.0 to 4.1.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.0.0...v4.1.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: org.mockito:mockito-junit-jupiter dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2ca7d254..0433f545 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ UTF-8 8 - 4.0.0 + 4.1.0 PADLA for Java From bba1a9ca1ee3d680f85c2460f1f8552d9b861796 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Nov 2021 10:06:25 +0000 Subject: [PATCH 36/59] build(deps): bump github/codeql-action from 1.0.23 to 1.0.24 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 1.0.23 to 1.0.24. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v1.0.23...v1.0.24) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index ce99ccee..dd4017b0 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -29,12 +29,12 @@ jobs: cache: 'maven' - name: Initialize CodeQL - uses: github/codeql-action/init@v1.0.23 + uses: github/codeql-action/init@v1.0.24 with: languages: java - name: Autobuild - uses: github/codeql-action/autobuild@v1.0.23 + uses: github/codeql-action/autobuild@v1.0.24 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1.0.23 + uses: github/codeql-action/analyze@v1.0.24 From b7dd631be643c9ff73a2db27662079710beaba64 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 10:03:56 +0000 Subject: [PATCH 37/59] build(deps): bump junit-bom from 5.8.1 to 5.8.2 Bumps [junit-bom](https://github.com/junit-team/junit5) from 5.8.1 to 5.8.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.8.1...r5.8.2) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0433f545..067bd105 100644 --- a/pom.xml +++ b/pom.xml @@ -247,7 +247,7 @@ org.junit junit-bom - 5.8.1 + 5.8.2 pom import From 7fd64e213defce317a2e6eb7de544d21b6a1e1cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Nov 2021 10:05:31 +0000 Subject: [PATCH 38/59] build(deps): bump actions/setup-java from 2.3.1 to 2.4.0 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 2.3.1 to 2.4.0. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v2.3.1...v2.4.0) --- updated-dependencies: - dependency-name: actions/setup-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 2 +- .github/workflows/deploy-release.yaml | 2 +- .github/workflows/deploy-snapshot.yaml | 2 +- .github/workflows/test.yaml | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index dd4017b0..dd5796a8 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v2.4.0 - name: Set up Java 17 - uses: actions/setup-java@v2.3.1 + uses: actions/setup-java@v2.4.0 with: distribution: 'zulu' java-version: '17' diff --git a/.github/workflows/deploy-release.yaml b/.github/workflows/deploy-release.yaml index 2907a20e..703890df 100644 --- a/.github/workflows/deploy-release.yaml +++ b/.github/workflows/deploy-release.yaml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v2.4.0 - name: Set up Java 17 & Deployment credentials - uses: actions/setup-java@v2.3.1 + uses: actions/setup-java@v2.4.0 with: distribution: 'zulu' java-version: '17' diff --git a/.github/workflows/deploy-snapshot.yaml b/.github/workflows/deploy-snapshot.yaml index 2ea037ba..4fc6cd5f 100644 --- a/.github/workflows/deploy-snapshot.yaml +++ b/.github/workflows/deploy-snapshot.yaml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v2.4.0 - name: Set up Java 17 & Deployment credentials - uses: actions/setup-java@v2.3.1 + uses: actions/setup-java@v2.4.0 with: distribution: 'zulu' java-version: '17' diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 272b9454..51210a68 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -11,7 +11,7 @@ jobs: - uses: actions/checkout@v2.4.0 - name: Set up Java 17 - uses: actions/setup-java@v2.3.1 + uses: actions/setup-java@v2.4.0 with: distribution: 'zulu' java-version: '17' @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@v2.4.0 - name: Set up Java 17 - uses: actions/setup-java@v2.3.1 + uses: actions/setup-java@v2.4.0 with: distribution: 'zulu' java-version: '17' From 7c4f7bfca7141e82adf27140671fd7dc7f4029db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Dec 2021 10:04:47 +0000 Subject: [PATCH 39/59] build(deps): bump caffeine from 2.9.2 to 2.9.3 Bumps [caffeine](https://github.com/ben-manes/caffeine) from 2.9.2 to 2.9.3. - [Release notes](https://github.com/ben-manes/caffeine/releases) - [Commits](https://github.com/ben-manes/caffeine/compare/v2.9.2...v2.9.3) --- updated-dependencies: - dependency-name: com.github.ben-manes.caffeine:caffeine dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 067bd105..bdd90095 100644 --- a/pom.xml +++ b/pom.xml @@ -257,7 +257,7 @@ com.github.ben-manes.caffeine caffeine - 2.9.2 + 2.9.3 provided true From 7cc3d7c3ffdcde716fe36f2c8f37a7197bdd6d16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Dec 2021 10:06:52 +0000 Subject: [PATCH 40/59] build(deps): bump github/codeql-action from 1.0.24 to 1.0.25 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 1.0.24 to 1.0.25. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v1.0.24...v1.0.25) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index dd5796a8..7a2ace90 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -29,12 +29,12 @@ jobs: cache: 'maven' - name: Initialize CodeQL - uses: github/codeql-action/init@v1.0.24 + uses: github/codeql-action/init@v1.0.25 with: languages: java - name: Autobuild - uses: github/codeql-action/autobuild@v1.0.24 + uses: github/codeql-action/autobuild@v1.0.25 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1.0.24 + uses: github/codeql-action/analyze@v1.0.25 From dcab5419f818c8fec4a1e238f24965509c9c0409 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Sat, 11 Dec 2021 21:57:26 +0300 Subject: [PATCH 41/59] chore(java-commons): simplify radix checks in `NumberUtil` --- .../javacommons/primitive/NumberUtil.java | 70 ++++++++++--------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/primitive/NumberUtil.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/primitive/NumberUtil.java index 7270fb32..d86f943d 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/primitive/NumberUtil.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/primitive/NumberUtil.java @@ -19,7 +19,7 @@ public class NumberUtil { /** * Default radix of a number. */ - public static final int DEFAULT_RADIX = 10; + public final int DEFAULT_RADIX = 10; /** *

Parses an {@code int} number.

@@ -28,16 +28,13 @@ public class NumberUtil { * * @param possibleInteger string which is expected to contain an {@code int} number but may not * @param radix radix of the possible number - * @return optional containing the parsed number or an empty one if it could not be parsed * + * @return optional containing the parsed number or an empty one if it could not be parsed * @throws IllegalArgumentException if the radix - * is out of bound [{@value Character#MIN_RADIX}; {@value Character#MAX_RADIX}]. + * is out of bound [{@link Character#MIN_RADIX}; {@link Character#MAX_RADIX}]. */ public @NotNull OptionalInt parseInt(final @NonNull CharSequence possibleInteger, final int radix) { - // check radix bounds - if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) throw new IllegalArgumentException( - "Radix " + radix + " is out of bounds [" + Character.MIN_RADIX + "; " + Character.MAX_RADIX + "]" - ); + checkRadix(radix); // check string length final int length; @@ -107,10 +104,10 @@ public class NumberUtil { * but it returns {@link OptionalInt} to handle invalid input instead of throwing {@link NumberFormatException}. * * @param possibleInteger string which is expected to contain an {@code int} number but may not - * @return optional containing the parsed number or an empty one if it could not be parsed * + * @return optional containing the parsed number or an empty one if it could not be parsed * @throws IllegalArgumentException if the radix - * is out of bound [{@value Character#MIN_RADIX}; {@value Character#MAX_RADIX}]. + * is out of bound [{@link Character#MIN_RADIX}; {@link Character#MAX_RADIX}]. */ public @NotNull OptionalInt parseInt(final @NonNull CharSequence possibleInteger) { return parseInt(possibleInteger, 10); @@ -123,18 +120,15 @@ public class NumberUtil { * * @param possibleInteger string which is expected to contain an {@code int} number but may not * @param radix radix of the possible number - * @return result containing the parsed number or an error one if it could not be parsed * + * @return result containing the parsed number or an error one if it could not be parsed * @throws IllegalArgumentException if the radix - * is out of bound [{@value Character#MIN_RADIX}; {@value Character#MAX_RADIX}]. + * is out of bound [{@link Character#MIN_RADIX}; {@link Character#MAX_RADIX}]. */ public @NotNull Result<@NotNull Integer, @NotNull IntegerParseError> parseIntResult( final @NonNull CharSequence possibleInteger, final int radix ) { - // check radix bounds - if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) throw new IllegalArgumentException( - "Radix " + radix + " is out of bounds [" + Character.MIN_RADIX + "; " + Character.MAX_RADIX + "]" - ); + checkRadix(radix); final int length; @@ -204,13 +198,14 @@ public class NumberUtil { * but it returns {@link Result} to handle invalid input instead of throwing {@link NumberFormatException}. * * @param possibleInteger string which is expected to contain an {@code int} number but may not - * @return result containing the parsed number or an error one if it could not be parsed * + * @return result containing the parsed number or an error one if it could not be parsed * @throws IllegalArgumentException if the radix - * is out of bound [{@value Character#MIN_RADIX}; {@value Character#MAX_RADIX}]. + * is out of bound [{@link Character#MIN_RADIX}; {@link Character#MAX_RADIX}]. */ public @NotNull Result<@NotNull Integer, @NotNull IntegerParseError> parseIntResult( - final @NonNull CharSequence possibleInteger) { + final @NonNull CharSequence possibleInteger + ) { return parseIntResult(possibleInteger, DEFAULT_RADIX); } @@ -221,16 +216,13 @@ public class NumberUtil { * * @param possibleLong string which is expected to contain a {@code long} number but may not * @param radix radix of the possible number - * @return optional containing the parsed number or an empty one if it could not be parsed * + * @return optional containing the parsed number or an empty one if it could not be parsed * @throws IllegalArgumentException if the radix - * is out of bound [{@value Character#MIN_RADIX}; {@value Character#MAX_RADIX}]. + * is out of bound [{@link Character#MIN_RADIX}; {@link Character#MAX_RADIX}]. */ public @NotNull OptionalLong parseLong(final @NonNull CharSequence possibleLong, final int radix) { - // check radix bounds - if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) throw new IllegalArgumentException( - "Radix " + radix + " is out of bounds [" + Character.MIN_RADIX + "; " + Character.MAX_RADIX + "]" - ); + checkRadix(radix); // check string length final int length; @@ -300,10 +292,10 @@ public class NumberUtil { * but it returns {@link OptionalLong} to handle invalid input instead of throwing {@link NumberFormatException}. * * @param possibleLong string which is expected to contain a {@code long} number but may not - * @return optional containing the parsed number or an empty one if it could not be parsed * + * @return optional containing the parsed number or an empty one if it could not be parsed * @throws IllegalArgumentException if the radix - * is out of bound [{@value Character#MIN_RADIX}; {@value Character#MAX_RADIX}]. + * is out of bound [{@link Character#MIN_RADIX}; {@link Character#MAX_RADIX}]. */ public @NotNull OptionalLong parseLong(final @NonNull CharSequence possibleLong) { return parseLong(possibleLong, DEFAULT_RADIX); @@ -316,18 +308,15 @@ public class NumberUtil { * * @param possibleLong string which is expected to contain a {@code long} number but may not * @param radix radix of the possible number - * @return result containing the parsed number or an error one if it could not be parsed * + * @return result containing the parsed number or an error one if it could not be parsed * @throws IllegalArgumentException if the radix - * is out of bound [{@value Character#MIN_RADIX}; {@value Character#MAX_RADIX}]. + * is out of bound [{@link Character#MIN_RADIX}; {@link Character#MAX_RADIX}]. */ public @NotNull Result<@NotNull Long, @NotNull IntegerParseError> parseLongResult( final @NonNull CharSequence possibleLong, final int radix ) { - // check radix bounds - if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) throw new IllegalArgumentException( - "Radix " + radix + " is out of bounds [" + Character.MIN_RADIX + "; " + Character.MAX_RADIX + "]" - ); + checkRadix(radix); // check string length final int length; @@ -397,14 +386,27 @@ public class NumberUtil { * but it returns {@link Result} to handle invalid input instead of throwing {@link NumberFormatException}. * * @param possibleLong string which is expected to contain a {@code long} number but may not - * @return result containing the parsed number or an error one if it could not be parsed * + * @return result containing the parsed number or an error one if it could not be parsed * @throws IllegalArgumentException if the radix - * is out of bound [{@value Character#MIN_RADIX}; {@value Character#MAX_RADIX}]. + * is out of bound [{@link Character#MIN_RADIX}; {@link Character#MAX_RADIX}]. */ public @NotNull Result<@NotNull Long, @NotNull IntegerParseError> parseLongResult( final @NonNull CharSequence possibleLong ) { return parseLongResult(possibleLong, DEFAULT_RADIX); } + + /** + * Checks that the radix is between {@link Character#MIN_RADIX} and {@link Character#MAX_RADIX}. + * + * @param radix checked radix + * + * @throws IllegalArgumentException if {@code radix} is not between the bounds + */ + private void checkRadix(final int radix) { + if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) throw new IllegalArgumentException( + "Radix " + radix + " is out of bounds [" + Character.MIN_RADIX + "; " + Character.MAX_RADIX + "]" + ); + } } From 5a174dc8e08780c0e07e7177b82a6e9badfd291e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Dec 2021 10:08:53 +0000 Subject: [PATCH 42/59] build(deps): bump github/codeql-action from 1.0.25 to 1.0.26 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 1.0.25 to 1.0.26. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v1.0.25...v1.0.26) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index 7a2ace90..569a4130 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -29,12 +29,12 @@ jobs: cache: 'maven' - name: Initialize CodeQL - uses: github/codeql-action/init@v1.0.25 + uses: github/codeql-action/init@v1.0.26 with: languages: java - name: Autobuild - uses: github/codeql-action/autobuild@v1.0.25 + uses: github/codeql-action/autobuild@v1.0.26 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1.0.25 + uses: github/codeql-action/analyze@v1.0.26 From 02410075601d4295a518299de5282716c1ce7da9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Dec 2021 10:05:14 +0000 Subject: [PATCH 43/59] build(deps-dev): bump version.mockito from 4.1.0 to 4.2.0 Bumps `version.mockito` from 4.1.0 to 4.2.0. Updates `mockito-core` from 4.1.0 to 4.2.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.1.0...v4.2.0) Updates `mockito-junit-jupiter` from 4.1.0 to 4.2.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.1.0...v4.2.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: org.mockito:mockito-junit-jupiter dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bdd90095..0c8b0ee3 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ UTF-8 8 - 4.1.0 + 4.2.0 PADLA for Java From 9dd447261df77283d8dfb06c50f3d1aa1c75150f Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Sat, 18 Dec 2021 18:28:15 +0300 Subject: [PATCH 44/59] fix(java-commons): make `CaffeineCacheFactory` a `static` `class` --- .../java/ru/progrm_jarvis/javacommons/cache/CaffeineCache.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/cache/CaffeineCache.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/cache/CaffeineCache.java index 15c7054b..35469a38 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/cache/CaffeineCache.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/cache/CaffeineCache.java @@ -57,7 +57,7 @@ public class CaffeineCache { */ @RequiredArgsConstructor(access = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) - private final class CaffeineCacheFactory implements CacheFactory { + private static final class CaffeineCacheFactory implements CacheFactory { /** * Factory used for creation of {@link Caffeine} builder From 81558404f842e0da4e0297fd8bac5a7ed32e470a Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Sat, 18 Dec 2021 18:32:00 +0300 Subject: [PATCH 45/59] refactor(java-commons): don't make `TypeHints#resolve()` consume var-arg array Whenever it was called via var-arg form it became useless (either the caller had enough knowledge of the type or never enough) This resolves #298 --- .../main/java/ru/progrm_jarvis/javacommons/util/TypeHints.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/TypeHints.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/TypeHints.java index 85447bce..5455866f 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/TypeHints.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/util/TypeHints.java @@ -20,8 +20,7 @@ public class TypeHints { * @param generic type whose class object should be resolved * @return class object for the given array */ - @SuppressWarnings("unchecked") - public @NotNull Class resolve(final @Nullable T... typeHint) { + public @NotNull Class resolve(final @Nullable T @NotNull [] typeHint) { return UncheckedCasts.uncheckedClassCast(typeHint.getClass().getComponentType()); } From e4661df6792f55125f0d169774182d19f12235db Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Sat, 18 Dec 2021 18:35:18 +0300 Subject: [PATCH 46/59] chore(java-commons): remove redundant `Predicate` import from `ConcurrentSetFromMapWrapper` --- .../collection/concurrent/ConcurrentSetFromMapWrapper.java | 1 - 1 file changed, 1 deletion(-) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/concurrent/ConcurrentSetFromMapWrapper.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/concurrent/ConcurrentSetFromMapWrapper.java index 0177903e..b90b6130 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/concurrent/ConcurrentSetFromMapWrapper.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/collection/concurrent/ConcurrentSetFromMapWrapper.java @@ -11,7 +11,6 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.Predicate; @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) public class ConcurrentSetFromMapWrapper> From fcbb06795c07595e01b7ef60134db51cc29a1abd Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Sat, 18 Dec 2021 18:36:01 +0300 Subject: [PATCH 47/59] fix: update `SimplePlaceholdersTest` to the new default --- .../placeholder/SimplePlaceholdersTest.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/placeholder/SimplePlaceholdersTest.java b/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/placeholder/SimplePlaceholdersTest.java index f57df880..66c386ce 100644 --- a/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/placeholder/SimplePlaceholdersTest.java +++ b/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/placeholder/SimplePlaceholdersTest.java @@ -47,10 +47,10 @@ protected static Stream provideWithoutRegisteredPlaceholders() { arguments(target, "{:} hello", "{:} hello"), arguments(target, "hello {:}", "hello {:}"), arguments(target, "{:} hello {:}", "{:} hello {:}"), - arguments(target, "{rand} hello {:}", "??? hello {:}"), - arguments(target, "{rand} hello {rand}", "??? hello ???"), - arguments(target, "{rand} hello {:}", "??? hello {:}"), - arguments(target, "{unknown:} hello {:}", "??? hello {:}") + arguments(target, "{rand} hello {:}", " hello {:}"), + arguments(target, "{rand} hello {rand}", " hello "), + arguments(target, "{rand} hello {:}", " hello {:}"), + arguments(target, "{unknown:} hello {:}", " hello {:}") )); } @@ -102,11 +102,11 @@ protected static Stream provideWithoutRegisteredPlaceholdersAndEscapi arguments(target, "hello \\{:}\\", "hello {:}\\"), arguments(target, "\\{\\:\\}\\ hello \\{\\:\\}", "{:} hello {:}"), arguments(target, "\\{\\:\\}\\ hello \\{\\:\\}\\", "{:} hello {:}\\"), - arguments(target, "{\\ran\\d} hello {:}", "??? hello {:}"), - arguments(target, "{rand\\} \\hello {rand}", "???"), - arguments(target, "{rand\\} hello \\{:}", "???"), - arguments(target, "{unknown:\\} hi\\\\ {:}", "???"), - arguments(target, "{unknown:\\\\} hello {:}"), + arguments(target, "{rand\\} \\hello {rand}", ""), + arguments(target, "{rand\\} hello \\{:}", ""), + arguments(target, "{unknown:\\} hi\\\\ {:}", ""), + arguments(target, "{unknown:\\\\} provideWithEscapedChars() { @BeforeEach void setUp() { placeholders = SimplePlaceholders.builder().build(); - placeholders.add("*", ((value, target) -> "#")); + placeholders.add("*", (value, target) -> "#"); placeholders.add("test", (value, target) -> { switch (value) { case "name": return target.name; From a80092e86c51f494c369d20e6c7c8e3114d2ce62 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Sat, 18 Dec 2021 18:36:01 +0300 Subject: [PATCH 48/59] fix(ultimate-messenger): update `SimplePlaceholdersTest` to the new default --- .../placeholder/SimplePlaceholdersTest.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/placeholder/SimplePlaceholdersTest.java b/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/placeholder/SimplePlaceholdersTest.java index f57df880..66c386ce 100644 --- a/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/placeholder/SimplePlaceholdersTest.java +++ b/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/placeholder/SimplePlaceholdersTest.java @@ -47,10 +47,10 @@ protected static Stream provideWithoutRegisteredPlaceholders() { arguments(target, "{:} hello", "{:} hello"), arguments(target, "hello {:}", "hello {:}"), arguments(target, "{:} hello {:}", "{:} hello {:}"), - arguments(target, "{rand} hello {:}", "??? hello {:}"), - arguments(target, "{rand} hello {rand}", "??? hello ???"), - arguments(target, "{rand} hello {:}", "??? hello {:}"), - arguments(target, "{unknown:} hello {:}", "??? hello {:}") + arguments(target, "{rand} hello {:}", " hello {:}"), + arguments(target, "{rand} hello {rand}", " hello "), + arguments(target, "{rand} hello {:}", " hello {:}"), + arguments(target, "{unknown:} hello {:}", " hello {:}") )); } @@ -102,11 +102,11 @@ protected static Stream provideWithoutRegisteredPlaceholdersAndEscapi arguments(target, "hello \\{:}\\", "hello {:}\\"), arguments(target, "\\{\\:\\}\\ hello \\{\\:\\}", "{:} hello {:}"), arguments(target, "\\{\\:\\}\\ hello \\{\\:\\}\\", "{:} hello {:}\\"), - arguments(target, "{\\ran\\d} hello {:}", "??? hello {:}"), - arguments(target, "{rand\\} \\hello {rand}", "???"), - arguments(target, "{rand\\} hello \\{:}", "???"), - arguments(target, "{unknown:\\} hi\\\\ {:}", "???"), - arguments(target, "{unknown:\\\\} hello {:}"), + arguments(target, "{rand\\} \\hello {rand}", ""), + arguments(target, "{rand\\} hello \\{:}", ""), + arguments(target, "{unknown:\\} hi\\\\ {:}", ""), + arguments(target, "{unknown:\\\\} provideWithEscapedChars() { @BeforeEach void setUp() { placeholders = SimplePlaceholders.builder().build(); - placeholders.add("*", ((value, target) -> "#")); + placeholders.add("*", (value, target) -> "#"); placeholders.add("test", (value, target) -> { switch (value) { case "name": return target.name; From 168430d246370bc354762376550741cf0158e093 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Sat, 18 Dec 2021 18:49:09 +0300 Subject: [PATCH 49/59] docs(java-commons): add missing javadocs to `AbstractManagedPendingService`'s `protected` methods --- .../service/AbstractManagedPendingService.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/service/AbstractManagedPendingService.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/service/AbstractManagedPendingService.java index a1012421..307f498f 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/service/AbstractManagedPendingService.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/service/AbstractManagedPendingService.java @@ -83,8 +83,19 @@ protected AbstractManagedPendingService(final @NonNull Lock lifecycleLock, } } + /** + * Creates a service for the provided owner. + * + * @param owner owner of the created service + * @return creates service + */ protected abstract S newService(@NonNull O owner); + /** + * Marks the provided owner as ready. + * + * @param owner owner which should now be considered ready + */ @SuppressWarnings("resource") // close() is already the cause of this method being called protected void markAsReady(final @NonNull O owner) { final Lock lock; @@ -226,6 +237,12 @@ protected SafeOwnedService(final @NotNull O owner, final S service) { closed = new AtomicBoolean(); } + /** + * Triggers the failure due to this service being closed. + * + * @throws IllegalStateException always + */ + @SuppressWarnings("MethodMayBeStatic") // overriding classes may implement instance-specific behaviour protected void failOnClosed() { throw new IllegalStateException("This managed service has already been closed"); } From 6e6a3f4b05f8665cd7e810d59b92355c2cfd3093 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Mon, 20 Dec 2021 19:07:40 +0300 Subject: [PATCH 50/59] chore(ultimate-messenger): place nullability annotations correctly in `TextModel` and `NestingTextModel` --- .../ultimatemessenger/format/model/NestingTextModel.java | 2 +- .../ultimatemessenger/format/model/TextModel.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/NestingTextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/NestingTextModel.java index ea90f2ef..5f89e8c5 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/NestingTextModel.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/NestingTextModel.java @@ -13,7 +13,7 @@ public interface NestingTextModel extends TextModel, List> { @Override - @NotNull default String getText(@NotNull T target) { + default @NotNull String getText(@NotNull T target) { return stream() .map(element -> element.getText(target)) .collect(Collectors.joining()); diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java index 17a49716..32c2ac36 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java @@ -44,7 +44,7 @@ default boolean isDynamic() { * * @return minimal possible length of the value returned by {@link #getText(Object)} being empty if it is undefined */ - @NotNull default OptionalInt getMinLength() { + default @NotNull OptionalInt getMinLength() { return OptionalInt.empty(); } @@ -53,7 +53,7 @@ default boolean isDynamic() { * * @return maximal possible length of the value returned by {@link #getText(Object)} being empty if it is undefined */ - @NotNull default OptionalInt getMaxLength() { + default @NotNull OptionalInt getMaxLength() { return OptionalInt.empty(); } @@ -64,7 +64,7 @@ default boolean isDynamic() { * @return singleton of an empty static text model */ @SuppressWarnings("unchecked") - @NotNull static TextModel empty() { + static @NotNull TextModel empty() { return (TextModel) EmptyTextModel.INSTANCE; } From 8ec6e5963fbd7e218cc6304179740fb42ef3d080 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Mon, 20 Dec 2021 19:23:09 +0300 Subject: [PATCH 51/59] feat: deprecate `StaticTextModel` in favor of `TextModel#of(String)` --- ...ractGeneratingTextModelFactoryBuilder.java | 2 +- .../format/model/SimpleTextModelFactory.java | 4 +- .../format/model/StaticTextModel.java | 103 +++--------------- .../format/model/TextModel.java | 78 ++++++++++++- ...cTextModelTest.java => TextModelTest.java} | 16 +-- 5 files changed, 102 insertions(+), 101 deletions(-) rename ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/model/{StaticTextModelTest.java => TextModelTest.java} (81%) diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AbstractGeneratingTextModelFactoryBuilder.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AbstractGeneratingTextModelFactoryBuilder.java index a3b7d046..b759d435 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AbstractGeneratingTextModelFactoryBuilder.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AbstractGeneratingTextModelFactoryBuilder.java @@ -186,7 +186,7 @@ protected void endLastNodeModification() { val tail = lastNode; // this should never happen actually, but it might be an error marker for broken implementations assert tail != null; - return StaticTextModel.of(tail.asStatic().getText()); + return TextModel.of(tail.asStatic().getText()); } if (staticLength == 0 && dynamicNodeCount == 1) { // only 1 dynamic element without static ones val tail = lastNode; diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java index 0e0453aa..1c041fe2 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java @@ -64,8 +64,8 @@ private static final class SimpleTextModelBuilder extends AbstractCachingText @Override public @NotNull TextModelFactory.TextModelBuilder append(final @NonNull String staticText) { if (!staticText.isEmpty()) { - if (lastStaticText == null) elements.add(StaticTextModel.of(lastStaticText = staticText)); - else elements.set(elements.size() - 1, StaticTextModel.of(lastStaticText += staticText)); // ... + if (lastStaticText == null) elements.add(TextModel.of(lastStaticText = staticText)); + else elements.set(elements.size() - 1, TextModel.of(lastStaticText += staticText)); // ... // ... join nearby static text blocks markAsChanged(); diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/StaticTextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/StaticTextModel.java index be16db20..05ba12c2 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/StaticTextModel.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/StaticTextModel.java @@ -1,102 +1,29 @@ package ru.progrm_jarvis.ultimatemessenger.format.model; -import lombok.AccessLevel; import lombok.NonNull; -import lombok.Value; -import lombok.experimental.FieldDefaults; -import lombok.val; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.OptionalInt; +import lombok.experimental.UtilityClass; /** - * Text model representing a block of static text. + * Legacy factory of static {@link TextModel text models}. * - * @param type of object according to which the text model is formatted (actually, not used) + * @deprecated use {@link TextModel#of(String)} instead, + * this one will most probably be removed before release 1.0.0 */ -@Value -@FieldDefaults(level = AccessLevel.PRIVATE) -public class StaticTextModel implements TextModel { +@Deprecated +@UtilityClass +public class StaticTextModel { /** - * Text of this text model - */ - @NonNull String text; - /** - * Length of ths text model's {@link #text text} wrapped in {@link OptionalInt} - */ - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @NonNull OptionalInt length; - /** - * {@link Object#hashCode() Hash-code} of this static text model - * (effectively {@link String#hashCode()} of {@link #text}) - */ - int hashCode; - - /** - * Instantiates a new static text model of the given text. - * - * @param text text of this text model + * Creates a text model of the given static text. * - * @implNote this is not generated via Lombok because there is field dependency - * ({@link #length} and {@link #hashCode}are based on {@link #text}) - */ - public StaticTextModel(final @NotNull String text) { - this.text = text; - length = OptionalInt.of(text.length()); - hashCode = text.hashCode(); - } - - @Override - @Contract(pure = true) - public boolean isDynamic() { - return false; - } - - @Override - @Contract(pure = true) - public @NotNull OptionalInt getMinLength() { - return length; - } - - @Override - @Contract(pure = true) - public @NotNull OptionalInt getMaxLength() { - return length; - } - - @Override - @Contract(pure = true) - public @NotNull String getText(final @Nullable T target) { - return text; - } - - @Override - @Contract(pure = true) - public boolean equals(final @Nullable Object object) { - if (object == this) return true; - if (object instanceof TextModel) { - val textModel = (TextModel) object; - return !textModel.isDynamic() && textModel.hashCode() == hashCode && textModel.getText(null).equals(text); - } - return false; - } - - @Override - @Contract(pure = true) - public int hashCode() { - return hashCode; - } - - /** - * Gets a static text model of the given text. + * @param text static text of the text model + * @param type of object according to which the text model is formatted (effectively unused) + * @return text model of the given static text * - * @param text text of the static text model - * @param type of object according to which the text model is formatted (actually, not used) - * @return text model of the given text + * @deprecated use {@link TextModel#of(String)} instead */ - public static TextModel of(final @NonNull String text) { - return text.isEmpty() ? TextModel.empty() : new StaticTextModel<>(text); + @Deprecated + public TextModel of(final @NonNull String text) { + return TextModel.of(text); } } diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java index 32c2ac36..a3b4144d 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java @@ -1,7 +1,7 @@ package ru.progrm_jarvis.ultimatemessenger.format.model; -import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; +import lombok.*; +import lombok.experimental.FieldDefaults; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -68,6 +68,17 @@ default boolean isDynamic() { return (TextModel) EmptyTextModel.INSTANCE; } + /** + * Creates a text model of the given static text. + * + * @param text static text of the text model + * @param type of object according to which the text model is formatted (effectively unused) + * @return text model of the given static text + */ + static @NotNull TextModel of(final @NonNull String text) { + return new StaticTextModel<>(text, OptionalInt.of(text.length())); + } + /** * Empty static text model. */ @@ -140,4 +151,67 @@ public String toString() { return "TextModel{\"\"}"; } } + + /** + * Text model representing a block of static text. + * + * @param type of object according to which the text model is formatted (actually, not used) + */ + @Value + @FieldDefaults(level = AccessLevel.PRIVATE) + @RequiredArgsConstructor(access = AccessLevel.PRIVATE) + class StaticTextModel implements TextModel { + + /** + * Text of this text model + */ + @NonNull String text; + /** + * Length of ths text model's {@link #text text} wrapped in {@link OptionalInt} + */ + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @NonNull OptionalInt length; + + @Override + @Contract(pure = true) + public boolean isDynamic() { + return false; + } + + @Override + @Contract(pure = true) + public @NotNull OptionalInt getMinLength() { + return length; + } + + @Override + @Contract(pure = true) + public @NotNull OptionalInt getMaxLength() { + return length; + } + + @Override + @Contract(pure = true) + public @NotNull String getText(final @Nullable T target) { + return text; + } + + @Override + @Contract(pure = true) + public boolean equals(final @Nullable Object object) { + if (object == this) return true; + if (object instanceof TextModel) { + final TextModel textModel; + return !(textModel = (TextModel) object).isDynamic() // cheapest check + && textModel.hashCode() == hashCode() // `Object#equals(Object)` contract + && textModel.getText(null).equals(text); + } + return false; + } + + @Override + @Contract(pure = true) + public int hashCode() { + return text.hashCode(); + } + } } diff --git a/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/model/StaticTextModelTest.java b/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModelTest.java similarity index 81% rename from ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/model/StaticTextModelTest.java rename to ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModelTest.java index 84eddec8..fefe9ce1 100644 --- a/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/model/StaticTextModelTest.java +++ b/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModelTest.java @@ -17,20 +17,20 @@ import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.params.provider.Arguments.arguments; -class StaticTextModelTest { +class TextModelTest { static Stream provideTestSubjects() { return Stream.of( - arguments(StaticTextModel.of("foo"), "foo"), - arguments(StaticTextModel.of("bar"), "bar"), - arguments(StaticTextModel.of("baz"), "baz"), - arguments(StaticTextModel.of("mr. user"), "mr. user"), - arguments(StaticTextModel.of("Hello world!"), "Hello world!"), + arguments(TextModel.of("foo"), "foo"), + arguments(TextModel.of("bar"), "bar"), + arguments(TextModel.of("baz"), "baz"), + arguments(TextModel.of("mr. user"), "mr. user"), + arguments(TextModel.of("Hello world!"), "Hello world!"), arguments( - StaticTextModel.of("Japris Pogrammer seems to be a coder"), + TextModel.of("Japris Pogrammer seems to be a coder"), "Japris Pogrammer seems to be a coder" ), - arguments(StaticTextModel.of(""), "") // empty text is also text + arguments(TextModel.of(""), "") // empty text is also text ); } From 84c7294157ac134fe004a1cb523a6529c00307e9 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Mon, 20 Dec 2021 19:53:03 +0300 Subject: [PATCH 52/59] feat(java-commons): add `NumberUtil#saturatingSum(..)` --- .../javacommons/primitive/NumberUtil.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/primitive/NumberUtil.java b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/primitive/NumberUtil.java index d86f943d..fb4b34ff 100644 --- a/java-commons/src/main/java/ru/progrm_jarvis/javacommons/primitive/NumberUtil.java +++ b/java-commons/src/main/java/ru/progrm_jarvis/javacommons/primitive/NumberUtil.java @@ -16,6 +16,16 @@ @UtilityClass public class NumberUtil { + /** + * Number of bits in an {@code int} except for the sign bit. + */ + public final int INT_NON_SIGN_BITS = Integer.SIZE - 1; + + /** + * Number of bits in a {@code long} except for the sign bit. + */ + public final int LONG_NON_SIGN_BITS = Long.SIZE - 1; + /** * Default radix of a number. */ @@ -397,6 +407,40 @@ public class NumberUtil { return parseLongResult(possibleLong, DEFAULT_RADIX); } + // the following is based on: https://stackoverflow.com/a/2633161/6277184 + + /** + * Sums the {@code int} values using their bounds instead of wrapping on overflow. + * + * @param left left addend + * @param right right addend + * @return sum of the addends + * + * @implNote implementation is based + * on Stackoverflow answer + */ + public int saturatingSum(final int left, final int right) { + final int sum; + return (Integer.MIN_VALUE ^ (sum = left + right) >> INT_NON_SIGN_BITS ^ sum) + & ((left ^ sum) & ~(left ^ right)) >> INT_NON_SIGN_BITS ^ sum; + } + + /** + * Sums the {@code long} values using their bounds instead of wrapping on overflow. + * + * @param left left addend + * @param right right addend + * @return sum of the addends + * + * @implNote implementation is based + * on Stackoverflow answer + */ + public long saturatingSum(final long left, final long right) { + final long sum; + return (Long.MIN_VALUE ^ (sum = left + right) >> LONG_NON_SIGN_BITS ^ sum) + & ((left ^ sum) & ~(left ^ right)) >> LONG_NON_SIGN_BITS ^ sum; + } + /** * Checks that the radix is between {@link Character#MIN_RADIX} and {@link Character#MAX_RADIX}. * From 0722041c0f670967e059ba1aba3b503e03fdeb80 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Mon, 20 Dec 2021 20:02:44 +0300 Subject: [PATCH 53/59] feat(ultimate-messenger)!: use primitive values for `TextModel` bounds --- ...ractGeneratingTextModelFactoryBuilder.java | 2 +- ...gTextModel.java => CompoundTextModel.java} | 2 +- .../model/DelegatingCompoundTextModel.java | 94 +++++++++++++++++++ .../model/DelegatingNestingTextModel.java | 51 ---------- .../format/model/SimpleTextModelFactory.java | 2 +- .../format/model/TextModel.java | 42 ++++----- .../format/model/TextModelTest.java | 11 +-- 7 files changed, 116 insertions(+), 88 deletions(-) rename ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/{NestingTextModel.java => CompoundTextModel.java} (86%) create mode 100644 ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingCompoundTextModel.java delete mode 100644 ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingNestingTextModel.java diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AbstractGeneratingTextModelFactoryBuilder.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AbstractGeneratingTextModelFactoryBuilder.java index b759d435..0bdc0cb1 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AbstractGeneratingTextModelFactoryBuilder.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AbstractGeneratingTextModelFactoryBuilder.java @@ -79,7 +79,7 @@ protected void endModification(final @NotNull SN staticNode) { protected void endModification(final @NotNull DN dynamicNode) { // increment the amount of dynamic elements dynamicNodeCount++; - dynamicNode.getContent().getMinLength().ifPresent(length -> minDynamicLength += length); + minDynamicLength += dynamicNode.getContent().getMinLength(); } /** diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/NestingTextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java similarity index 86% rename from ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/NestingTextModel.java rename to ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java index 5f89e8c5..051d2b43 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/NestingTextModel.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java @@ -10,7 +10,7 @@ * * @param type of object according to which the text model is formatted */ -public interface NestingTextModel extends TextModel, List> { +public interface CompoundTextModel extends TextModel, List> { @Override default @NotNull String getText(@NotNull T target) { diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingCompoundTextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingCompoundTextModel.java new file mode 100644 index 00000000..20891b24 --- /dev/null +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingCompoundTextModel.java @@ -0,0 +1,94 @@ +package ru.progrm_jarvis.ultimatemessenger.format.model; + +import lombok.*; +import lombok.experimental.Delegate; +import lombok.experimental.FieldDefaults; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; +import ru.progrm_jarvis.javacommons.ownership.annotation.Own; +import ru.progrm_jarvis.javacommons.primitive.NumberUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * {@link CompoundTextModel} which delegates its {@link List list} methods to the inner {@link List}. + * + * @param type of object according to which the text model is formatted + */ +@Value +@RequiredArgsConstructor(access = AccessLevel.PROTECTED) // allow extension +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public class DelegatingCompoundTextModel implements CompoundTextModel { + + /** + * Content of this {@link CompoundTextModel nesting text model} + */ + @Delegate @NonNull List> elements; + + /** + * Minimal possible length of the produced string + */ + int minLength; + + /** + * Maximal possible length + */ + int maxLength; + + @Override + public @NotNull String getText(@NotNull final T target) { + return CompoundTextModel.super.getText(target); + } + + @Override + public @Range(from = 0, to = Integer.MAX_VALUE) int getMinLength() { + return minLength; + } + + @Override + public @Range(from = 0, to = Integer.MAX_VALUE) int getMaxLength() { + return maxLength; + } + + /** + * Creates a new delegating {@link CompoundTextModel} using the given collection fot its backend. + * + * @param elements elements to use as this {@link CompoundTextModel nesting text model's} content + * @param type of object according to which the text model is formatted + * @return created delegating nesting text model + */ + public static @NotNull CompoundTextModel from(final @Own @NonNull List> elements) { + var minLength = 0; + var maxLength = 0; + + for (val element : elements) { + minLength += element.getMinLength(); + maxLength = NumberUtil.saturatingSum(maxLength, element.getMaxLength()); + } + + return new DelegatingCompoundTextModel<>(elements, minLength, maxLength); + } + + /** + * Creates a new delegating {@link CompoundTextModel} using the copy of the given collection fot its backend. + * + * @param elements elements copied to the new collection which will be used + * as this {@link CompoundTextModel nesting text model's} content + * @param type of object according to which the text model is formatted + * @return created delegating nesting text model + */ + public static @NotNull CompoundTextModel fromCopyOf(final @NonNull List> elements) { + val copy = new ArrayList>(elements.size()); + var minLength = 0; + var maxLength = 0; + + for (val element : elements) { + copy.add(element); + minLength += element.getMinLength(); + maxLength = NumberUtil.saturatingSum(maxLength, element.getMaxLength()); + } + + return new DelegatingCompoundTextModel<>(copy, minLength, maxLength); + } +} diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingNestingTextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingNestingTextModel.java deleted file mode 100644 index 8156942a..00000000 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingNestingTextModel.java +++ /dev/null @@ -1,51 +0,0 @@ -package ru.progrm_jarvis.ultimatemessenger.format.model; - -import lombok.AccessLevel; -import lombok.Data; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import lombok.experimental.Delegate; -import lombok.experimental.FieldDefaults; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; - -/** - * {@link NestingTextModel} which delegates its {@link List list} methods to the inner {@link List}. - * - * @param type of object according to which the text model is formatted - */ -@Data -@RequiredArgsConstructor(access = AccessLevel.PROTECTED) // allow extension -@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) -public class DelegatingNestingTextModel implements NestingTextModel { - - /** - * Content of this {@link NestingTextModel nesting text model} - */ - @Delegate @NonNull List> elements; - - /** - * Creates a new delegating {@link NestingTextModel} using the given collection fot its backend. - * - * @param elements elements to use as this {@link NestingTextModel nesting text model's} content - * @param type of object according to which the text model is formatted - * @return created delegating nesting text model - */ - public static @NotNull NestingTextModel from(final @NonNull List> elements) { - return new DelegatingNestingTextModel<>(elements); - } - - /** - * Creates a new delegating {@link NestingTextModel} using the copy of the given collection fot its backend. - * - * @param elements elements copied to the new collection which will be used - * as this {@link NestingTextModel nesting text model's} content - * @param type of object according to which the text model is formatted - * @return created delegating nesting text model - */ - public static @NotNull NestingTextModel fromCopyOf(final @NonNull List> elements) { - return new DelegatingNestingTextModel<>(new ArrayList<>(elements)); - } -} diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java index 1c041fe2..268c243c 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java @@ -97,7 +97,7 @@ private static final class SimpleTextModelBuilder extends AbstractCachingText @Override protected @NotNull TextModel buildTextModel(final boolean release) { - return elements.isEmpty() ? TextModel.empty() : DelegatingNestingTextModel.fromCopyOf(elements); + return elements.isEmpty() ? TextModel.empty() : DelegatingCompoundTextModel.fromCopyOf(elements); } } } diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java index a3b4144d..1f766306 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java @@ -5,6 +5,7 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Range; import java.util.OptionalInt; @@ -42,19 +43,20 @@ default boolean isDynamic() { /** * Gets the minimal length of the value returned by {@link #getText(Object)}. * - * @return minimal possible length of the value returned by {@link #getText(Object)} being empty if it is undefined + * @return minimal possible length of the value returned by {@link #getText(Object)} */ - default @NotNull OptionalInt getMinLength() { - return OptionalInt.empty(); + default @Range(from = 0, to = Integer.MAX_VALUE) int getMinLength() { + return 0; } /** * Gets the maximal length of the value returned by {@link #getText(Object)}. * - * @return maximal possible length of the value returned by {@link #getText(Object)} being empty if it is undefined + * @return maximal possible length of the value returned by {@link #getText(Object)} + * or {@link Integer#MAX_VALUE} if it is unknown or may be bigger than {@link Integer#MAX_VALUE} */ - default @NotNull OptionalInt getMaxLength() { - return OptionalInt.empty(); + default @Range(from = 0, to = Integer.MAX_VALUE) int getMaxLength() { + return Integer.MAX_VALUE; } /** @@ -76,7 +78,7 @@ default boolean isDynamic() { * @return text model of the given static text */ static @NotNull TextModel of(final @NonNull String text) { - return new StaticTextModel<>(text, OptionalInt.of(text.length())); + return new StaticTextModel<>(text); } /** @@ -91,12 +93,6 @@ final class EmptyTextModel implements TextModel { */ private static final int EMPTY_HASHCODE = 0; - /** - * {@code 0} wrapped in {@link OptionalInt} - */ - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") - private static final @NotNull OptionalInt OPTIONAL_ZERO = OptionalInt.of(0); - /** * Singleton instance of this text model */ @@ -110,14 +106,14 @@ final class EmptyTextModel implements TextModel { @Override @Contract(pure = true) - public @NotNull OptionalInt getMinLength() { - return OPTIONAL_ZERO; + public @Range(from = 0, to = Integer.MAX_VALUE) int getMinLength() { + return 0; } @Override @Contract(pure = true) - public @NotNull OptionalInt getMaxLength() { - return OPTIONAL_ZERO; + public @Range(from = 0, to = Integer.MAX_VALUE) int getMaxLength() { + return 0; } @Override @@ -166,10 +162,6 @@ class StaticTextModel implements TextModel { * Text of this text model */ @NonNull String text; - /** - * Length of ths text model's {@link #text text} wrapped in {@link OptionalInt} - */ - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @NonNull OptionalInt length; @Override @Contract(pure = true) @@ -179,14 +171,14 @@ public boolean isDynamic() { @Override @Contract(pure = true) - public @NotNull OptionalInt getMinLength() { - return length; + public @Range(from = 0, to = Integer.MAX_VALUE) int getMinLength() { + return text.length(); } @Override @Contract(pure = true) - public @NotNull OptionalInt getMaxLength() { - return length; + public @Range(from = 0, to = Integer.MAX_VALUE) int getMaxLength() { + return text.length(); } @Override diff --git a/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModelTest.java b/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModelTest.java index fefe9ce1..41e4797c 100644 --- a/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModelTest.java +++ b/ultimate-messenger/src/test/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModelTest.java @@ -14,7 +14,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.params.provider.Arguments.arguments; class TextModelTest { @@ -50,19 +49,13 @@ void testGetTextForNotNull(final @NotNull TextModel textModel, final @NotN @ParameterizedTest @MethodSource("provideTestSubjects") void testMinLength(final @NotNull TextModel textModel, final @NotNull String text) { - assertThat(textModel.getMinLength().orElseGet(() -> { - fail("Min length is undefined"); - return 0; - }), is(text.length())); + assertThat(textModel.getMinLength(), is(text.length())); } @ParameterizedTest @MethodSource("provideTestSubjects") void testMaxLength(final @NotNull TextModel textModel, final @NotNull String text) { - assertThat(textModel.getMaxLength().orElseGet(() -> { - fail("Max length is undefined"); - return 0; - }), is(text.length())); + assertThat(textModel.getMaxLength(), is(text.length())); } @Value From a7f92cc5da8122248233157f34e19bb4df6e7594 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Mon, 20 Dec 2021 20:10:44 +0300 Subject: [PATCH 54/59] feat: add `TextModel#write(..)` for future optimized implementations --- .../format/model/TextModel.java | 81 ++++++++++++++++--- 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java index 1f766306..ddf693c0 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java @@ -1,13 +1,19 @@ package ru.progrm_jarvis.ultimatemessenger.format.model; -import lombok.*; +import lombok.AccessLevel; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.Value; import lombok.experimental.FieldDefaults; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Range; -import java.util.OptionalInt; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; /** * Parsed model of a dynamic text. @@ -20,7 +26,7 @@ public interface TextModel { /** * Gets the text formatted for the given target. * - * @param target object according to which the text models gets formatted, + * @param target object according to which the text models gets formatted * if the model is not {@link #isDynamic() dynamic} then it should return the same result for any {@code target} * including {@code null} * @return text formatted for the given target @@ -29,6 +35,39 @@ public interface TextModel { */ @NotNull String getText(T target); + /** + * Writes the text formatted for the gicen target into the provided output. + * + * @param output text output + * @param target object according to which the text models gets formatted + * @throws IOException if it is thrown by the {@code output} + */ + default void write(final @NonNull DataOutputStream output, final T target) throws IOException { + output.writeUTF(getText(target)); + } + + /** + * Writes the text formatted for the gicen target into the provided output. + * + * @param output text output + * @param target object according to which the text models gets formatted + * @throws IOException if it is thrown by the {@code output} + */ + default void write(final @NonNull Writer output, final T target) throws IOException { + output.write(getText(target)); + } + + /** + * Writes the text formatted for the gicen target into the provided output. + * + * @param output text output + * @param target object according to which the text models gets formatted + * @throws IOException if it is thrown by the {@code output} + */ + default void write(final @NonNull PrintWriter output, final T target) { + output.write(getText(target)); + } + /** * Retrieves whether this text model is dynamic. * @@ -104,6 +143,15 @@ final class EmptyTextModel implements TextModel { return ""; // thanks to JVM magic this is always the same object (got using LDC) } + @Override + public void write(final @NonNull DataOutputStream output, final Object target) {} + + @Override + public void write(final @NonNull Writer output, final Object target) {} + + @Override + public void write(final @NonNull PrintWriter output, final Object target) {} + @Override @Contract(pure = true) public @Range(from = 0, to = Integer.MAX_VALUE) int getMinLength() { @@ -163,6 +211,27 @@ class StaticTextModel implements TextModel { */ @NonNull String text; + @Override + @Contract(pure = true) + public @NotNull String getText(final @Nullable T target) { + return text; + } + + @Override + public void write(final @NonNull DataOutputStream output, final Object target) throws IOException { + output.writeUTF(text); + } + + @Override + public void write(final @NonNull Writer output, final Object target) throws IOException { + output.write(text); + } + + @Override + public void write(final @NonNull PrintWriter output, final Object target) { + output.write(text); + } + @Override @Contract(pure = true) public boolean isDynamic() { @@ -181,12 +250,6 @@ public boolean isDynamic() { return text.length(); } - @Override - @Contract(pure = true) - public @NotNull String getText(final @Nullable T target) { - return text; - } - @Override @Contract(pure = true) public boolean equals(final @Nullable Object object) { From f85b2a85666e57394e0abd3e2fdabe7079f6002f Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Mon, 20 Dec 2021 20:14:19 +0300 Subject: [PATCH 55/59] refactor: implement `CompoundTextModel#write(..)` --- .../format/model/CompoundTextModel.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java index 051d2b43..a664a24e 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java @@ -1,7 +1,13 @@ package ru.progrm_jarvis.ultimatemessenger.format.model; +import lombok.NonNull; +import lombok.val; import org.jetbrains.annotations.NotNull; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; import java.util.List; import java.util.stream.Collectors; @@ -18,4 +24,19 @@ public interface CompoundTextModel extends TextModel, List> { .map(element -> element.getText(target)) .collect(Collectors.joining()); } + + @Override + default void write(final @NonNull DataOutputStream output, final T target) throws IOException { + for (val element : this) element.write(output, target); + } + + @Override + default void write(final @NonNull Writer output, final T target) throws IOException { + for (val element : this) element.write(output, target); + } + + @Override + default void write(final @NonNull PrintWriter output, final T target) { + for (val element : this) element.write(output, target); + } } From ec15433e18b14181f33061659fcb5db2012216c3 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Mon, 20 Dec 2021 20:33:45 +0300 Subject: [PATCH 56/59] feat: deprecate `DelegatingCompoundTextModel` in favor of factories in `CompoundTextModel` --- .../format/model/CompoundTextModel.java | 105 +++++++++++++++++- .../model/DelegatingCompoundTextModel.java | 94 ---------------- .../model/DelegatingNestingTextModel.java | 48 ++++++++ .../format/model/SimpleTextModelFactory.java | 2 +- .../format/model/TextModel.java | 48 +++++++- 5 files changed, 197 insertions(+), 100 deletions(-) delete mode 100644 ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingCompoundTextModel.java create mode 100644 ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingNestingTextModel.java diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java index a664a24e..dd42adc7 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java @@ -1,13 +1,21 @@ package ru.progrm_jarvis.ultimatemessenger.format.model; -import lombok.NonNull; -import lombok.val; +import lombok.*; +import lombok.experimental.Delegate; +import lombok.experimental.FieldDefaults; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; +import org.jetbrains.annotations.Unmodifiable; +import ru.progrm_jarvis.javacommons.ownership.annotation.Own; +import ru.progrm_jarvis.javacommons.ownership.annotation.Ref; +import ru.progrm_jarvis.javacommons.primitive.NumberUtil; import java.io.DataOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.Writer; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -25,6 +33,20 @@ public interface CompoundTextModel extends TextModel, List> { .collect(Collectors.joining()); } + @Override + default @NotNull StringBuilder write(final @NonNull StringBuilder output, final T target) { + for (val element : this) output.append(element.getText(target)); + + return output; + } + + @Override + default @NotNull StringBuffer write(final @NonNull StringBuffer output, final T target) { + for (val element : this) output.append(element.getText(target)); + + return output; + } + @Override default void write(final @NonNull DataOutputStream output, final T target) throws IOException { for (val element : this) element.write(output, target); @@ -39,4 +61,83 @@ default void write(final @NonNull Writer output, final T target) throws IOExcept default void write(final @NonNull PrintWriter output, final T target) { for (val element : this) element.write(output, target); } + + /** + * Creates a new unmodifiable compound text model using the given collection for its backend. + * + * @param elements elements to use as this compound text model's content + * @param type of object according to which the text model is formatted + * @return created delegating nesting text model + */ + static @NotNull CompoundTextModel from(final @NonNull @Own List> elements) { + var minLength = 0; + var maxLength = 0; + for (val element : elements) { + minLength += element.getMinLength(); + maxLength = NumberUtil.saturatingSum(maxLength, element.getMaxLength()); + } + + return new DelegatingCompoundTextModel<>(Collections.unmodifiableList(elements), minLength, maxLength); + } + + /** + * Creates a new unmodifiable compound text model using the copy of the given collection's copy for its backend. + * + * @param elements elements copied to the new collection which will be used as this text model's content + * @param type of object according to which the text model is formatted + * @return created delegating nesting text model + */ + static @NotNull CompoundTextModel fromCopyOf(final @NonNull @Ref List> elements) { + val copy = new ArrayList>(elements.size()); + var minLength = 0; + var maxLength = 0; + for (val element : elements) { + copy.add(element); + minLength += element.getMinLength(); + maxLength = NumberUtil.saturatingSum(maxLength, element.getMaxLength()); + } + + return new DelegatingCompoundTextModel<>(Collections.unmodifiableList(copy), minLength, maxLength); + } + + /** + * {@link CompoundTextModel} which delegates its {@link List list} methods to the inner {@link List}. + * + * @param type of object according to which the text model is formatted + */ + @Value + @RequiredArgsConstructor(access = AccessLevel.PROTECTED) // allow extension + @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) + class DelegatingCompoundTextModel implements CompoundTextModel { + + /** + * Content of this {@link CompoundTextModel nesting text model} + */ + @Delegate @NonNull @Unmodifiable List> elements; + + /** + * Minimal possible length of the produced string as specified by {@link TextModel#getMinLength()} + */ + int minLength; + + /** + * Maximal possible length of the produced string as specified by {@link TextModel#getMaxLength()} + */ + int maxLength; + + @Override + public @NotNull String getText(@NotNull final T target) { + return write(new StringBuilder(minLength /* O(1) */), target).toString(); + } + + @Override + public @Range(from = 0, to = Integer.MAX_VALUE) int getMinLength() { + return minLength; + } + + @Override + public @Range(from = 0, to = Integer.MAX_VALUE) int getMaxLength() { + return maxLength; + } + } } diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingCompoundTextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingCompoundTextModel.java deleted file mode 100644 index 20891b24..00000000 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingCompoundTextModel.java +++ /dev/null @@ -1,94 +0,0 @@ -package ru.progrm_jarvis.ultimatemessenger.format.model; - -import lombok.*; -import lombok.experimental.Delegate; -import lombok.experimental.FieldDefaults; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Range; -import ru.progrm_jarvis.javacommons.ownership.annotation.Own; -import ru.progrm_jarvis.javacommons.primitive.NumberUtil; - -import java.util.ArrayList; -import java.util.List; - -/** - * {@link CompoundTextModel} which delegates its {@link List list} methods to the inner {@link List}. - * - * @param type of object according to which the text model is formatted - */ -@Value -@RequiredArgsConstructor(access = AccessLevel.PROTECTED) // allow extension -@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) -public class DelegatingCompoundTextModel implements CompoundTextModel { - - /** - * Content of this {@link CompoundTextModel nesting text model} - */ - @Delegate @NonNull List> elements; - - /** - * Minimal possible length of the produced string - */ - int minLength; - - /** - * Maximal possible length - */ - int maxLength; - - @Override - public @NotNull String getText(@NotNull final T target) { - return CompoundTextModel.super.getText(target); - } - - @Override - public @Range(from = 0, to = Integer.MAX_VALUE) int getMinLength() { - return minLength; - } - - @Override - public @Range(from = 0, to = Integer.MAX_VALUE) int getMaxLength() { - return maxLength; - } - - /** - * Creates a new delegating {@link CompoundTextModel} using the given collection fot its backend. - * - * @param elements elements to use as this {@link CompoundTextModel nesting text model's} content - * @param type of object according to which the text model is formatted - * @return created delegating nesting text model - */ - public static @NotNull CompoundTextModel from(final @Own @NonNull List> elements) { - var minLength = 0; - var maxLength = 0; - - for (val element : elements) { - minLength += element.getMinLength(); - maxLength = NumberUtil.saturatingSum(maxLength, element.getMaxLength()); - } - - return new DelegatingCompoundTextModel<>(elements, minLength, maxLength); - } - - /** - * Creates a new delegating {@link CompoundTextModel} using the copy of the given collection fot its backend. - * - * @param elements elements copied to the new collection which will be used - * as this {@link CompoundTextModel nesting text model's} content - * @param type of object according to which the text model is formatted - * @return created delegating nesting text model - */ - public static @NotNull CompoundTextModel fromCopyOf(final @NonNull List> elements) { - val copy = new ArrayList>(elements.size()); - var minLength = 0; - var maxLength = 0; - - for (val element : elements) { - copy.add(element); - minLength += element.getMinLength(); - maxLength = NumberUtil.saturatingSum(maxLength, element.getMaxLength()); - } - - return new DelegatingCompoundTextModel<>(copy, minLength, maxLength); - } -} diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingNestingTextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingNestingTextModel.java new file mode 100644 index 00000000..9befec8a --- /dev/null +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/DelegatingNestingTextModel.java @@ -0,0 +1,48 @@ +package ru.progrm_jarvis.ultimatemessenger.format.model; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.NotNull; +import ru.progrm_jarvis.javacommons.ownership.annotation.Own; +import ru.progrm_jarvis.javacommons.ownership.annotation.Ref; + +import java.util.List; + +/** + * Legacy factory of static {@link CompoundTextModel compound text models}. + * + * @deprecated use {@link CompoundTextModel#from(List)} and {@link CompoundTextModel#fromCopyOf(List)} instead, + * this one will most probably be removed before release 1.0.0 + */ +@Deprecated +@UtilityClass +public class DelegatingNestingTextModel { + + /** + * Creates a new unmodifiable compound text model using the given collection for its backend. + * + * @param elements elements to use as this compound text model's content + * @param type of object according to which the text model is formatted + * @return created delegating nesting text model + * + * @deprecated use {@link CompoundTextModel#from(List)} instead + */ + @Deprecated + public @NotNull CompoundTextModel from(final @NonNull @Own List> elements) { + return CompoundTextModel.from(elements); + } + + /** + * Creates a new unmodifiable compound text model using the copy of the given collection's copy for its backend. + * + * @param elements elements copied to the new collection which will be used as this text model's content + * @param type of object according to which the text model is formatted + * @return created delegating nesting text model + * + * @deprecated use {@link CompoundTextModel#fromCopyOf(List)} instead + */ + @Deprecated + public @NotNull CompoundTextModel fromCopyOf(final @NonNull @Ref List> elements) { + return CompoundTextModel.fromCopyOf(elements); + } +} diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java index 268c243c..0d24a0a6 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/SimpleTextModelFactory.java @@ -97,7 +97,7 @@ private static final class SimpleTextModelBuilder extends AbstractCachingText @Override protected @NotNull TextModel buildTextModel(final boolean release) { - return elements.isEmpty() ? TextModel.empty() : DelegatingCompoundTextModel.fromCopyOf(elements); + return elements.isEmpty() ? TextModel.empty() : CompoundTextModel.fromCopyOf(elements); } } } diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java index ddf693c0..478c7617 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java @@ -36,7 +36,29 @@ public interface TextModel { @NotNull String getText(T target); /** - * Writes the text formatted for the gicen target into the provided output. + * Writes the text formatted for the given target into the provided output. + * + * @param output text output + * @param target object according to which the text models gets formatted + * @return chained {@code output} + */ + default @NotNull StringBuilder write(final @NonNull StringBuilder output, final T target) { + return output.append(getText(target)); + } + + /** + * Writes the text formatted for the given target into the provided output. + * + * @param output text output + * @param target object according to which the text models gets formatted + * @return chained {@code output} + */ + default @NotNull StringBuffer write(final @NonNull StringBuffer output, final T target) { + return output.append(getText(target)); + } + + /** + * Writes the text formatted for the given target into the provided output. * * @param output text output * @param target object according to which the text models gets formatted @@ -47,7 +69,7 @@ default void write(final @NonNull DataOutputStream output, final T target) throw } /** - * Writes the text formatted for the gicen target into the provided output. + * Writes the text formatted for the given target into the provided output. * * @param output text output * @param target object according to which the text models gets formatted @@ -58,7 +80,7 @@ default void write(final @NonNull Writer output, final T target) throws IOExcept } /** - * Writes the text formatted for the gicen target into the provided output. + * Writes the text formatted for the given target into the provided output. * * @param output text output * @param target object according to which the text models gets formatted @@ -143,6 +165,16 @@ final class EmptyTextModel implements TextModel { return ""; // thanks to JVM magic this is always the same object (got using LDC) } + @Override + public @NotNull StringBuilder write(final @NonNull StringBuilder output, final Object target) { + return output; + } + + @Override + public @NotNull StringBuffer write(final @NonNull StringBuffer output, final Object target) { + return output; + } + @Override public void write(final @NonNull DataOutputStream output, final Object target) {} @@ -217,6 +249,16 @@ class StaticTextModel implements TextModel { return text; } + @Override + public @NotNull StringBuilder write(final @NonNull StringBuilder output, final Object target) { + return output.append(text); + } + + @Override + public @NotNull StringBuffer write(final @NonNull StringBuffer output, final Object target) { + return output.append(text); + } + @Override public void write(final @NonNull DataOutputStream output, final Object target) throws IOException { output.writeUTF(text); From 276d1c947ff79e222932cd7a8ba709bb30cac91e Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Mon, 20 Dec 2021 20:45:33 +0300 Subject: [PATCH 57/59] fix(ultimate-messenger): use `NumberUtil#saturingAdd(..)` when worjing with `TextModel`'s min lengths --- .../model/AbstractGeneratingTextModelFactoryBuilder.java | 3 ++- .../ultimatemessenger/format/model/CompoundTextModel.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AbstractGeneratingTextModelFactoryBuilder.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AbstractGeneratingTextModelFactoryBuilder.java index 0bdc0cb1..1f28a700 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AbstractGeneratingTextModelFactoryBuilder.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/AbstractGeneratingTextModelFactoryBuilder.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.MustBeInvokedByOverriders; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Range; +import ru.progrm_jarvis.javacommons.primitive.NumberUtil; import java.util.ArrayList; import java.util.List; @@ -79,7 +80,7 @@ protected void endModification(final @NotNull SN staticNode) { protected void endModification(final @NotNull DN dynamicNode) { // increment the amount of dynamic elements dynamicNodeCount++; - minDynamicLength += dynamicNode.getContent().getMinLength(); + minDynamicLength = NumberUtil.saturatingSum(minDynamicLength, dynamicNode.getContent().getMinLength()); } /** diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java index dd42adc7..f37d312d 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/CompoundTextModel.java @@ -73,7 +73,7 @@ default void write(final @NonNull PrintWriter output, final T target) { var minLength = 0; var maxLength = 0; for (val element : elements) { - minLength += element.getMinLength(); + minLength = NumberUtil.saturatingSum(minLength, element.getMinLength()); maxLength = NumberUtil.saturatingSum(maxLength, element.getMaxLength()); } @@ -93,7 +93,7 @@ default void write(final @NonNull PrintWriter output, final T target) { var maxLength = 0; for (val element : elements) { copy.add(element); - minLength += element.getMinLength(); + minLength = NumberUtil.saturatingSum(minLength, element.getMinLength()); maxLength = NumberUtil.saturatingSum(maxLength, element.getMaxLength()); } From 5385d093b3d958bfa1476720f08277d70ab2bd58 Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Mon, 20 Dec 2021 21:06:21 +0300 Subject: [PATCH 58/59] docs(ultimate-messenger): remove redundant `@throws` from `TextModel#write(PrintWriter, ..)` --- .../progrm_jarvis/ultimatemessenger/format/model/TextModel.java | 1 - 1 file changed, 1 deletion(-) diff --git a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java index 478c7617..607a595b 100644 --- a/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java +++ b/ultimate-messenger/src/main/java/ru/progrm_jarvis/ultimatemessenger/format/model/TextModel.java @@ -84,7 +84,6 @@ default void write(final @NonNull Writer output, final T target) throws IOExcept * * @param output text output * @param target object according to which the text models gets formatted - * @throws IOException if it is thrown by the {@code output} */ default void write(final @NonNull PrintWriter output, final T target) { output.write(getText(target)); From dafaa1285398cb45929d5a3034c0064047bb162a Mon Sep 17 00:00:00 2001 From: Petr Portnov Date: Tue, 21 Dec 2021 20:12:05 +0300 Subject: [PATCH 59/59] build: bump version to `1.0.0-rc.8` --- java-commons/pom.xml | 2 +- padla-bom/pom.xml | 8 ++++---- pom.xml | 2 +- reflector/pom.xml | 2 +- ultimate-messenger/pom.xml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/java-commons/pom.xml b/java-commons/pom.xml index d244edbe..36bd8e6a 100644 --- a/java-commons/pom.xml +++ b/java-commons/pom.xml @@ -6,7 +6,7 @@ ru.progrm-jarvis padla - 1.0.0-SNAPSHOT + 1.0.0-rc.8 java-commons diff --git a/padla-bom/pom.xml b/padla-bom/pom.xml index f9c59a21..574b00f6 100644 --- a/padla-bom/pom.xml +++ b/padla-bom/pom.xml @@ -6,7 +6,7 @@ ru.progrm-jarvis padla - 1.0.0-SNAPSHOT + 1.0.0-rc.8 padla-bom pom @@ -20,17 +20,17 @@ ru.progrm-jarvis java-commons - 1.0.0-SNAPSHOT + 1.0.0-rc.8 ru.progrm-jarvis reflector - 1.0.0-SNAPSHOT + 1.0.0-rc.8 ru.progrm-jarvis ultimate-messenger - 1.0.0-SNAPSHOT + 1.0.0-rc.8 diff --git a/pom.xml b/pom.xml index 24e2a584..216e9745 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 ru.progrm-jarvis padla - 1.0.0-SNAPSHOT + 1.0.0-rc.8 java-commons reflector diff --git a/reflector/pom.xml b/reflector/pom.xml index ad2dea06..c59b19e3 100644 --- a/reflector/pom.xml +++ b/reflector/pom.xml @@ -6,7 +6,7 @@ ru.progrm-jarvis padla - 1.0.0-SNAPSHOT + 1.0.0-rc.8 reflector diff --git a/ultimate-messenger/pom.xml b/ultimate-messenger/pom.xml index 9023600c..db161cba 100644 --- a/ultimate-messenger/pom.xml +++ b/ultimate-messenger/pom.xml @@ -6,7 +6,7 @@ ru.progrm-jarvis padla - 1.0.0-SNAPSHOT + 1.0.0-rc.8 ultimate-messenger