From b3e9ee6373a44865f70ef9281c6d1c85f795f5a9 Mon Sep 17 00:00:00 2001 From: mauro <851903+mtrevisan@users.noreply.github.com> Date: Sun, 3 Mar 2024 16:16:26 +0100 Subject: [PATCH 01/15] readme --- README.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 5b1d9ad78..5bc1780f9 100644 --- a/README.md +++ b/README.md @@ -1541,24 +1541,24 @@ Pull requests are welcomed. - improvement on handling values inside big decimal converter. - improvement on error reporting. -- renamed `Composer.composeMessage` into compose. +- renamed `Composer.composeMessage` into `compose`. - corrected error while showing the start array of message header in the description. -- fix size validation of array and list (can be zero) +- fix size validation of array and list (now it can be zero). ### version 3.1.1 - 20240229 -- Fixed an error if annotating with @Skip as the last a of the POJO. +- Fixed an error if annotating with `@Skip` as the last annotation of the POJO. ### version 3.1.0 - 20240228 -- Added `BindList`, the equivalent of `BindArray` for messages with separators. +- Added `@BindList`, the equivalent of `@BindArray` for messages with separators. ### version 3.0.2 - 20240223 -- Fixed a bug on `ConfigurationHeader` where the protocol range check was incorrectly done considering the minimum protocol as the maximum. +- Fixed a bug on `@ConfigurationHeader` where the protocol range check was incorrectly done considering the minimum protocol as the maximum. ### version 3.0.1 - 20240220 @@ -1570,29 +1570,26 @@ Pull requests are welcomed. - Added `CoreBuilder` to facilitate the creation of a `Core`: now it is no longer necessary to remember the order in which the methods should be called. - Added missing javadoc. Enhanced existing javadoc. -- Added `BindBitSet` binding for java `BitSet`. +- Added `@BindBitSet` binding for java `@BitSet`. - Added `Extractor`, used to programmatically extract values from a POJO. - Removed `Bits`. - Enhanced binding validation. - Fixed a concurrency bug on the validation of alternatives. - Reordered some packages to better reflect usage. - ### version 2.1.2 - 20210118 - Added missing javadoc. - No more cycles between classes or packages. - ### version 2.1.1 - 20210114 -- Bug fix: `Evaluator` class is now exported. +- Bug fix: `Evaluator` class is now exportable. - Removed a package cycle. - General cleaning of the code (removed duplicated code, useless templates, etc.). - ### version 2.1.0 - 20211213 @@ -1600,7 +1597,6 @@ Pull requests are welcomed. - Added methods to retrieve a description of the protocol (in JSON format). - Decomposed and simplified `Parser` class. - ### version 2.0.0 - 20211127 From cda3db512ee24d1bf45538426075f8702fbd259c Mon Sep 17 00:00:00 2001 From: mauro <851903+mtrevisan@users.noreply.github.com> Date: Sun, 3 Mar 2024 19:17:16 +0100 Subject: [PATCH 02/15] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5bc1780f9..7774de2a1 100644 --- a/README.md +++ b/README.md @@ -1537,7 +1537,7 @@ Pull requests are welcomed. ## Changelog -### version 3.1.2 - 202403?? +### version 3.1.2 - 20240302 - improvement on handling values inside big decimal converter. - improvement on error reporting. From 7e7a450f82d222706d6d5876c0897e477c7ef194 Mon Sep 17 00:00:00 2001 From: mauro <851903+mtrevisan@users.noreply.github.com> Date: Sun, 3 Mar 2024 19:20:26 +0100 Subject: [PATCH 03/15] library version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7d4eeeb4a..1e6090ea2 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ 2.0.12 - 1.5.1 + 1.5.2 From 4090f17617c4492fd92ce4bc6316e9c36baf8307 Mon Sep 17 00:00:00 2001 From: mauro <851903+mtrevisan@users.noreply.github.com> Date: Sun, 3 Mar 2024 21:18:15 +0100 Subject: [PATCH 04/15] version method name change --- pom.xml | 2 +- .../mtrevisan/boxon/core/Descriptor.java | 29 +++++++++++++++++-- .../boxon/core/keys/DescriberKey.java | 2 ++ .../mtrevisan/boxon/core/DescriptorTest.java | 11 +++---- .../boxon/core/DescriptorThreadedTest.java | 6 ++-- .../boxon/core/codecs/CodecListTest.java | 2 +- 6 files changed, 39 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index 1e6090ea2..1d00c8d10 100644 --- a/pom.xml +++ b/pom.xml @@ -299,7 +299,7 @@ org.codehaus.mojo templating-maven-plugin - 1.0.0 + 3.0.0 generate-version-class diff --git a/src/main/java/io/github/mtrevisan/boxon/core/Descriptor.java b/src/main/java/io/github/mtrevisan/boxon/core/Descriptor.java index f087267da..339a14b4d 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/Descriptor.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/Descriptor.java @@ -80,7 +80,7 @@ private Descriptor(final Core core){ * @return The list of descriptions. * @throws TemplateException If a template is not well formatted. */ - public List> describeTemplates() throws TemplateException{ + public List> describe() throws TemplateException{ final Collection> templates = loaderTemplate.getTemplates(); final List> description = new ArrayList<>(templates.size()); for(final Template template : templates) @@ -88,6 +88,24 @@ public List> describeTemplates() throws TemplateException{ return Collections.unmodifiableList(description); } + /** + * Description of a single template annotated with {@link MessageHeader}. + * + * @param templateClass Template class to be described. + * @return The list of descriptions. + * @throws AnnotationException If an annotation is not well formatted. + * @throws TemplateException If a template is not well formatted. + */ + public Map describe(final Class templateClass) throws AnnotationException, TemplateException{ + if(templateClass.isAnnotationPresent(MessageHeader.class)){ + final Template template = loaderTemplate.extractTemplate(templateClass); + return describeTemplate(template); + } + + throw AnnotationException.create("Template {} didn't have the `MessageHeader` annotation", + templateClass.getSimpleName()); + } + /** * Description of all the templates in the given package annotated with {@link MessageHeader}. * @@ -96,7 +114,7 @@ public List> describeTemplates() throws TemplateException{ * @throws AnnotationException If an annotation is not well formatted. * @throws TemplateException If a template is not well formatted. */ - public List> describeTemplates(final Class... templateClasses) throws AnnotationException, TemplateException{ + public List> describe(final Class... templateClasses) throws AnnotationException, TemplateException{ final List> description = new ArrayList<>(templateClasses.length); for(int i = 0; i < templateClasses.length; i ++){ final Class templateClass = templateClasses[i]; @@ -104,12 +122,16 @@ public List> describeTemplates(final Class... templateCla final Template template = loaderTemplate.extractTemplate(templateClass); description.add(describeTemplate(template)); } + else + throw AnnotationException.create("Template {} didn't have the `MessageHeader` annotation", + templateClass.getSimpleName()); } return Collections.unmodifiableList(description); } private Map describeTemplate(final Template template) throws TemplateException{ final Map description = new HashMap<>(3); + description.put(DescriberKey.TEMPLATE.toString(), template.getType().getName()); describeHeader(template.getHeader(), description); describeFields(template.getBoundedFields(), description); describeContext(description); @@ -157,7 +179,8 @@ private void describeContext(final Map description){ final Map ctx = new HashMap<>(core.getContext()); ctx.remove(ContextHelper.CONTEXT_SELF); ctx.remove(ContextHelper.CONTEXT_CHOICE_PREFIX); - description.put(DescriberKey.CONTEXT.toString(), ctx); + if(!ctx.isEmpty()) + description.put(DescriberKey.CONTEXT.toString(), ctx); } } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/keys/DescriberKey.java b/src/main/java/io/github/mtrevisan/boxon/core/keys/DescriberKey.java index a0b3eb71d..909788b9e 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/keys/DescriberKey.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/keys/DescriberKey.java @@ -29,6 +29,8 @@ * Holds the constants used as a key in the {@link io.github.mtrevisan.boxon.core.Descriptor Descriptor}. */ public enum DescriberKey{ + TEMPLATE("template"), + CONTEXT("context"), HEADER("header"), diff --git a/src/test/java/io/github/mtrevisan/boxon/core/DescriptorTest.java b/src/test/java/io/github/mtrevisan/boxon/core/DescriptorTest.java index 02c862e09..8aef6f652 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/DescriptorTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/DescriptorTest.java @@ -58,14 +58,17 @@ void description() throws AnnotationException, ConfigurationException, CodecExce .create(); Descriptor descriptor = Descriptor.create(core); - List> descriptions = descriptor.describeTemplates(); + List> descriptions = descriptor.describe(); Assertions.assertEquals(1, descriptions.size()); Map description = descriptions.get(0); String jsonDescription = PrettyPrintMap.toString(description); - Assertions.assertEquals("{fields:[{charset:UTF-8,size:#headerLength(),name:messageHeader,annotationType:io.github.mtrevisan.boxon.annotations.bindings.BindString,fieldType:java.lang.String},{converter:" + Assertions.assertEquals("{template:io.github.mtrevisan.boxon.core.codecs.queclink.ACKMessageHex," + + "context:{headerLength:" + ParserTest.class.getDeclaredMethod("headerLength") + + ",deviceTypes:[QUECLINK_GB200S (0x46)]},header:{start:[+ACK],charset:UTF-8}" + + ",fields:[{charset:UTF-8,size:#headerLength(),name:messageHeader,annotationType:io.github.mtrevisan.boxon.annotations.bindings.BindString,fieldType:java.lang.String},{converter:" + ACKMessageHex.MessageTypeConverter.class.getName() + ",name:messageType,annotationType:io.github.mtrevisan.boxon.annotations.bindings.BindByte,fieldType:java.lang.String},{converter:" + ACKMaskHex.ACKMaskConverter.class.getName() @@ -89,9 +92,7 @@ void description() throws AnnotationException, ConfigurationException, CodecExce + ZonedDateTime.class.getName() + ",byteOrder:BIG_ENDIAN},{condition:mask.hasMessageId(),name:messageId,annotationType:io.github.mtrevisan.boxon.annotations.bindings.BindShort,fieldType:short,byteOrder:BIG_ENDIAN},{skipEnd:4,skipStart:4,name:checksum,annotationType:io.github.mtrevisan.boxon.annotations.Checksum,startValue:-1,type:short,fieldType:short,byteOrder:BIG_ENDIAN,algorithm:" + CRC16CCITT.class.getName() - + "}],context:{headerLength:" - + ParserTest.class.getDeclaredMethod("headerLength") - + ",deviceTypes:[QUECLINK_GB200S (0x46)]},header:{start:[+ACK],charset:UTF-8}}", jsonDescription); + + "}]}", jsonDescription); } } diff --git a/src/test/java/io/github/mtrevisan/boxon/core/DescriptorThreadedTest.java b/src/test/java/io/github/mtrevisan/boxon/core/DescriptorThreadedTest.java index 2f4bcdb1a..8ae083307 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/DescriptorThreadedTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/DescriptorThreadedTest.java @@ -57,7 +57,7 @@ void concurrencySingleParserSingleCore() throws AnnotationException, Configurati int threadCount = 10; AtomicInteger counter = new AtomicInteger(); MultithreadingHelper.testMultithreading( - () -> descriptor.describeTemplates(), + () -> descriptor.describe(), descriptions -> counter.addAndGet(descriptions.size()), threadCount ); @@ -82,7 +82,7 @@ void concurrencyMultipleParserSingleCore() throws NoSuchMethodException, Templat MultithreadingHelper.testMultithreading( () -> { Descriptor descriptor = Descriptor.create(core); - return descriptor.describeTemplates(); + return descriptor.describe(); }, descriptions -> counter.addAndGet(descriptions.size()), threadCount @@ -108,7 +108,7 @@ void concurrencyMultipleParserMultipleCore() throws NoSuchMethodException, Templ .withTemplate(ACKMessageHex.class) .create(); Descriptor descriptor = Descriptor.create(core); - return descriptor.describeTemplates(); + return descriptor.describe(); }, descriptions -> counter.addAndGet(descriptions.size()), threadCount diff --git a/src/test/java/io/github/mtrevisan/boxon/core/codecs/CodecListTest.java b/src/test/java/io/github/mtrevisan/boxon/core/codecs/CodecListTest.java index 0a9df6174..21ae2becb 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/codecs/CodecListTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/codecs/CodecListTest.java @@ -210,7 +210,7 @@ public ConverterChoice[] alternatives(){ ReflectionHelper.injectValue(codec, TemplateParserInterface.class, templateParser); ReflectionHelper.injectValue(codec, Evaluator.class, Evaluator.create()); BitWriter writer = BitWriter.create(); - codec.encode(writer, annotation, null, encodedValue); + codec.encode(writer, annotation, null, encodedValue); writer.flush(); Assertions.assertEquals("2,0,1,12,2,1,2,0,", new String(writer.array(), StandardCharsets.UTF_8)); From ee73b47e7187f2615edd56dc10e8cd16bee36097 Mon Sep 17 00:00:00 2001 From: Mauro Trevisan Date: Mon, 4 Mar 2024 14:34:20 +0100 Subject: [PATCH 05/15] fixed duplicated descriptions --- README.md | 5 +++++ src/main/java/io/github/mtrevisan/boxon/core/Descriptor.java | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7774de2a1..d50e7bb5b 100644 --- a/README.md +++ b/README.md @@ -1536,6 +1536,11 @@ Pull requests are welcomed. ## Changelog + +### version 3.1.3 - 202403?? + +- fixed duplicated descriptions + ### version 3.1.2 - 20240302 diff --git a/src/main/java/io/github/mtrevisan/boxon/core/Descriptor.java b/src/main/java/io/github/mtrevisan/boxon/core/Descriptor.java index 339a14b4d..6781dbd18 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/Descriptor.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/Descriptor.java @@ -41,6 +41,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; @@ -81,7 +82,8 @@ private Descriptor(final Core core){ * @throws TemplateException If a template is not well formatted. */ public List> describe() throws TemplateException{ - final Collection> templates = loaderTemplate.getTemplates(); + final Collection> templates = new HashSet<>(loaderTemplate.getTemplates()); + final List> description = new ArrayList<>(templates.size()); for(final Template template : templates) description.add(describeTemplate(template)); From c7e5d0719cb4734d438eb435010f0d8b9fcb6a45 Mon Sep 17 00:00:00 2001 From: Mauro Trevisan Date: Wed, 6 Mar 2024 12:13:17 +0100 Subject: [PATCH 06/15] fixed readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d50e7bb5b..7a1ec1eca 100644 --- a/README.md +++ b/README.md @@ -1488,7 +1488,7 @@ for(int index = 0; index < result.size(); index ++){ Exception error = response.getError(); if(error != null){ - LOGGER.error("An error occurred while parsing:\r\n {}", response.getOriginator()); + LOGGER.error("An error occurred while parsing:\r\n {}", response.getSource()); } else if(parsedMessage != null){ ... @@ -1511,7 +1511,7 @@ byte[] composedMessage = response.getMessage(); Exception error = response.getError(); if(error != null){ - LOGGER.error("An error occurred while composing:\r\n {}", response.getOriginator()); + LOGGER.error("An error occurred while composing:\r\n {}", response.getSource()); } else if(composedMessage != null){ ... From d71d7ad1b764badb9c0f9fa2a0f3f9e3c0adf11f Mon Sep 17 00:00:00 2001 From: Mauro Trevisan Date: Wed, 6 Mar 2024 12:55:32 +0100 Subject: [PATCH 07/15] Add TextStatistics Utility Class A new utility class, `TextStatistics`, was added to the project. This class can be used to compute a histogram of the bytes seen in a stream. Some supported operations include counting occurrences of specific bytes and determining if the byte stream resembles UTF-8 encoded text. --- .../boxon/helpers/TextStatistics.java | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java b/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java new file mode 100644 index 000000000..3f0f845e9 --- /dev/null +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java @@ -0,0 +1,148 @@ +package io.github.mtrevisan.boxon.helpers; + + +/** + * Utility class for computing a histogram of the bytes seen in a stream. + * + * @since Apache Tika 1.2 + * + * @see Apache Tika. + */ +public class TextStatistics{ + + private final int[] counts = new int[256]; + + private int total = 0; + + + public void addData(final byte[] buffer, final int offset, final int length){ + for(int i = 0; i < length; i ++){ + counts[buffer[offset + i] & 0xff] ++; + total ++; + } + } + + /** + * Checks whether at least one byte was seen and that the bytes that were seen were mostly plain text (i.e. < 2% control, > 90% ASCII + * range). + * + * @return Whether the seen bytes were mostly safe ASCII. + * + * @see TIKA-483 + * @see TIKA-688 + */ + public boolean isMostlyAscii(){ + final int control = count(0, 0x20); + final int ascii = count(0x20, 128); + final int safe = countSafeControl(); + return (total > 0 + && (control - safe) * 100 < total * 2 + && (ascii + safe) * 100 > total * 90); + } + + /** + * Checks whether the observed byte stream looks like UTF-8 encoded text. + * + * @return Whether the seen bytes look like UTF-8. + * + * @since Apache Tika 1.3 + */ + public boolean looksLikeUTF8(){ + final int control = count(0, 0x20); + int utf8 = count(0x20, 0x80); + final int safe = countSafeControl(); + + int expectedContinuation = 0; + final int[] leading = new int[]{count(0xC0, 0xE0), count(0xE0, 0xF0), count(0xF0, 0xF8)}; + for(int i = 0; i < leading.length; i ++){ + utf8 += leading[i]; + expectedContinuation += (i + 1) * leading[i]; + } + + final int continuation = count(0x80, 0xC0); + return (utf8 > 0 + && continuation <= expectedContinuation + && continuation >= expectedContinuation - 3 + && count(0xF8, 0x100) == 0 + && (control - safe) * 100 < utf8 * 2); + } + + /** + * Returns the total number of bytes seen so far. + * + * @return Count of all bytes. + */ + public int count(){ + return total; + } + + /** + * Returns the number of occurrences of the given byte. + * + * @param b Byte. + * @return Count of the given byte. + */ + public int count(final int b){ + return counts[b & 0xFF]; + } + + /** + * Counts control characters (i.e. < 0x20, excluding tab, CR, LF, page feed and escape). + *

+ * This definition of control characters is based on section 4 of the "Content-Type Processing Model" Internet-draft + * (draft-abarth-mime-sniff-01). + *

+	 * +-------------------------+
+	 * | Binary data byte ranges |
+	 * +-------------------------+
+	 * | 0x00 -- 0x08            |
+	 * | 0x0B                    |
+	 * | 0x0E -- 0x1A            |
+	 * | 0x1C -- 0x1F            |
+	 * +-------------------------+
+	 * 
+ * + * @return Count of control characters. + * + * @see TIKA-154 + */ + public int countControl(){ + return (count(0, 0x20) - countSafeControl()); + } + + /** + * Counts "safe" (i.e. seven-bit non-control) ASCII characters. + * + * @return Count of safe ASCII characters. + * @see #countControl() + */ + public int countSafeAscii(){ + return (count(0x20, 128) + countSafeControl()); + } + + /** + * Counts eight bit characters, i.e. bytes with their highest bit set. + * + * @return Count of eight bit characters. + */ + public int countEightBit(){ + return count(128, 256); + } + + private int count(final int from, final int to){ + assert 0 <= from && to <= counts.length; + + int count = 0; + for(int i = from; i < to; i ++) + count += counts[i]; + return count; + } + + private int countSafeControl(){ + // tab, LF, CR + return count('\t') + count('\n') + count('\r') + //new page, escape + + count(0x0c) + count(0x1b); + } + +} From a823e7ef5d8f017402d31ac15425c841addc6137 Mon Sep 17 00:00:00 2001 From: mauro <851903+mtrevisan@users.noreply.github.com> Date: Wed, 6 Mar 2024 21:27:36 +0100 Subject: [PATCH 08/15] refactor --- .../boxon/helpers/TextStatistics.java | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java b/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java index 3f0f845e9..46df3b991 100644 --- a/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java @@ -1,3 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.github.mtrevisan.boxon.helpers; @@ -8,11 +24,12 @@ * * @see Apache Tika. */ -public class TextStatistics{ +public final class TextStatistics{ private final int[] counts = new int[256]; - private int total = 0; + /** Total number of bytes seen so far. */ + private int total; public void addData(final byte[] buffer, final int offset, final int length){ @@ -53,7 +70,7 @@ public boolean looksLikeUTF8(){ final int safe = countSafeControl(); int expectedContinuation = 0; - final int[] leading = new int[]{count(0xC0, 0xE0), count(0xE0, 0xF0), count(0xF0, 0xF8)}; + final int[] leading = {count(0xC0, 0xE0), count(0xE0, 0xF0), count(0xF0, 0xF8)}; for(int i = 0; i < leading.length; i ++){ utf8 += leading[i]; expectedContinuation += (i + 1) * leading[i]; @@ -61,21 +78,11 @@ public boolean looksLikeUTF8(){ final int continuation = count(0x80, 0xC0); return (utf8 > 0 - && continuation <= expectedContinuation - && continuation >= expectedContinuation - 3 + && expectedContinuation - 3 <= continuation && continuation <= expectedContinuation && count(0xF8, 0x100) == 0 && (control - safe) * 100 < utf8 * 2); } - /** - * Returns the total number of bytes seen so far. - * - * @return Count of all bytes. - */ - public int count(){ - return total; - } - /** * Returns the number of occurrences of the given byte. * @@ -139,10 +146,10 @@ private int count(final int from, final int to){ } private int countSafeControl(){ - // tab, LF, CR + //tab, LF, CR return count('\t') + count('\n') + count('\r') //new page, escape - + count(0x0c) + count(0x1b); + + count(0x0C) + count(0x1B); } } From 8b84893ad526881cfec7499c95719ce071f8ec44 Mon Sep 17 00:00:00 2001 From: Mauro Trevisan Date: Thu, 7 Mar 2024 16:18:06 +0100 Subject: [PATCH 09/15] added conversion from pojo to map --- pom.xml | 2 +- .../boxon/helpers/ReflectionHelper.java | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1d00c8d10..65401123d 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ UTF-8 UTF-8 - 1.11 + 11 11 11 diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java b/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java index e794bd723..040d73bd7 100644 --- a/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java @@ -30,7 +30,9 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.function.BiConsumer; @@ -116,6 +118,25 @@ private static void injectValue(final Class objType, final Object obj, fi catch(final IllegalArgumentException | IllegalAccessException ignored){} } + + /** + * Maps the fields of an object to a Map, where the keys are the field names and the values are the field values. + * + * @param template The object whose fields should be mapped. + * @return A Map containing the field names as keys and the field values as values. + * @throws IllegalAccessException If there are any accessibility issues while accessing the fields. + */ + public static Map mapObject(final Object template) throws IllegalAccessException{ + final List fields = getAccessibleFields(template.getClass()); + makeFieldsAccessible(fields); + final Map map = new HashMap<>(fields.size()); + for(int i = 0; i < fields.size(); i ++){ + final Field field = fields.get(i); + map.put(field.getName(), field.get(template)); + } + return map; + } + /** * Retrieve all declared fields in the current class AND in the parent classes. * From ae5fb9699b78d36f14a656e8e4e8be34f5f589fa Mon Sep 17 00:00:00 2001 From: Mauro Trevisan Date: Thu, 7 Mar 2024 16:22:04 +0100 Subject: [PATCH 10/15] refactor --- .../java/io/github/mtrevisan/boxon/core/CoreBuilder.java | 1 + .../core/helpers/configurations/ConfigurationMessage.java | 1 + .../mtrevisan/boxon/core/helpers/templates/Template.java | 1 + .../mtrevisan/boxon/core/parsers/LoaderConfiguration.java | 4 ++++ .../mtrevisan/boxon/core/parsers/LoaderTemplate.java | 2 ++ .../mtrevisan/boxon/core/parsers/TemplateParser.java | 1 + .../github/mtrevisan/boxon/helpers/ReflectionHelper.java | 7 +++---- 7 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/github/mtrevisan/boxon/core/CoreBuilder.java b/src/main/java/io/github/mtrevisan/boxon/core/CoreBuilder.java index c1a99156a..5caa8036d 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/CoreBuilder.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/CoreBuilder.java @@ -286,6 +286,7 @@ private static void executeCommands(final List executors) thr ConfigurationException{ for(int i = 0; i < JavaHelper.lengthOrZero(executors); i ++){ final RunnableThrowable executor = executors.get(i); + executor.execute(); } } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationMessage.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationMessage.java index 0a369a01b..abf495f94 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationMessage.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationMessage.java @@ -118,6 +118,7 @@ private List loadAnnotatedFields(final Class type, final Version final List configFields = new ArrayList<>(size); for(int i = 0; i < size; i ++){ final Field field = fields.get(i); + final ConfigurationSkip[] skips = field.getDeclaredAnnotationsByType(ConfigurationSkip.class); final Annotation[] declaredAnnotations = field.getDeclaredAnnotations(); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/Template.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/Template.java index 373ed3d9a..300d076e4 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/Template.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/Template.java @@ -122,6 +122,7 @@ private Pair loadAnnotatedFields(final Class type, final Function evaluatedFields = new ArrayList<>(size); for(int i = 0; i < size; i ++){ final Field field = fields.get(i); + final Skip[] skips = field.getDeclaredAnnotationsByType(Skip.class); final Checksum checksum = field.getDeclaredAnnotation(Checksum.class); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderConfiguration.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderConfiguration.java index 1a298215f..3bfdbb389 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderConfiguration.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderConfiguration.java @@ -135,6 +135,7 @@ private Map> extractConfigurations(final List> configurations = new ConcurrentHashMap<>(size); for(int i = 0; i < size; i ++){ final Class type = annotatedClasses.get(i); + //for each extracted class, try to parse it, extracting all the information needed for the configuration of a message final ConfigurationMessage from = createConfiguration(type); if(from.canBeCoded()){ @@ -269,6 +270,7 @@ private static void fillDefaultValues(final Object configurationObject, final Li throws EncodeException, CodecException, AnnotationException{ for(int i = 0; i < fields.size(); i ++){ final ConfigField field = fields.get(i); + final Annotation annotation = field.getBinding(); final ConfigurationManagerInterface manager = ConfigurationManagerFactory.buildManager(annotation); Object dataValue = manager.getDefaultValue(field.getField(), protocol); @@ -282,6 +284,7 @@ private static Collection extractMandatoryFields(final List mandatoryFields = new HashSet<>(size); for(int i = 0; i < size; i ++){ final ConfigField field = fields.get(i); + final ConfigurationManagerInterface manager = ConfigurationManagerFactory.buildManager(field.getBinding()); final Annotation annotation = manager.annotationToBeProcessed(protocol); if(manager.isMandatory(annotation)) @@ -293,6 +296,7 @@ private static Collection extractMandatoryFields(final List fields, final String key, final Version protocol) throws EncodeException{ for(int i = 0; i < fields.size(); i ++){ final ConfigField field = fields.get(i); + final ConfigurationManagerInterface manager = ConfigurationManagerFactory.buildManager(field.getBinding()); final Annotation annotation = manager.annotationToBeProcessed(protocol); if(annotation.annotationType() != Annotation.class && manager.getShortDescription().equals(key)) diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderTemplate.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderTemplate.java index b770d0420..b8c9354af 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderTemplate.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderTemplate.java @@ -148,6 +148,7 @@ private List> extractTemplates(final List> annotatedClasses final List> templates = new ArrayList<>(size); for(int i = 0; i < size; i ++){ final Class type = annotatedClasses.get(i); + //for each extracted class, try to parse it, extracting all the information needed for the codec of a message final Template from = createTemplate(type); if(from.canBeCoded()) @@ -195,6 +196,7 @@ private void addTemplatesInner(final List> templates) throws Templat //load each template into the available templates list for(int i = 0; i < templates.size(); i ++){ final Template template = templates.get(i); + if(template != null && template.canBeCoded()) addTemplateInner(template); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/TemplateParser.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/TemplateParser.java index 4afff823a..e5b4f0ed8 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/TemplateParser.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/TemplateParser.java @@ -322,6 +322,7 @@ private void processEvaluatedFields(final Template template, final ParserCont final List evaluatedFields = template.getEvaluatedFields(); for(int i = 0; i < evaluatedFields.size(); i ++){ final EvaluatedField field = evaluatedFields.get(i); + final Evaluator evaluator = core.getEvaluator(); final boolean process = evaluator.evaluateBoolean(field.getBinding().condition(), parserContext.getRootObject()); if(!process) diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java b/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java index 040d73bd7..e88d6d6e7 100644 --- a/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java @@ -124,15 +124,14 @@ private static void injectValue(final Class objType, final Object obj, fi * * @param template The object whose fields should be mapped. * @return A Map containing the field names as keys and the field values as values. - * @throws IllegalAccessException If there are any accessibility issues while accessing the fields. */ - public static Map mapObject(final Object template) throws IllegalAccessException{ + public static Map mapObject(final Object template){ final List fields = getAccessibleFields(template.getClass()); - makeFieldsAccessible(fields); final Map map = new HashMap<>(fields.size()); for(int i = 0; i < fields.size(); i ++){ final Field field = fields.get(i); - map.put(field.getName(), field.get(template)); + + map.put(field.getName(), getValue(template, field)); } return map; } From 4a4b053fbe626bec365c50d9288b56c51c4665a7 Mon Sep 17 00:00:00 2001 From: Mauro Trevisan Date: Thu, 7 Mar 2024 17:26:16 +0100 Subject: [PATCH 11/15] fix if object is null --- .../mtrevisan/boxon/helpers/ReflectionHelper.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java b/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java index e88d6d6e7..13ac0bc6a 100644 --- a/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java @@ -122,16 +122,19 @@ private static void injectValue(final Class objType, final Object obj, fi /** * Maps the fields of an object to a Map, where the keys are the field names and the values are the field values. * - * @param template The object whose fields should be mapped. + * @param object The object whose fields should be mapped. * @return A Map containing the field names as keys and the field values as values. */ - public static Map mapObject(final Object template){ - final List fields = getAccessibleFields(template.getClass()); + public static Map mapObject(final Object object){ + if(object == null) + return null; + + final List fields = getAccessibleFields(object.getClass()); final Map map = new HashMap<>(fields.size()); for(int i = 0; i < fields.size(); i ++){ final Field field = fields.get(i); - map.put(field.getName(), getValue(template, field)); + map.put(field.getName(), getValue(object, field)); } return map; } From d4845a0bce17801fdf05a7c71630b12882952d32 Mon Sep 17 00:00:00 2001 From: mauro <851903+mtrevisan@users.noreply.github.com> Date: Thu, 7 Mar 2024 19:46:48 +0100 Subject: [PATCH 12/15] readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a1ec1eca..131a741af 100644 --- a/README.md +++ b/README.md @@ -1539,7 +1539,8 @@ Pull requests are welcomed. ### version 3.1.3 - 202403?? -- fixed duplicated descriptions +- fixed duplicated descriptions. +- added method to map a POJO into a `Map` into `ReflectionHelper`. ### version 3.1.2 - 20240302 From 22b0140dbb3405243efeb292416ff07e70f82150 Mon Sep 17 00:00:00 2001 From: Mauro Trevisan Date: Mon, 11 Mar 2024 11:54:43 +0100 Subject: [PATCH 13/15] fixes speed enhancements --- README.md | 18 +++--- .../boxon/annotations/MessageHeader.java | 4 +- .../boxon/annotations/checksummers/BSD16.java | 7 +- .../boxon/annotations/checksummers/BSD8.java | 7 +- .../annotations/checksummers/CRC16CCITT.java | 7 +- .../CompositeConfigurationField.java | 2 +- .../configurations/ConfigurationEnum.java | 3 +- .../configurations/ConfigurationHeader.java | 6 +- .../mtrevisan/boxon/core/Configurator.java | 42 +++++++++--- .../io/github/mtrevisan/boxon/core/Core.java | 2 + .../mtrevisan/boxon/core/CoreBuilder.java | 4 +- .../mtrevisan/boxon/core/Descriptor.java | 11 ++-- .../boxon/core/codecs/BindingData.java | 6 +- .../boxon/core/codecs/CodecArray.java | 8 +-- .../boxon/core/codecs/CodecHelper.java | 6 +- .../boxon/core/codecs/CodecList.java | 3 +- .../boxon/core/codecs/LoaderCodec.java | 31 +++++---- .../mtrevisan/boxon/core/helpers/ValueOf.java | 2 +- .../helpers/codecs/NumberWriterManager.java | 21 +++++- .../configurations/AlternativeManager.java | 15 +++-- .../configurations/CompositeManager.java | 17 +++-- .../ConfigurationAnnotationValidator.java | 7 +- .../configurations/ConfigurationHelper.java | 10 +-- .../configurations/ConfigurationMessage.java | 9 +-- .../helpers/configurations/PlainManager.java | 4 +- .../configurations/ValidationHelper.java | 24 +++---- .../descriptors/AnnotationDescriptor.java | 23 ++++--- .../core/helpers/extractors/JSONPath.java | 5 +- .../core/helpers/templates/Template.java | 23 ++++--- .../TemplateAnnotationValidator.java | 17 +++-- .../core/parsers/ConfigurationParser.java | 4 +- .../core/parsers/LoaderConfiguration.java | 10 +-- .../boxon/core/parsers/LoaderTemplate.java | 11 ++-- .../boxon/core/parsers/TemplateParser.java | 10 +-- .../parsers/matchers/BNDMPatternMatcher.java | 7 +- .../parsers/matchers/KRPatternMatcher.java | 5 +- .../mtrevisan/boxon/helpers/Evaluator.java | 6 +- .../boxon/helpers/GenericHelper.java | 23 ++++--- .../boxon/helpers/ReflectionHelper.java | 21 ++++-- .../mtrevisan/boxon/helpers/StringHelper.java | 28 ++++---- .../boxon/helpers/TextStatistics.java | 10 +-- .../mtrevisan/boxon/io/BitSetHelper.java | 2 +- .../github/mtrevisan/boxon/io/BitWriter.java | 2 +- .../mtrevisan/boxon/io/ParserDataType.java | 64 +++++++++++++++---- .../mtrevisan/boxon/logs/EventLogger.java | 10 +-- .../boxon/semanticversioning/Version.java | 9 +-- .../boxon/MapIterationSpeedTest.java | 55 ++++++++++++++++ .../mtrevisan/boxon/core/ComposerTest.java | 4 +- .../boxon/core/ComposerThreadedTest.java | 6 +- .../boxon/core/ConfiguratorTest.java | 16 ++--- .../boxon/core/ConfiguratorThreadedTest.java | 12 ++-- .../mtrevisan/boxon/core/DescriptorTest.java | 2 +- .../boxon/core/DescriptorThreadedTest.java | 6 +- .../mtrevisan/boxon/core/ParserTest.java | 14 ++-- .../boxon/core/ParserThreadedTest.java | 6 +- .../core/codecs/queclink/DeviceTypes.java | 37 +++++++---- .../queclink/REGConfigurationASCII.java | 4 +- .../core/parsers/TemplateParserTest.java | 6 +- .../boxon/helpers/StringHelperTest.java | 6 +- 59 files changed, 474 insertions(+), 266 deletions(-) create mode 100644 src/test/java/io/github/mtrevisan/boxon/MapIterationSpeedTest.java diff --git a/README.md b/README.md index 131a741af..23a5e086c 100644 --- a/README.md +++ b/README.md @@ -808,7 +808,7 @@ Example: ```java DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Core core = CoreBuilder.builder() .withContextPair("deviceTypes", deviceTypes) .withContextFunction(ParserTest.class.getDeclaredMethod("headerLength")) @@ -899,7 +899,7 @@ configurationData.put(Parser.CONFIGURATION_FIELD_TYPE, "AT+"); configurationData.put("Weekday", "TUESDAY|WEDNESDAY"); ... -ComposerResponse composedMessage = configurator.composeConfiguration("1.20", Collections.singletonMap("AT+", configurationData)); +Response composedMessage = configurator.composeConfiguration("1.20", "AT+", configurationData); ``` @@ -914,7 +914,7 @@ ComposerResponse composedMessage = configurator.composeConfiguration("1. - `longDescription`: a more expressive description, optional. - `minProtocol`: minimum protocol for which this configuration message is valid, optional (should follow [Semantic Versioning](https://semver.org/)). - `maxProtocol`: maximum protocol for which this configuration message is valid, optional (should follow [Semantic Versioning](https://semver.org/)). - - `start`: starting text of the message, optional. + - `start`: starting text of the message, mandatory, used as an identifier (and thus must be unique for every configuration message). - `end`: ending text of the message, optional. - `charset`: charset of the message, optional. @@ -929,7 +929,7 @@ This annotation is bounded to a class. #### example ```java -@ConfigurationHeader(start = "+", end = "-") +@ConfigurationHeader(shortDescription = "A configuration message", start = "+", end = "-") private class ConfigurationMessage{ ... } @@ -1116,7 +1116,7 @@ This annotation is bounded to a variable. shortDescription = "Download protocol", terminator = ",", enumeration = DownloadProtocol.class, value = { @AlternativeSubField(maxProtocol = "1.35", defaultValue = "HTTP"), - @AlternativeSubField(minProtocol = "1.36", defaultValue = "HTTP") + @AlternativeSubField(minProtocol = "1.36", defaultValue = "HTTPS") } ) private DownloadProtocol downloadProtocol; @@ -1518,8 +1518,6 @@ else if(composedMessage != null){ } ``` -Remember that the header that will be written is the first in `@MessageHeader`. -
@@ -1538,9 +1536,13 @@ Pull requests are welcomed. ### version 3.1.3 - 202403?? - - fixed duplicated descriptions. +- fixed validation on max value while composing a message. +- fixed number not written with the correct radix. +- made `shortDescription` mandatory in the annotation, as it should have been. - added method to map a POJO into a `Map` into `ReflectionHelper`. +- added method `Configurator.composeConfiguration` accepting a POJO. +- corrected errors in the documentation. ### version 3.1.2 - 20240302 diff --git a/src/main/java/io/github/mtrevisan/boxon/annotations/MessageHeader.java b/src/main/java/io/github/mtrevisan/boxon/annotations/MessageHeader.java index 1bbd9648d..d7584557a 100644 --- a/src/main/java/io/github/mtrevisan/boxon/annotations/MessageHeader.java +++ b/src/main/java/io/github/mtrevisan/boxon/annotations/MessageHeader.java @@ -42,7 +42,7 @@ /** * The initial bytes that determines the type of message. - *

This SHOULD be read by the template of a message.

+ *

This SHOULD be read by the parser of the template.

* * @return The header bytes of this message. */ @@ -50,7 +50,7 @@ /** * The final bytes that closes the message. - *

This SHOULD NOT be read by the template of a message.

+ *

This SHOULD NOT be read by the parser of the template.

* * @return The tail bytes of this message (defaults to empty string). */ diff --git a/src/main/java/io/github/mtrevisan/boxon/annotations/checksummers/BSD16.java b/src/main/java/io/github/mtrevisan/boxon/annotations/checksummers/BSD16.java index 1dd4ba7cc..b7e8ce57b 100644 --- a/src/main/java/io/github/mtrevisan/boxon/annotations/checksummers/BSD16.java +++ b/src/main/java/io/github/mtrevisan/boxon/annotations/checksummers/BSD16.java @@ -42,9 +42,12 @@ public final class BSD16 implements Checksummer{ @Override public short calculateChecksum(final byte[] data, final int start, final int end, final int startValue){ short value = (short)startValue; - for(int i = Math.max(start, 0); i < Math.min(end, data.length); i ++) + for(int i = Math.max(start, 0), length = Math.min(end, data.length); i < length; i ++){ + final byte datum = data[i]; + //apply circular right shift and add new value - value = (short)((value >>> 1) + ((value & 0x01) << 15) + data[i]); + value = (short)((value >>> 1) + ((value & 0x01) << 15) + datum); + } return value; } diff --git a/src/main/java/io/github/mtrevisan/boxon/annotations/checksummers/BSD8.java b/src/main/java/io/github/mtrevisan/boxon/annotations/checksummers/BSD8.java index 52a9e6004..3b87ecabe 100644 --- a/src/main/java/io/github/mtrevisan/boxon/annotations/checksummers/BSD8.java +++ b/src/main/java/io/github/mtrevisan/boxon/annotations/checksummers/BSD8.java @@ -42,9 +42,12 @@ public final class BSD8 implements Checksummer{ @Override public short calculateChecksum(final byte[] data, final int start, final int end, final int startValue){ byte value = (byte)startValue; - for(int i = Math.max(start, 0); i < Math.min(end, data.length); i ++) + for(int i = Math.max(start, 0), length = Math.min(end, data.length); i < length; i ++){ + final byte datum = data[i]; + //apply circular right shift and add new value - value = (byte)((value >>> 1) + ((value & 0x01) << 7) + data[i]); + value = (byte)((value >>> 1) + ((value & 0x01) << 7) + datum); + } return value; } diff --git a/src/main/java/io/github/mtrevisan/boxon/annotations/checksummers/CRC16CCITT.java b/src/main/java/io/github/mtrevisan/boxon/annotations/checksummers/CRC16CCITT.java index 5e38e3051..20bfe34d7 100644 --- a/src/main/java/io/github/mtrevisan/boxon/annotations/checksummers/CRC16CCITT.java +++ b/src/main/java/io/github/mtrevisan/boxon/annotations/checksummers/CRC16CCITT.java @@ -49,10 +49,11 @@ public final class CRC16CCITT implements Checksummer{ @Override public short calculateChecksum(final byte[] data, final int start, final int end, final int startValue){ short value = (short)startValue; - for(int i = Math.max(start, 0); i < Math.min(end, data.length); i ++){ + for(int i = Math.max(start, 0), length = Math.min(end, data.length); i < length; i ++){ final byte datum = data[i]; - for(int j = 0; j < Byte.SIZE; j ++){ - final boolean bit = (((datum >> (7 - j)) & 1) != 0); + + for(int j = Byte.SIZE - 1; j >= 0; j --){ + final boolean bit = (((datum >> j) & 1) != 0); final boolean c15 = ((value & 0x8000) != 0); value <<= 1; if(c15 ^ bit) diff --git a/src/main/java/io/github/mtrevisan/boxon/annotations/configurations/CompositeConfigurationField.java b/src/main/java/io/github/mtrevisan/boxon/annotations/configurations/CompositeConfigurationField.java index ece7aa92a..47c250fd2 100644 --- a/src/main/java/io/github/mtrevisan/boxon/annotations/configurations/CompositeConfigurationField.java +++ b/src/main/java/io/github/mtrevisan/boxon/annotations/configurations/CompositeConfigurationField.java @@ -54,7 +54,7 @@ * * @return A short description of the field. */ - String shortDescription() default ""; + String shortDescription(); /** * A long description of the field. diff --git a/src/main/java/io/github/mtrevisan/boxon/annotations/configurations/ConfigurationEnum.java b/src/main/java/io/github/mtrevisan/boxon/annotations/configurations/ConfigurationEnum.java index 2e1bfcc64..769c7a848 100644 --- a/src/main/java/io/github/mtrevisan/boxon/annotations/configurations/ConfigurationEnum.java +++ b/src/main/java/io/github/mtrevisan/boxon/annotations/configurations/ConfigurationEnum.java @@ -55,9 +55,8 @@ public interface ConfigurationEnum{ * @param value The value to be converted. * @return The enumeration constant that matches the value. */ - @SuppressWarnings("ReturnOfNull") static ConfigurationEnum extractEnum(final ConfigurationEnum[] enumConstants, final String value){ - for(int i = 0; i < enumConstants.length; i ++) + for(int i = 0, length = enumConstants.length; i < length; i ++) if(enumConstants[i].name().equals(value)) return enumConstants[i]; return null; diff --git a/src/main/java/io/github/mtrevisan/boxon/annotations/configurations/ConfigurationHeader.java b/src/main/java/io/github/mtrevisan/boxon/annotations/configurations/ConfigurationHeader.java index 927d953b2..97e83975c 100644 --- a/src/main/java/io/github/mtrevisan/boxon/annotations/configurations/ConfigurationHeader.java +++ b/src/main/java/io/github/mtrevisan/boxon/annotations/configurations/ConfigurationHeader.java @@ -45,7 +45,7 @@ * * @return A short description of the message. */ - String shortDescription() default ""; + String shortDescription(); /** * A long description of the message. @@ -71,7 +71,7 @@ /** * The initial bytes that determines the type of message. - *

This SHOULD be read by the protocol of a single message.

+ *

This SHOULD be written by the composer.

* * @return The header bytes of this message. */ @@ -79,7 +79,7 @@ /** * The final bytes that determines the type of message. - *

This SHOULD NOT be read by the protocol of a single message.

+ *

This SHOULD NOT be written by the composer.

* * @return The tail bytes of this message (defaults to empty string). */ diff --git a/src/main/java/io/github/mtrevisan/boxon/core/Configurator.java b/src/main/java/io/github/mtrevisan/boxon/core/Configurator.java index f9789f3d4..db0709477 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/Configurator.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/Configurator.java @@ -37,6 +37,7 @@ import io.github.mtrevisan.boxon.exceptions.EncodeException; import io.github.mtrevisan.boxon.exceptions.FieldException; import io.github.mtrevisan.boxon.helpers.Evaluator; +import io.github.mtrevisan.boxon.helpers.ReflectionHelper; import io.github.mtrevisan.boxon.helpers.StringHelper; import io.github.mtrevisan.boxon.io.BitWriter; import io.github.mtrevisan.boxon.io.BitWriterInterface; @@ -76,6 +77,7 @@ private Configurator(final Core core){ evaluator = core.getEvaluator(); } + /** * Retrieve all the configuration regardless the protocol version. * @@ -88,6 +90,7 @@ public List> getConfigurations() throws ConfigurationExcepti return extractConfigurations(configurationValues, Version.EMPTY); } + /** * Retrieve all the protocol version boundaries. * @@ -95,12 +98,17 @@ public List> getConfigurations() throws ConfigurationExcepti */ public List getProtocolVersionBoundaries(){ final List> configurationValues = configurationParser.getConfigurations(); - final List protocolVersionBoundaries = new ArrayList<>(configurationValues.size()); - for(int i = 0; i < configurationValues.size(); i ++) - protocolVersionBoundaries.addAll(configurationValues.get(i).getProtocolVersionBoundaries()); + final int length = configurationValues.size(); + final List protocolVersionBoundaries = new ArrayList<>(length); + for(int i = 0; i < length; i ++){ + final ConfigurationMessage configuration = configurationValues.get(i); + + protocolVersionBoundaries.addAll(configuration.getProtocolVersionBoundaries()); + } return Collections.unmodifiableList(protocolVersionBoundaries); } + /** * Retrieve all the configuration given a protocol version. * @@ -120,9 +128,11 @@ public List> getConfigurations(final String protocol) throws private static List> extractConfigurations(final List> configurationValues, final Version protocol) throws ConfigurationException, CodecException{ - final List> response = new ArrayList<>(configurationValues.size()); - for(int i = 0; i < configurationValues.size(); i ++){ + final int length = configurationValues.size(); + final List> response = new ArrayList<>(length); + for(int i = 0; i < length; i ++){ final ConfigurationMessage configuration = configurationValues.get(i); + final ConfigurationHeader header = configuration.getHeader(); if(!ConfigurationHelper.shouldBeExtracted(protocol, header.minProtocol(), header.maxProtocol())) continue; @@ -155,10 +165,11 @@ private static Map extractMap(final Version protocol, final Conf private static Map extractFieldsMap(final Version protocol, final ConfigurationMessage configuration) throws ConfigurationException, CodecException{ final List fields = configuration.getConfigurationFields(); - final int size = fields.size(); - final Map fieldsMap = new HashMap<>(size); - for(int i = 0; i < size; i ++){ + final int length = fields.size(); + final Map fieldsMap = new HashMap<>(length); + for(int i = 0; i < length; i ++){ final ConfigField field = fields.get(i); + final Annotation annotation = field.getBinding(); final ConfigurationManagerInterface manager = ConfigurationManagerFactory.buildManager(annotation); final Map fieldMap = manager.extractConfigurationMap(field.getFieldType(), protocol); @@ -168,6 +179,21 @@ private static Map extractFieldsMap(final Version protocol, fina return fieldsMap; } + + /** + * Compose a configuration message. + * + * @param protocolVersion The protocol version (should follow Semantic Versioning). + * @param messageStart The initial bytes of the message, see {@link ConfigurationHeader#start()}. + * @param template The template, or a POJO, containing the data to be composed. + * @return The composition response. + */ + public Response composeConfiguration(final String protocolVersion, final String messageStart, + final Object template){ + final Map data = ReflectionHelper.mapObject(template); + return composeConfiguration(protocolVersion, messageStart, data); + } + /** * Compose a configuration message. * diff --git a/src/main/java/io/github/mtrevisan/boxon/core/Core.java b/src/main/java/io/github/mtrevisan/boxon/core/Core.java index 6e7f285fd..e28be4174 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/Core.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/Core.java @@ -38,8 +38,10 @@ import io.github.mtrevisan.boxon.logs.EventListener; import java.lang.reflect.Method; +import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.Random; /** diff --git a/src/main/java/io/github/mtrevisan/boxon/core/CoreBuilder.java b/src/main/java/io/github/mtrevisan/boxon/core/CoreBuilder.java index 5caa8036d..3aabea892 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/CoreBuilder.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/CoreBuilder.java @@ -274,7 +274,7 @@ private void addMethod(final ConfigurationStep configurationStep, final Runnable */ public Core create() throws AnnotationException, TemplateException, ConfigurationException{ final ConfigurationStep[] values = ConfigurationStep.values(); - for(int i = 0; i < values.length; i ++){ + for(int i = 0, length = values.length; i < length; i ++){ final List executors = calls.get(values[i]); executeCommands(executors); } @@ -284,7 +284,7 @@ public Core create() throws AnnotationException, TemplateException, Configuratio private static void executeCommands(final List executors) throws AnnotationException, TemplateException, ConfigurationException{ - for(int i = 0; i < JavaHelper.lengthOrZero(executors); i ++){ + for(int i = 0, length = JavaHelper.lengthOrZero(executors); i < length; i ++){ final RunnableThrowable executor = executors.get(i); executor.execute(); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/Descriptor.java b/src/main/java/io/github/mtrevisan/boxon/core/Descriptor.java index 6781dbd18..91ee37d0e 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/Descriptor.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/Descriptor.java @@ -117,8 +117,9 @@ public Map describe(final Class templateClass) throws Annotat * @throws TemplateException If a template is not well formatted. */ public List> describe(final Class... templateClasses) throws AnnotationException, TemplateException{ - final List> description = new ArrayList<>(templateClasses.length); - for(int i = 0; i < templateClasses.length; i ++){ + final int length = templateClasses.length; + final List> description = new ArrayList<>(length); + for(int i = 0; i < length; i ++){ final Class templateClass = templateClasses[i]; if(templateClass.isAnnotationPresent(MessageHeader.class)){ final Template template = loaderTemplate.extractTemplate(templateClass); @@ -149,9 +150,9 @@ private static void describeHeader(final MessageHeader header, final Map fields, final Map description) throws TemplateException{ - final int size = fields.size(); - final Collection> fieldsDescription = new ArrayList<>(size); - for(int i = 0; i < size; i ++) + final int length = fields.size(); + final Collection> fieldsDescription = new ArrayList<>(length); + for(int i = 0; i < length; i ++) describeField(fields.get(i), fieldsDescription); description.put(DescriberKey.FIELDS.toString(), fieldsDescription); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/codecs/BindingData.java b/src/main/java/io/github/mtrevisan/boxon/core/codecs/BindingData.java index fa212c1fa..31aaa6475 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/codecs/BindingData.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/codecs/BindingData.java @@ -171,7 +171,7 @@ private void addPrefixToContext(final BitReaderInterface reader){ } private ObjectChoices.ObjectChoice chooseAlternative(final ObjectChoices.ObjectChoice[] alternatives){ - for(int i = 0; i < alternatives.length; i ++){ + for(int i = 0, length = alternatives.length; i < length; i ++){ final ObjectChoices.ObjectChoice alternative = alternatives[i]; if(evaluator.evaluateBoolean(alternative.condition(), rootObject)) return alternative; @@ -239,7 +239,7 @@ boolean hasSelectSeparatedAlternatives(){ } private ObjectChoicesList.ObjectChoiceList chooseAlternative(final ObjectChoicesList.ObjectChoiceList[] alternatives){ - for(int i = 0; i < alternatives.length; i ++){ + for(int i = 0, length = alternatives.length; i < length; i ++){ final ObjectChoicesList.ObjectChoiceList alternative = alternatives[i]; if(evaluator.evaluateBoolean(alternative.condition(), rootObject)) return alternative; @@ -258,7 +258,7 @@ private static boolean isEmptyChoice(final ObjectChoicesList.ObjectChoiceList ch */ Class> getChosenConverter(){ final ConverterChoices.ConverterChoice[] alternatives = selectConverterFrom.alternatives(); - for(int i = 0; i < alternatives.length; i ++){ + for(int i = 0, length = alternatives.length; i < length; i ++){ final ConverterChoices.ConverterChoice alternative = alternatives[i]; if(evaluator.evaluateBoolean(alternative.condition(), rootObject)) return alternative.converter(); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecArray.java b/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecArray.java index 7ec8f94e0..b46c26ea1 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecArray.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecArray.java @@ -79,7 +79,7 @@ private static T[] createArray(final Class type, final int leng private void decodeWithAlternatives(final BitReaderInterface reader, final Object[] array, final BindingData bindingData, final Object rootObject) throws FieldException{ - for(int i = 0; i < array.length; i ++){ + for(int i = 0, length = array.length; i < length; i ++){ final Class chosenAlternativeType = bindingData.chooseAlternativeType(reader); //read object @@ -92,7 +92,7 @@ private void decodeWithoutAlternatives(final BitReaderInterface reader, final Ob throws FieldException{ final Template template = templateParser.createTemplate(type); - for(int i = 0; i < array.length; i ++) + for(int i = 0, length = array.length; i < length; i ++) array[i] = templateParser.decode(template, reader, null); } @@ -120,7 +120,7 @@ public void encode(final BitWriterInterface writer, final Annotation annotation, private void encodeWithAlternatives(final BitWriterInterface writer, final Object[] array, final ObjectChoices selectFrom) throws FieldException{ final ObjectChoices.ObjectChoice[] alternatives = selectFrom.alternatives(); - for(int i = 0; i < array.length; i ++){ + for(int i = 0, length = array.length; i < length; i ++){ final Object elem = array[i]; final Class type = elem.getClass(); @@ -137,7 +137,7 @@ private void encodeWithAlternatives(final BitWriterInterface writer, final Objec private void encodeWithoutAlternatives(final BitWriterInterface writer, final Object[] array, final Class type) throws FieldException{ final Template template = templateParser.createTemplate(type); - for(int i = 0; i < array.length; i ++) + for(int i = 0, length = array.length; i < length; i ++) templateParser.encode(template, writer, null, array[i]); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecHelper.java b/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecHelper.java index 99e703b76..c95d6187b 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecHelper.java @@ -67,7 +67,7 @@ static void assertSizeEquals(final int expectedSize, final int size){ } static ObjectChoices.ObjectChoice chooseAlternative(final ObjectChoices.ObjectChoice[] alternatives, final Class type){ - for(int i = 0; i < alternatives.length; i ++){ + for(int i = 0, length = alternatives.length; i < length; i ++){ final ObjectChoices.ObjectChoice alternative = alternatives[i]; if(alternative.type().isAssignableFrom(type)) return alternative; @@ -92,7 +92,7 @@ static void writeHeader(final BitWriterInterface writer, final ObjectChoices.Obj static ObjectChoicesList.ObjectChoiceList chooseAlternative(final ObjectChoicesList.ObjectChoiceList[] alternatives, final Class type){ - for(int i = 0; i < alternatives.length; i ++){ + for(int i = 0, length = alternatives.length; i < length; i ++){ final ObjectChoicesList.ObjectChoiceList alternative = alternatives[i]; if(alternative.type().isAssignableFrom(type)) return alternative; @@ -154,7 +154,7 @@ else if(valueClass.isArray()) private static int calculateCompositeValue(final Object value){ int compositeEnumValue = 0; - for(int i = 0; i < Array.getLength(value); i ++) + for(int i = 0, length = Array.getLength(value); i < length; i ++) compositeEnumValue |= ((ConfigurationEnum)Array.get(value, i)).getCode(); return compositeEnumValue; } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecList.java b/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecList.java index f0b3b4669..47fde4722 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecList.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecList.java @@ -97,8 +97,9 @@ public void encode(final BitWriterInterface writer, final Annotation annotation, } private void encodeWithAlternatives(final BitWriterInterface writer, final List list) throws FieldException{ - for(int i = 0; i < list.size(); i ++){ + for(int i = 0, length = list.size(); i < length; i ++){ final Object elem = list.get(i); + final Class type = elem.getClass(); final Template template = templateParser.createTemplate(type); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/codecs/LoaderCodec.java b/src/main/java/io/github/mtrevisan/boxon/core/codecs/LoaderCodec.java index c57d13465..e00b4d541 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/codecs/LoaderCodec.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/codecs/LoaderCodec.java @@ -102,9 +102,11 @@ public void loadCodecsFrom(final Class... basePackageClasses){ } private List> extractCodecs(final List> derivedClasses){ - final List> codecs = new ArrayList<>(derivedClasses.size()); - for(int i = 0; i < derivedClasses.size(); i ++){ + final int length = derivedClasses.size(); + final List> codecs = new ArrayList<>(length); + for(int i = 0; i < length; i ++){ final Class type = derivedClasses.get(i); + //for each extracted class, try to create an instance final CodecInterface codec = (CodecInterface)ConstructorHelper.getCreator(type) .get(); @@ -144,28 +146,35 @@ public void addCodec(final CodecInterface codec){ public void addCodecs(final CodecInterface... codecs){ Objects.requireNonNull(codecs, "Codecs cannot be null"); - final Class[] codecClasses = new Class[codecs.length]; - for(int i = 0; i < codecs.length; i ++) + final int length = codecs.length; + final Class[] codecClasses = new Class[length]; + for(int i = 0; i < length; i ++) codecClasses[i] = codecs[i].getClass(); eventListener.loadingCodec(codecClasses); addCodecsInner(codecs); - eventListener.loadedCodecs(codecs.length); + eventListener.loadedCodecs(length); } private void addCodecsInner(@SuppressWarnings("BoundedWildcard") final List> codecs){ //load each codec into the available codec list - for(int i = 0; i < codecs.size(); i ++) - if(codecs.get(i) != null) - addCodecInner(codecs.get(i)); + for(int i = 0, length = codecs.size(); i < length; i ++){ + final CodecInterface codec = codecs.get(i); + + if(codec != null) + addCodecInner(codec); + } } private void addCodecsInner(final CodecInterface... codecs){ //load each codec into the available codec list - for(int i = 0; i < codecs.length; i ++) - if(codecs[i] != null) - addCodecInner(codecs[i]); + for(int i = 0, length = codecs.length; i < length; i ++){ + final CodecInterface codec = codecs[i]; + + if(codec != null) + addCodecInner(codec); + } } private void addCodecInner(final CodecInterface codec){ diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/ValueOf.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/ValueOf.java index 2378caf79..f9d409958 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/ValueOf.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/ValueOf.java @@ -81,7 +81,7 @@ private ValueOf(final Class type, final Function fieldAccessor, final C final T[] enumConstants = type.getEnumConstants(); final Map map = createMap(comparator, enumConstants); - for(int i = 0; i < enumConstants.length; i ++){ + for(int i = 0, length = enumConstants.length; i < length; i ++){ final K key = fieldAccessor.apply(enumConstants[i]); if(map.put(key, enumConstants[i]) != null) throw new IllegalStateException("Duplicate key in enum " + type.getSimpleName() + ": " + key); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/codecs/NumberWriterManager.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/codecs/NumberWriterManager.java index 4efd9caa7..df538e1d3 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/codecs/NumberWriterManager.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/codecs/NumberWriterManager.java @@ -24,8 +24,12 @@ */ package io.github.mtrevisan.boxon.core.helpers.codecs; +import io.github.mtrevisan.boxon.helpers.StringHelper; import io.github.mtrevisan.boxon.io.BitWriterInterface; +import java.math.BigDecimal; +import java.math.BigInteger; + final class NumberWriterManager implements WriterManagerInterface{ @@ -47,8 +51,21 @@ NumberWriterManager withRadix(final int radix){ @Override public void put(final Object value){ - final String val = Long.toString(((Number)value).longValue(), radix); - writer.putText(val); + if(value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long){ + final String text = String.valueOf(value); + if(radix == 10) + writer.putText(text); + else{ + final BigInteger bi = new BigInteger(text); + writer.putText(radix == 16 + ? StringHelper.toHexString(bi.toByteArray()) + : bi.toString(radix)); + } + } + else if(value instanceof BigDecimal) + writer.putText(((BigDecimal)value).toPlainString()); + else if(value instanceof BigInteger) + writer.putText(((BigInteger)value).toString(radix)); } } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/AlternativeManager.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/AlternativeManager.java index 50ac7312f..c0543db2c 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/AlternativeManager.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/AlternativeManager.java @@ -80,7 +80,7 @@ public void addProtocolVersionBoundaries(final Collection protocolVersio protocolVersionBoundaries.add(annotation.maxProtocol()); final AlternativeSubField[] alternativeFields = annotation.value(); - for(int i = 0; i < alternativeFields.length; i ++){ + for(int i = 0, length = alternativeFields.length; i < length; i ++){ final AlternativeSubField fieldBinding = alternativeFields[i]; protocolVersionBoundaries.add(fieldBinding.minProtocol()); protocolVersionBoundaries.add(fieldBinding.maxProtocol()); @@ -98,7 +98,7 @@ public Annotation annotationToBeProcessed(final Version protocol){ private Annotation findAlternative(final Version protocol){ Annotation match = null; final AlternativeSubField[] alternativeFields = annotation.value(); - for(int j = 0; match == null && j < alternativeFields.length; j ++){ + for(int j = 0, length = alternativeFields.length; match == null && j < length; j ++){ final AlternativeSubField fieldBinding = alternativeFields[j]; if(ConfigurationHelper.shouldBeExtracted(protocol, fieldBinding.minProtocol(), fieldBinding.maxProtocol())) match = fieldBinding; @@ -136,8 +136,9 @@ public Map extractConfigurationMap(final Class fieldType, fin private Map extractConfigurationMapWithoutProtocol(final Class fieldType, final Map alternativeMap) throws ConfigurationException, CodecException{ final AlternativeSubField[] alternativeFields = annotation.value(); - final Collection> alternatives = new ArrayList<>(alternativeFields.length); - for(int j = 0; j < alternativeFields.length; j ++){ + final int length = alternativeFields.length; + final Collection> alternatives = new ArrayList<>(length); + for(int j = 0; j < length; j ++){ final AlternativeSubField alternativeField = alternativeFields[j]; final Map fieldMap = extractMap(alternativeField, fieldType); @@ -202,8 +203,8 @@ private static Map extractMap(final AlternativeSubField binding, if(!fieldType.isEnum() && !fieldType.isArray()) ConfigurationHelper.putIfNotEmpty(ConfigurationKey.FIELD_TYPE, ParserDataType.toPrimitiveTypeOrSelf(fieldType).getSimpleName(), map); - ConfigurationHelper.putIfNotEmpty(ConfigurationKey.MIN_VALUE, ParserDataType.getValue(fieldType, binding.minValue()), map); - ConfigurationHelper.putIfNotEmpty(ConfigurationKey.MAX_VALUE, ParserDataType.getValue(fieldType, binding.maxValue()), map); + ConfigurationHelper.putIfNotEmpty(ConfigurationKey.MIN_VALUE, ParserDataType.getBigNumber(binding.minValue()), map); + ConfigurationHelper.putIfNotEmpty(ConfigurationKey.MAX_VALUE, ParserDataType.getBigNumber(binding.maxValue()), map); ConfigurationHelper.putIfNotEmpty(ConfigurationKey.PATTERN, binding.pattern(), map); if(String.class.isAssignableFrom(fieldType)) @@ -214,7 +215,7 @@ private static Map extractMap(final AlternativeSubField binding, private AlternativeSubField extractField(final Version protocol){ final AlternativeSubField[] alternativeFields = annotation.value(); - for(int i = 0; i < alternativeFields.length; i ++){ + for(int i = 0, length = alternativeFields.length; i < length; i ++){ final AlternativeSubField fieldBinding = alternativeFields[i]; if(ConfigurationHelper.shouldBeExtracted(protocol, fieldBinding.minProtocol(), fieldBinding.maxProtocol())) return fieldBinding; diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/CompositeManager.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/CompositeManager.java index 96f8ae1a6..f677dfe2d 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/CompositeManager.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/CompositeManager.java @@ -85,8 +85,9 @@ public Object getDefaultValue(final Field field, final Version protocol) throws //compose field value final String composition = annotation.composition(); final CompositeSubField[] fields = annotation.value(); - final Map dataValue = new HashMap<>(fields.length); - for(int i = 0; i < fields.length; i ++) + final int length = fields.length; + final Map dataValue = new HashMap<>(length); + for(int i = 0; i < length; i ++) dataValue.put(fields[i].shortDescription(), fields[i].defaultValue()); return replace(composition, dataValue, fields); } @@ -108,7 +109,7 @@ public Annotation annotationToBeProcessed(final Version protocol){ public boolean isMandatory(final Annotation annotation){ boolean mandatory = false; final CompositeSubField[] compositeFields = this.annotation.value(); - for(int j = 0; !mandatory && j < compositeFields.length; j ++) + for(int j = 0, length = compositeFields.length; !mandatory && j < length; j ++) mandatory = StringHelper.isBlank(compositeFields[j].defaultValue()); return mandatory; } @@ -121,8 +122,9 @@ public Map extractConfigurationMap(final Class fieldType, fin final Map compositeMap = extractMap(); final CompositeSubField[] bindings = annotation.value(); - final Map compositeFieldsMap = new HashMap<>(bindings.length); - for(int j = 0; j < bindings.length; j ++){ + final int length = bindings.length; + final Map compositeFieldsMap = new HashMap<>(length); + for(int j = 0; j < length; j ++){ final Map fieldMap = extractMap(bindings[j], fieldType); compositeFieldsMap.put(bindings[j].shortDescription(), fieldMap); @@ -196,8 +198,9 @@ public Object convertValue(final Field field, final String dataKey, Object dataV private static String replace(final String text, final Map replacements, final CompositeSubField[] fields) throws EncodeException{ - final Map trueReplacements = new HashMap<>(fields.length); - for(int i = 0; i < fields.length; i ++){ + final int length = fields.length; + final Map trueReplacements = new HashMap<>(length); + for(int i = 0; i < length; i ++){ final String key = fields[i].shortDescription(); trueReplacements.put(key, replacements.get(key)); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationAnnotationValidator.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationAnnotationValidator.java index 8110e4ec1..cce0bfcc1 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationAnnotationValidator.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationAnnotationValidator.java @@ -132,7 +132,8 @@ void validate(final Field field, final Annotation annotation, final Version minP throw AnnotationException.create("Composite fields must have a string variable to be bounded to"); final CompositeSubField[] fields = binding.value(); - if(fields.length == 0) + final int length = fields.length; + if(length == 0) throw AnnotationException.create("Composite fields must have at least one sub-field"); validateCharset(configData.getCharset()); @@ -141,7 +142,7 @@ void validate(final Field field, final Annotation annotation, final Version minP ValidationHelper.validateProtocol(configData, minProtocolVersion, maxProtocolVersion); - for(int i = 0; i < fields.length; i ++) + for(int i = 0; i < length; i ++) SUB_FIELD.validate(field, fields[i], minProtocolVersion, maxProtocolVersion); } }, @@ -183,7 +184,7 @@ void validate(final Field field, final Annotation annotation, final Version minP ValidationHelper.validateProtocol(configData, minProtocolVersion, maxProtocolVersion); final AlternativeSubField[] alternatives = binding.value(); - for(int i = 0; i < JavaHelper.lengthOrZero(alternatives); i ++){ + for(int i = 0, length = JavaHelper.lengthOrZero(alternatives); i < length; i ++){ final ConfigFieldData alternativeConfigData = ConfigFieldDataBuilder.create(field, alternatives[i]); ValidationHelper.validateProtocol(alternativeConfigData, minProtocolVersion, maxProtocolVersion); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationHelper.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationHelper.java index 743c02d9d..32de69c47 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationHelper.java @@ -87,8 +87,9 @@ static Object extractEnumerationValue(final Class fieldType, final String val private static T[] extractEnumerationArrayValue(final CharSequence value, final Class enumeration){ final ConfigurationEnum[] enumConstants = enumeration.getEnumConstants(); final String[] defaultValues = splitMultipleEnumerations(value); - final T[] valEnum = (T[])Array.newInstance(enumeration, defaultValues.length); - for(int i = 0; i < defaultValues.length; i ++) + final int length = defaultValues.length; + final T[] valEnum = (T[])Array.newInstance(enumeration, length); + for(int i = 0; i < length; i ++) valEnum[i] = (T)ConfigurationEnum.extractEnum(enumConstants, defaultValues[i]); return valEnum; } @@ -128,8 +129,9 @@ static void extractEnumeration(final Class fieldType, final Class map) throws ConfigurationException{ if(enumeration != NullEnum.class){ final ConfigurationEnum[] enumConstants = enumeration.getEnumConstants(); - final String[] enumValues = new String[enumConstants.length]; - for(int j = 0; j < enumConstants.length; j ++) + final int length = enumConstants.length; + final String[] enumValues = new String[length]; + for(int j = 0; j < length; j ++) enumValues[j] = enumConstants[j].name(); putIfNotEmpty(ConfigurationKey.ENUMERATION, enumValues, map); if(fieldType.isEnum()) diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationMessage.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationMessage.java index abf495f94..8e71d54b8 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationMessage.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationMessage.java @@ -151,7 +151,7 @@ private static Annotation validateField(final Field field, final Annotation[] an final Version maxProtocolVersion) throws AnnotationException, CodecException{ /** filter out {@link ConfigurationSkip} annotations */ Annotation foundAnnotation = null; - for(int i = 0; foundAnnotation == null && i < annotations.length; i ++){ + for(int i = 0, length = annotations.length; foundAnnotation == null && i < length; i ++){ final Class annotationType = annotations[i].annotationType(); if(ConfigurationSkip.class.isAssignableFrom(annotationType) || ConfigurationSkip.ConfigurationSkips.class.isAssignableFrom(annotationType)) @@ -171,11 +171,12 @@ private static void validateAnnotation(final Field field, final Annotation annot } private List extractProtocolVersionBoundaries(final List configFields){ - final List boundaries = new ArrayList<>(configFields.size() * 2 + 2); + final int length = configFields.size(); + final List boundaries = new ArrayList<>(length * 2 + 2); boundaries.add(header.minProtocol()); boundaries.add(header.maxProtocol()); - for(int i = 0; i < configFields.size(); i ++){ + for(int i = 0; i < length; i ++){ final ConfigField configField = configFields.get(i); final Annotation annotation = configField.getBinding(); @@ -193,7 +194,7 @@ private List extractProtocolVersionBoundaries(final List co } private static void extractProtocolVersionBoundaries(final ConfigurationSkip[] skips, final Collection boundaries){ - for(int j = 0; j < skips.length; j ++){ + for(int j = 0, length = skips.length; j < length; j ++){ boundaries.add(skips[j].minProtocol()); boundaries.add(skips[j].maxProtocol()); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/PlainManager.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/PlainManager.java index 622a9ad92..8e1533d40 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/PlainManager.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/PlainManager.java @@ -109,8 +109,8 @@ private Map extractMap(final Class fieldType) throws Configur if(!fieldType.isEnum() && !fieldType.isArray()) ConfigurationHelper.putIfNotEmpty(ConfigurationKey.FIELD_TYPE, ParserDataType.toPrimitiveTypeOrSelf(fieldType).getSimpleName(), map); - ConfigurationHelper.putIfNotEmpty(ConfigurationKey.MIN_VALUE, ParserDataType.getValue(fieldType, annotation.minValue()), map); - ConfigurationHelper.putIfNotEmpty(ConfigurationKey.MAX_VALUE, ParserDataType.getValue(fieldType, annotation.maxValue()), map); + ConfigurationHelper.putIfNotEmpty(ConfigurationKey.MIN_VALUE, ParserDataType.getBigNumber(annotation.minValue()), map); + ConfigurationHelper.putIfNotEmpty(ConfigurationKey.MAX_VALUE, ParserDataType.getBigNumber(annotation.maxValue()), map); ConfigurationHelper.putIfNotEmpty(ConfigurationKey.PATTERN, annotation.pattern(), map); ConfigurationHelper.extractEnumeration(fieldType, annotation.enumeration(), map); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ValidationHelper.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ValidationHelper.java index f4421ea65..43b11189a 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ValidationHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ValidationHelper.java @@ -113,10 +113,10 @@ static void validateMinMaxValues(final ConfigFieldData field, final Object dataV final String defaultValue = field.getDefaultValue(); final Object def = ParserDataType.getValue(fieldType, defaultValue); - final Object min = validateMinValue(field, def); - final Object max = validateMaxValue(field, def); + final Number min = validateMinValue(field, def); + final Number max = validateMaxValue(field, def); - if(min != null && max != null && ((Number)min).doubleValue() > ((Number)max).doubleValue()) + if(min != null && max != null && min.doubleValue() > max.doubleValue()) //maxValue after or equal to minValue throw AnnotationException.create("Minimum value should be less than or equal to maximum value in {}; expected {} <= {}", field.getAnnotationName(), field.getMinValue(), field.getMaxValue()); @@ -129,17 +129,17 @@ static void validateMinMaxValues(final ConfigFieldData field, final Object dataV } } - private static Object validateMinValue(final ConfigFieldData field, final Object def) throws AnnotationException, CodecException{ - Object min = null; + private static Number validateMinValue(final ConfigFieldData field, final Object def) throws AnnotationException, CodecException{ + Number min = null; final String minValue = field.getMinValue(); if(!StringHelper.isBlank(minValue)){ - min = ParserDataType.getValue(field.getFieldType(), minValue); + min = ParserDataType.getBigNumber(minValue); //minValue compatible with variable type if(min == null) throw AnnotationException.create("Incompatible minimum value in {}; found {}, expected {}", field.getAnnotationName(), minValue.getClass().getSimpleName(), field.getFieldType().toString()); - if(def != null && ((Number)def).doubleValue() < ((Number)min).doubleValue()) + if(def != null && ((Number)def).doubleValue() < min.doubleValue()) //defaultValue compatible with minValue throw AnnotationException.create("Default value incompatible with minimum value in {}; expected {} >= {}", field.getAnnotationName(), field.getDefaultValue(), minValue.getClass().getSimpleName()); @@ -147,17 +147,17 @@ private static Object validateMinValue(final ConfigFieldData field, final Object return min; } - private static Object validateMaxValue(final ConfigFieldData field, final Object def) throws AnnotationException, CodecException{ - Object max = null; + private static Number validateMaxValue(final ConfigFieldData field, final Object def) throws AnnotationException, CodecException{ + Number max = null; final String maxValue = field.getMaxValue(); if(!StringHelper.isBlank(maxValue)){ - max = ParserDataType.getValue(field.getFieldType(), maxValue); + max = ParserDataType.getBigNumber(maxValue); //maxValue compatible with variable type if(max == null) throw AnnotationException.create("Incompatible maximum value in {}; found {}, expected {}", field.getAnnotationName(), maxValue.getClass().getSimpleName(), field.getFieldType().toString()); - if(def != null && ((Number)def).doubleValue() > ((Number)max).doubleValue()) + if(def != null && ((Number)def).doubleValue() > max.doubleValue()) //defaultValue compatible with maxValue throw AnnotationException.create("Default value incompatible with maximum value in {}; expected {} <= {}", field.getAnnotationName(), field.getDefaultValue(), maxValue.getClass().getSimpleName()); @@ -285,7 +285,7 @@ private static void validateEnumMultipleValues(final ConfigFieldData field, fina throw AnnotationException.create("Default value for mutually exclusive enumeration field in {} should be a value; found {}, expected one of {}", field.getAnnotationName(), defaultValue, Arrays.toString(enumConstants)); - for(int i = 0; i < JavaHelper.lengthOrZero(defaultValues); i ++){ + for(int i = 0, length = JavaHelper.lengthOrZero(defaultValues); i < length; i ++){ final ConfigurationEnum enumValue = ConfigurationEnum.extractEnum(enumConstants, defaultValues[i]); if(enumValue == null) throw AnnotationException.create("Default value not compatible with `enumeration` in {}; found {}, expected one of {}", diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/descriptors/AnnotationDescriptor.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/descriptors/AnnotationDescriptor.java index 42366d78b..411ab43dc 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/descriptors/AnnotationDescriptor.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/descriptors/AnnotationDescriptor.java @@ -354,7 +354,7 @@ public static AnnotationDescriptor fromAnnotation(final Annotation annotation){ * @param rootDescription The map in which to load the descriptions. */ public static void describeSkips(final Skip[] skips, final Collection> rootDescription){ - for(int j = 0; j < skips.length; j ++){ + for(int j = 0, length = skips.length; j < length; j ++){ final Skip skip = skips[j]; final Map skipDescription = new HashMap<>(5); putIfNotEmpty(DescriberKey.ANNOTATION_TYPE, Skip.class, skipDescription); @@ -374,9 +374,10 @@ private static void describeChoices(final ObjectChoices choices, final Map rootDescription){ - if(alternatives.length > 0){ - final Collection> alternativesDescription = new ArrayList<>(alternatives.length); - for(int j = 0; j < alternatives.length; j ++){ + final int length = alternatives.length; + if(length > 0){ + final Collection> alternativesDescription = new ArrayList<>(length); + for(int j = 0; j < length; j ++){ final ObjectChoices.ObjectChoice alternative = alternatives[j]; describeObjectChoicesAlternatives(alternative.condition(), alternative.prefix(), alternative.type(), alternativesDescription); } @@ -392,9 +393,10 @@ private static void describeChoices(final ObjectChoicesList choices, final Map rootDescription){ - if(alternatives.length > 0){ - final Collection> alternativesDescription = new ArrayList<>(alternatives.length); - for(int j = 0; j < alternatives.length; j ++){ + final int length = alternatives.length; + if(length > 0){ + final Collection> alternativesDescription = new ArrayList<>(length); + for(int j = 0; j < length; j ++){ final ObjectChoicesList.ObjectChoiceList alternative = alternatives[j]; describeObjectChoicesAlternatives(alternative.condition(), alternative.prefix(), alternative.type(), alternativesDescription); } @@ -423,9 +425,10 @@ private static void describeConverter(final Class> con private static void describeAlternatives(final ConverterChoices.ConverterChoice[] alternatives, final Map rootDescription){ - if(alternatives.length > 0){ - final Collection> alternativesDescription = new ArrayList<>(alternatives.length); - for(int j = 0; j < alternatives.length; j ++){ + final int length = alternatives.length; + if(length > 0){ + final Collection> alternativesDescription = new ArrayList<>(length); + for(int j = 0; j < length; j ++){ final ConverterChoices.ConverterChoice alternative = alternatives[j]; final Map alternativeDescription = new HashMap<>(2); putIfNotEmpty(DescriberKey.BIND_CONDITION, alternative.condition(), alternativeDescription); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/extractors/JSONPath.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/extractors/JSONPath.java index a5957ee42..37c97aa2c 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/extractors/JSONPath.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/extractors/JSONPath.java @@ -86,7 +86,7 @@ private static String[] parsePath(final String path) throws JSONPathException{ throw JSONPathException.create("invalid path '{}'", path); final String[] components = StringHelper.split(path, DECODED_SLASH); - for(int i = 0; i < components.length; i ++) + for(int i = 0, length = components.length; i < length; i ++) if(!StringHelper.isBlank(components[i])){ //NOTE: the order here is important! components[i] = replace(components[i], TILDE_ONE, DECODED_SLASH); @@ -153,7 +153,7 @@ private static String replace(final String text, final String searchString, fina @SuppressWarnings("unchecked") private static T extract(final String[] path, Object data) throws JSONPathException, NoSuchFieldException{ - for(int i = 0; i < path.length; i ++){ + for(int i = 0, length = path.length; i < length; i ++){ final String currentPath = path[i]; final Integer idx = extractIndex(currentPath); @@ -168,7 +168,6 @@ private static T extract(final String[] path, Object data) throws JSONPathEx return (T)data; } - @SuppressWarnings("ReturnOfNull") private static Integer extractIndex(final String currentPath){ return (ParserDataType.isDecimalNumber(currentPath) && (currentPath.charAt(0) != '0' || currentPath.length() == 1) ? Integer.valueOf(currentPath) diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/Template.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/Template.java index 300d076e4..58676f720 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/Template.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/Template.java @@ -117,10 +117,10 @@ private Template(final Class type, final Function type, final Function> filterAnnotationsWithCodec) throws AnnotationException{ final List fields = ReflectionHelper.getAccessibleFields(type); - final int size = fields.size(); - final List boundedFields = new ArrayList<>(size); - final List evaluatedFields = new ArrayList<>(size); - for(int i = 0; i < size; i ++){ + final int length = fields.size(); + final List boundedFields = new ArrayList<>(length); + final List evaluatedFields = new ArrayList<>(length); + for(int i = 0; i < length; i ++){ final Field field = fields.get(i); final Skip[] skips = field.getDeclaredAnnotationsByType(Skip.class); @@ -160,8 +160,9 @@ private void loadChecksumField(final Checksum checksum, final Class type, fin @SuppressWarnings("ObjectAllocationInLoop") private static List extractEvaluations(final Annotation[] declaredAnnotations, final Field field){ - final List evaluations = new ArrayList<>(declaredAnnotations.length); - for(int i = 0; i < declaredAnnotations.length; i ++){ + final int length = declaredAnnotations.length; + final List evaluations = new ArrayList<>(length); + for(int i = 0; i < length; i ++){ final Annotation annotation = declaredAnnotations[i]; if(annotation.annotationType() == Evaluate.class) evaluations.add(EvaluatedField.create(field, (Evaluate)annotation)); @@ -172,14 +173,16 @@ private static List extractEvaluations(final Annotation[] declar private static Annotation validateField(final Field field, final List annotations) throws AnnotationException{ /** filter out {@link Skip} annotations and return the (first) valid binding annotation */ Annotation foundAnnotation = null; - for(int i = 0; foundAnnotation == null && i < annotations.size(); i ++){ - final Class annotationType = annotations.get(i).annotationType(); + for(int i = 0, length = annotations.size(); foundAnnotation == null && i < length; i ++){ + final Annotation annotation = annotations.get(i); + + final Class annotationType = annotation.annotationType(); if(annotationType == Skip.class || annotationType == Skip.Skips.class) continue; - validateAnnotation(field, annotations.get(i)); + validateAnnotation(field, annotation); - foundAnnotation = annotations.get(i); + foundAnnotation = annotation; } return foundAnnotation; } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/TemplateAnnotationValidator.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/TemplateAnnotationValidator.java index 8f8f72557..fe2aea1a3 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/TemplateAnnotationValidator.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/TemplateAnnotationValidator.java @@ -254,9 +254,11 @@ private static void validatePrefixLength(final int prefixSize) throws Annotation private static void validateObjectAlternatives(final Field field, final Class> converter, final ObjectChoices.ObjectChoice[] alternatives, final Class type, final int prefixLength) throws AnnotationException{ final boolean hasPrefix = (prefixLength > 0); - if(hasPrefix && alternatives.length == 0) + final int length = alternatives.length; + if(hasPrefix && length == 0) throw AnnotationException.create("No alternatives present"); - for(int i = 0; i < alternatives.length; i ++){ + + for(int i = 0; i < length; i ++){ final ObjectChoices.ObjectChoice alternative = alternatives[i]; validateAlternative(alternative.type(), alternative.condition(), type, hasPrefix); @@ -268,11 +270,12 @@ private static void validateObjectAlternatives(final Field field, final Class> converter, final ObjectChoicesList selectFrom, final Class type) throws AnnotationException{ final ObjectChoicesList.ObjectChoiceList[] alternatives = selectFrom.alternatives(); - if(alternatives.length == 0) + final int length = alternatives.length; + if(length == 0) throw AnnotationException.create("All alternatives must be non-empty"); int minHeaderLength = Integer.MAX_VALUE; - for(int i = 0; i < alternatives.length; i ++){ + for(int i = 0; i < length; i ++){ final int headerLength = alternatives[i].prefix().length(); if(headerLength < minHeaderLength) minHeaderLength = headerLength; @@ -287,9 +290,11 @@ private static void validateObjectListAlternatives(final Field field, final Clas final ObjectChoicesList.ObjectChoiceList[] alternatives, final Class type, final int prefixLength) throws AnnotationException{ final boolean hasPrefix = (prefixLength > 0); - if(hasPrefix && alternatives.length == 0) + final int length = alternatives.length; + if(hasPrefix && length == 0) throw AnnotationException.create("No alternatives present"); - for(int i = 0; i < alternatives.length; i ++){ + + for(int i = 0; i < length; i ++){ final ObjectChoicesList.ObjectChoiceList alternative = alternatives[i]; validateAlternative(alternative.type(), alternative.condition(), type, hasPrefix); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/ConfigurationParser.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/ConfigurationParser.java index f9bb9e490..96911b7c0 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/ConfigurationParser.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/ConfigurationParser.java @@ -171,7 +171,7 @@ public void encode(final ConfigurationMessage configuration, final BitWri //encode message fields: final List fields = configuration.getConfigurationFields(); - for(int i = 0; i < fields.size(); i ++){ + for(int i = 0, length = fields.size(); i < length; i ++){ final ConfigField field = fields.get(i); final ConfigurationManagerInterface manager = ConfigurationManagerFactory.buildManager(field.getBinding()); @@ -200,7 +200,7 @@ public void encode(final ConfigurationMessage configuration, final BitWri } private static void writeSkips(final ConfigurationSkip[] skips, final BitWriterInterface writer, final Version protocol){ - for(int i = 0; i < skips.length; i ++) + for(int i = 0, length = skips.length; i < length; i ++) writeSkip(skips[i], writer, protocol); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderConfiguration.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderConfiguration.java index 3bfdbb389..1ed97cdd3 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderConfiguration.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderConfiguration.java @@ -268,7 +268,7 @@ ConfigurationMessage getConfiguration(final String configurationType) throws private static void fillDefaultValues(final Object configurationObject, final List fields, final Version protocol) throws EncodeException, CodecException, AnnotationException{ - for(int i = 0; i < fields.size(); i ++){ + for(int i = 0, length = fields.size(); i < length; i ++){ final ConfigField field = fields.get(i); final Annotation annotation = field.getBinding(); @@ -280,9 +280,9 @@ private static void fillDefaultValues(final Object configurationObject, final Li } private static Collection extractMandatoryFields(final List fields, final Version protocol){ - final int size = fields.size(); - final Collection mandatoryFields = new HashSet<>(size); - for(int i = 0; i < size; i ++){ + final int length = fields.size(); + final Collection mandatoryFields = new HashSet<>(length); + for(int i = 0; i < length; i ++){ final ConfigField field = fields.get(i); final ConfigurationManagerInterface manager = ConfigurationManagerFactory.buildManager(field.getBinding()); @@ -294,7 +294,7 @@ private static Collection extractMandatoryFields(final List fields, final String key, final Version protocol) throws EncodeException{ - for(int i = 0; i < fields.size(); i ++){ + for(int i = 0, length = fields.size(); i < length; i ++){ final ConfigField field = fields.get(i); final ConfigurationManagerInterface manager = ConfigurationManagerFactory.buildManager(field.getBinding()); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderTemplate.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderTemplate.java index b8c9354af..e919faecb 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderTemplate.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderTemplate.java @@ -194,7 +194,7 @@ Template createTemplate(final Class type) throws AnnotationException{ private void addTemplatesInner(final List> templates) throws TemplateException{ //load each template into the available templates list - for(int i = 0; i < templates.size(); i ++){ + for(int i = 0, length = templates.size(); i < length; i ++){ final Template template = templates.get(i); if(template != null && template.canBeCoded()) @@ -213,7 +213,7 @@ private void addTemplateInner(final Template template) throws TemplateExcepti final MessageHeader header = template.getHeader(); final Charset charset = CharsetHelper.lookup(header.charset()); final String[] starts = header.start(); - for(int i = 0; i < starts.length; i ++) + for(int i = 0, length = starts.length; i < length; i ++) loadTemplateInner(template, starts[i], charset); } catch(final TemplateException e){ @@ -292,8 +292,9 @@ private static String calculateKey(final String headerStart, final Charset chars } private List filterAnnotationsWithCodec(final Annotation[] declaredAnnotations){ - final List annotations = new ArrayList<>(declaredAnnotations.length); - for(int i = 0; i < declaredAnnotations.length; i ++) + final int length = declaredAnnotations.length; + final List annotations = new ArrayList<>(length); + for(int i = 0; i < length; i ++) if(loaderCodec.hasCodec(declaredAnnotations[i].annotationType())) annotations.add(declaredAnnotations[i]); return annotations; @@ -319,7 +320,7 @@ private static int findNextMessageIndex(final BitReaderInterface reader, final M final Charset charset = CharsetHelper.lookup(header.charset()); final String[] messageStarts = header.start(); //select the minimum index with a valid template - for(int i = 0; i < messageStarts.length; i ++){ + for(int i = 0, length = messageStarts.length; i < length; i ++){ final int offset = searchNextSequence(reader, messageStarts[i].getBytes(charset)); if(offset >= 0 && (minOffset < 0 || offset < minOffset)) minOffset = offset; diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/TemplateParser.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/TemplateParser.java index e5b4f0ed8..2f093de71 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/TemplateParser.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/TemplateParser.java @@ -194,7 +194,7 @@ public T decode(final Template template, final BitReaderInterface reader, //decode message fields: final List fields = template.getBoundedFields(); - for(int i = 0; i < fields.size(); i ++){ + for(int i = 0, length = fields.size(); i < length; i ++){ final BoundedField field = fields.get(i); //process skip annotations: @@ -249,7 +249,7 @@ private void decodeField(final Template template, final BitReaderInterfac } private void readSkips(final Skip[] skips, final BitReaderInterface reader, final ParserContext parserContext){ - for(int i = 0; i < skips.length; i ++) + for(int i = 0, length = skips.length; i < length; i ++) readSkip(skips[i], reader, parserContext.getRootObject()); } @@ -320,7 +320,7 @@ private static short calculateChecksum(final int startPosition, final BitReaderI private void processEvaluatedFields(final Template template, final ParserContext parserContext){ final List evaluatedFields = template.getEvaluatedFields(); - for(int i = 0; i < evaluatedFields.size(); i ++){ + for(int i = 0, length = evaluatedFields.size(); i < length; i ++){ final EvaluatedField field = evaluatedFields.get(i); final Evaluator evaluator = core.getEvaluator(); @@ -347,7 +347,7 @@ public void encode(final Template template, final BitWriterInterface writ //encode message fields: final LoaderCodecInterface loaderCodec = core.getLoaderCodec(); final List fields = template.getBoundedFields(); - for(int i = 0; i < fields.size(); i ++){ + for(int i = 0, length = fields.size(); i < length; i ++){ final BoundedField field = fields.get(i); //process skip annotations: @@ -374,7 +374,7 @@ private boolean shouldProcessField(final String condition, final Object rootObje } private void writeSkips(final Skip[] skips, final BitWriterInterface writer, final ParserContext parserContext){ - for(int i = 0; i < skips.length; i ++) + for(int i = 0, length = skips.length; i < length; i ++) writeSkip(skips[i], writer, parserContext.getRootObject()); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/BNDMPatternMatcher.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/BNDMPatternMatcher.java index 0ca8808d8..684ba7aae 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/BNDMPatternMatcher.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/BNDMPatternMatcher.java @@ -75,12 +75,13 @@ private BNDMPatternMatcher(){} * @return an array of pre-processed pattern. */ public static int[] preProcessPatternWithWildcard(final byte[] pattern, final byte wildcard){ - assertLength(pattern.length); + final int length = pattern.length; + assertLength(length); int j = 0; - for(int i = 0; i < pattern.length; i ++) + for(int i = 0; i < length; i ++) if(pattern[i] == wildcard) - j |= 1 << (pattern.length - i - 1); + j |= 1 << (length - i - 1); final int[] preprocessedPattern = new int[Integer.SIZE << 3]; if(j != 0) diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/KRPatternMatcher.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/KRPatternMatcher.java index 38457c213..7a34a606b 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/KRPatternMatcher.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/KRPatternMatcher.java @@ -126,10 +126,11 @@ private static int updateHashForNextWindow(final byte[] source, final byte[] pat private static boolean equals(final byte[] array1, final int offset, final byte[] array2){ int i = 0; - for( ; i < array2.length; i ++) + final int length = array2.length; + for(; i < length; i ++) if(array1[i + offset] != array2[i]) break; - return (i == array2.length); + return (i == length); } } diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/Evaluator.java b/src/main/java/io/github/mtrevisan/boxon/helpers/Evaluator.java index a86d67a40..6d6527c69 100644 --- a/src/main/java/io/github/mtrevisan/boxon/helpers/Evaluator.java +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/Evaluator.java @@ -199,7 +199,7 @@ public int evaluateSize(final String expression, final Object rootObject){ } private static boolean isPositiveInteger(final CharSequence text){ - for(int i = 0; i < text.length(); i ++) + for(int i = 0, length = text.length(); i < length; i ++) if(!Character.isDigit(text.charAt(i))) return false; return true; @@ -219,11 +219,11 @@ protected final Field findField(final String name, Class cls, final boolean m return field; } - @SuppressWarnings("ReturnOfNull") private static Field findFieldInClass(final String name, final Class cls, final boolean mustBeStatic){ final Field[] declaredFields = cls.getDeclaredFields(); - for(int i = 0; i < declaredFields.length; i ++){ + for(int i = 0, length = declaredFields.length; i < length; i ++){ final Field field = declaredFields[i]; + if(field.getName().equals(name) && (!mustBeStatic || Modifier.isStatic(field.getModifiers()))) return field; } diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/GenericHelper.java b/src/main/java/io/github/mtrevisan/boxon/helpers/GenericHelper.java index 122a8e755..96aa29a71 100644 --- a/src/main/java/io/github/mtrevisan/boxon/helpers/GenericHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/GenericHelper.java @@ -114,8 +114,9 @@ else if(ancestorType instanceof Class && base.isAssignableFrom((Class)ancesto private static List> processBase(final Type[] actualArgs){ //there is a result if the base class is reached - final List> types = new ArrayList<>(actualArgs.length); - for(int i = 0; i < actualArgs.length; i ++){ + final int length = actualArgs.length; + final List> types = new ArrayList<>(length); + for(int i = 0; i < length; i ++){ final Class cls = toClass(actualArgs[i].getTypeName()); if(cls != null) types.add(cls); @@ -138,10 +139,13 @@ private static List> manageParameterizedAncestor(final Parameterize private static Class[] populateResolvedTypes(final ParameterizedType ancestorType, final Map typeVariables){ final Type[] types = ancestorType.getActualTypeArguments(); - final Collection> resolvedTypes = new ArrayList<>(types.length); + final int length = types.length; + final Collection> resolvedTypes = new ArrayList<>(length); //loop through all type arguments and replace type variables with the actually known types - for(int i = 0; i < types.length; i ++){ - final String typeName = resolveArgumentType(typeVariables, types[i]).getTypeName(); + for(int i = 0; i < length; i ++){ + final String typeName = resolveArgumentType(typeVariables, types[i]) + .getTypeName(); + final Class cls = toClass(typeName); if(cls != null) resolvedTypes.add(cls); @@ -150,9 +154,12 @@ private static Class[] populateResolvedTypes(final ParameterizedType ancestor } private static Map mapParameterTypes(final Class offspring, final Type[] actualArgs){ - final Map typeVariables = new HashMap<>(actualArgs.length); - for(int i = 0; i < actualArgs.length; i ++){ - final String key = offspring.getTypeParameters()[i].getName(); + final int length = actualArgs.length; + final Map typeVariables = new HashMap<>(length); + final TypeVariable>[] typeParameters = offspring.getTypeParameters(); + for(int i = 0; i < length; i ++){ + final String key = typeParameters[i].getName(); + typeVariables.put(key, actualArgs[i]); } return typeVariables; diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java b/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java index 13ac0bc6a..bc933ee52 100644 --- a/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java @@ -24,15 +24,19 @@ */ package io.github.mtrevisan.boxon.helpers; +import org.springframework.util.StopWatch; + import java.lang.reflect.Field; import java.lang.reflect.InaccessibleObjectException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.function.BiConsumer; @@ -111,7 +115,7 @@ public static void injectStaticValue(final Class type, final Class fie private static void injectValue(final Class objType, final Object obj, final Class fieldType, final T value){ try{ final List fields = getAccessibleFields(objType, fieldType); - for(int i = 0; i < fields.size(); i ++) + for(int i = 0, length = fields.size(); i < length; i ++) fields.get(i) .set(obj, value); } @@ -130,8 +134,9 @@ public static Map mapObject(final Object object){ return null; final List fields = getAccessibleFields(object.getClass()); - final Map map = new HashMap<>(fields.size()); - for(int i = 0; i < fields.size(); i ++){ + final int size = fields.size(); + final Map map = new HashMap<>(size); + for(int i = 0; i < size; i ++){ final Field field = fields.get(i); map.put(field.getName(), getValue(object, field)); @@ -188,22 +193,24 @@ private static BiConsumer, Field[]> getExtractChildFieldsMetho } private static void extractChildFields(final Collection fields, final Field[] rawFields){ - for(int i = 0; i < rawFields.length; i ++) + for(int i = 0, length = rawFields.length; i < length; i ++) fields.add(rawFields[i]); } //an injection must be performed private static void extractChildFields(final Collection fields, final Field[] rawFields, final Class fieldType){ - for(int i = 0; i < rawFields.length; i ++){ + for(int i = 0, length = rawFields.length; i < length; i ++){ final Field rawSubField = rawFields[i]; + if(rawSubField.isAnnotationPresent(Injected.class) && fieldType.isAssignableFrom(rawSubField.getType())) fields.add(rawSubField); } } private static void makeFieldsAccessible(final List fields){ - for(int i = 0; i < fields.size(); i ++) - fields.get(i).setAccessible(true); + for(int i = 0, length = fields.size(); i < length; i ++) + fields.get(i) + .setAccessible(true); } diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/StringHelper.java b/src/main/java/io/github/mtrevisan/boxon/helpers/StringHelper.java index fa9cea261..7b18b0fa6 100644 --- a/src/main/java/io/github/mtrevisan/boxon/helpers/StringHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/StringHelper.java @@ -111,11 +111,11 @@ public static String[] split(final String str, final char separatorChar){ } start = ++ i; - continue; } - - match = true; - i ++; + else{ + match = true; + i ++; + } } if(match) list.add(str.substring(start, i)); @@ -131,15 +131,16 @@ public static String[] split(final String str, final char separatorChar){ */ public static String toHexString(final byte[] array){ final int length = JavaHelper.lengthOrZero(array); - final StringBuilder sb = new StringBuilder(length << 1); + final char[] hexChars = new char[length << 1]; for(int i = 0; i < length; i ++){ - final byte elem = array[i]; + final int elem = array[i] & 0xFF; + final char highDigit = Character.forDigit((elem >>> 4) & 0x0F, 16); final char lowDigit = Character.forDigit(elem & 0x0F, 16); - sb.append(highDigit); - sb.append(lowDigit); + hexChars[i << 1] = highDigit; + hexChars[(i << 1) + 1] = lowDigit; } - return sb.toString() + return new String(hexChars) .toUpperCase(Locale.ROOT); } @@ -158,6 +159,7 @@ public static byte[] hexToByteArray(final CharSequence hexString){ for(int i = 0; i < length; i += 2){ final int highDigit = Character.digit(hexString.charAt(i), 16); final int lowDigit = Character.digit(hexString.charAt(i + 1), 16); + data[i >>> 1] = (byte)((highDigit << 4) + lowDigit); } return data; @@ -172,10 +174,10 @@ public static byte[] hexToByteArray(final CharSequence hexString){ */ public static String toASCIIString(final byte[] array){ final int length = JavaHelper.lengthOrZero(array); - final StringBuilder sb = new StringBuilder(length); + final char[] chars = new char[length]; for(int i = 0; i < length; i ++) - sb.append((char)(array[i] & 0xFF)); - return sb.toString(); + chars[i] = (char)(array[i] & 0xFF); + return new String(chars); } /** @@ -210,7 +212,7 @@ public static byte[] asciiToByteArray(final CharSequence asciiString){ * @return Whether the given text is {@code null}, empty or whitespace only. */ public static boolean isBlank(final CharSequence text){ - for(int i = 0; i < JavaHelper.lengthOrZero(text); i ++) + for(int i = 0, length = JavaHelper.lengthOrZero(text); i < length; i ++) if(!Character.isWhitespace(text.charAt(i))) return false; return true; diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java b/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java index 46df3b991..04dbe0519 100644 --- a/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java @@ -34,7 +34,7 @@ public final class TextStatistics{ public void addData(final byte[] buffer, final int offset, final int length){ for(int i = 0; i < length; i ++){ - counts[buffer[offset + i] & 0xff] ++; + counts[buffer[offset + i] & 0xFF] ++; total ++; } } @@ -71,9 +71,11 @@ public boolean looksLikeUTF8(){ int expectedContinuation = 0; final int[] leading = {count(0xC0, 0xE0), count(0xE0, 0xF0), count(0xF0, 0xF8)}; - for(int i = 0; i < leading.length; i ++){ - utf8 += leading[i]; - expectedContinuation += (i + 1) * leading[i]; + for(int i = 0, length = leading.length; i < length; i ++){ + final int chr = leading[i]; + + utf8 += chr; + expectedContinuation += (i + 1) * chr; } final int continuation = count(0x80, 0xC0); diff --git a/src/main/java/io/github/mtrevisan/boxon/io/BitSetHelper.java b/src/main/java/io/github/mtrevisan/boxon/io/BitSetHelper.java index 5b928187e..511b8f673 100644 --- a/src/main/java/io/github/mtrevisan/boxon/io/BitSetHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/io/BitSetHelper.java @@ -75,7 +75,7 @@ private static BitSet bitReverse(final BitSet bits){ * @param array The array to be reversed. */ private static void bitReverse(final byte[] array){ - for(int i = 0; i < array.length; i ++) + for(int i = 0, length = array.length; i < length; i ++) array[i] = reverseBits(array[i]); byteReverse(array); } diff --git a/src/main/java/io/github/mtrevisan/boxon/io/BitWriter.java b/src/main/java/io/github/mtrevisan/boxon/io/BitWriter.java index 7b036cdde..3ee1a1676 100644 --- a/src/main/java/io/github/mtrevisan/boxon/io/BitWriter.java +++ b/src/main/java/io/github/mtrevisan/boxon/io/BitWriter.java @@ -68,7 +68,7 @@ public void putByte(final byte value){ @Override public void putBytes(final byte[] array){ - for(int i = 0; i < array.length; i ++) + for(int i = 0, length = array.length; i < length; i ++) putByte(array[i]); } diff --git a/src/main/java/io/github/mtrevisan/boxon/io/ParserDataType.java b/src/main/java/io/github/mtrevisan/boxon/io/ParserDataType.java index 366d89161..cc20b3b01 100644 --- a/src/main/java/io/github/mtrevisan/boxon/io/ParserDataType.java +++ b/src/main/java/io/github/mtrevisan/boxon/io/ParserDataType.java @@ -28,6 +28,8 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.math.BigInteger; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -119,11 +121,13 @@ void write(final BitWriterInterface writer, final Object value, final ByteOrder private static final Map, ParserDataType> TYPE_MAP; static{ final ParserDataType[] values = values(); - final Map, Class> primitiveWrapperMap = new HashMap<>(values.length); - final Map, Class> wrapperPrimitiveMap = new HashMap<>(values.length); - final Map, ParserDataType> typeMap = new HashMap<>(values.length * 2); - for(int i = 0; i < values.length; i ++){ + final int length = values.length; + final Map, Class> primitiveWrapperMap = new HashMap<>(length); + final Map, Class> wrapperPrimitiveMap = new HashMap<>(length); + final Map, ParserDataType> typeMap = new HashMap<>(length << 1); + for(int i = 0; i < length; i ++){ final ParserDataType dt = values[i]; + primitiveWrapperMap.put(dt.primitiveType, dt.objectiveType); wrapperPrimitiveMap.put(dt.objectiveType, dt.primitiveType); typeMap.put(dt.primitiveType, dt); @@ -276,7 +280,6 @@ public static Object getValueOrSelf(final Class fieldType, final Object value * @return The primitive or objective value. * @throws CodecException If the value cannot be interpreted as primitive or objective. */ - @SuppressWarnings("ReturnOfNull") public static Object getValue(final Class fieldType, final String value) throws CodecException{ if(fieldType == String.class) return value; @@ -292,24 +295,58 @@ public static Object getValue(final Class fieldType, final String value) thro : val); } - private static Object toNumber(final String text, final Class objectiveType){ - Object response = null; + Object result = null; if(isNumeric(text)){ try{ - final Method method = objectiveType.getDeclaredMethod(METHOD_VALUE_OF, String.class, int.class); - final boolean hexadecimal = text.startsWith("0x"); - response = method.invoke(null, (hexadecimal? text.substring(2): text), (hexadecimal? 16: 10)); + final BigInteger decValue = (text.startsWith("0x") + ? new BigInteger(text.substring(2), 16) + : new BigInteger(text)); + final int maxBytes = (int)objectiveType.getDeclaredField("BYTES") + .get(null); + if(decValue.bitCount() <= maxBytes << 3){ + //extract decimal value as object + final byte[] byteArray = decValue.toByteArray(); + if(maxBytes == Byte.BYTES) + result = byteArray[0]; + else{ + long value = 0l; + for(int i = 0, length = byteArray.length; i < length; i ++) + value |= (byteArray[i] & 0xFFl) << (Byte.SIZE * (length - 1 - i)); + + if(maxBytes == Short.BYTES) + result = (short)value; + else if(maxBytes == Integer.BYTES) + result = (int)value; + else if(maxBytes == Long.BYTES) + result = value; + } + } } - catch(final NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored){} + catch(final NoSuchFieldException | IllegalAccessException ignored){} } - return response; + return result; } private static boolean isNumeric(final String text){ return (isHexadecimalNumber(text) || isDecimalNumber(text)); } + /** + * Returns the primitive or objective type (depending on the field type) data stored as a string value. + * + * @param value The string value to be interpreted. + * @return The primitive or objective value as an unsigned number (e.g. `(byte)0xFF` is 255 rather than -1). + */ + public static Number getBigNumber(final String value){ + if(value == null || value.isEmpty()) + return null; + + return (value.startsWith("0x") + ? new BigInteger(value.substring(2), 16) + : new BigDecimal(value)); + } + /** *

Checks if the text contains only Unicode digits. @@ -349,8 +386,9 @@ private static boolean isHexadecimalNumber(final String text){ } private static boolean isBaseNumber(final CharSequence text, final int offset, final int radix){ - for(int i = offset; i < text.length(); i ++){ + for(int i = offset, length = text.length(); i < length; i ++){ final char chr = text.charAt(i); + if(Character.digit(chr, radix) < 0) return true; } diff --git a/src/main/java/io/github/mtrevisan/boxon/logs/EventLogger.java b/src/main/java/io/github/mtrevisan/boxon/logs/EventLogger.java index e2bc50e96..da9265918 100644 --- a/src/main/java/io/github/mtrevisan/boxon/logs/EventLogger.java +++ b/src/main/java/io/github/mtrevisan/boxon/logs/EventLogger.java @@ -33,6 +33,7 @@ import java.util.Collection; import java.util.HashSet; +import java.util.Iterator; import java.util.StringJoiner; @@ -79,7 +80,7 @@ public void loadingCodecsFrom(final Class[] basePackageClasses){ public void loadingCodec(final Class[] codecClasses){ if(LOGGER.isInfoEnabled()){ final StringJoiner sj = new StringJoiner(", ", "[", "]"); - for(int i = 0; i < codecClasses.length; i ++) + for(int i = 0, length = codecClasses.length; i < length; i ++) sj.add(codecClasses[i].getSimpleName()); info("Loading codecs: {}", sj.toString()); @@ -105,7 +106,7 @@ public void loadingTemplatesFrom(final Class[] basePackageClasses){ private static StringJoiner joinPackageNames(final Class[] basePackageClasses){ final StringJoiner sj = new StringJoiner(", ", "[", "]"); - for(int i = 0; i < basePackageClasses.length; i ++) + for(int i = 0, length = basePackageClasses.length; i < length; i ++) sj.add(basePackageClasses[i].getPackageName()); return sj; } @@ -225,8 +226,9 @@ private static Object[] extractParameters(final Object[] parameters){ } private static Collection collectPackages(final Object[] parameters){ - final Collection packages = new HashSet<>(parameters.length); - for(int i = 0; i < parameters.length; i ++) + final int length = parameters.length; + final Collection packages = new HashSet<>(length); + for(int i = 0; i < length; i ++) packages.add(((Class)parameters[i]).getPackageName()); return packages; } diff --git a/src/main/java/io/github/mtrevisan/boxon/semanticversioning/Version.java b/src/main/java/io/github/mtrevisan/boxon/semanticversioning/Version.java index b92be844a..8aae5fd1f 100644 --- a/src/main/java/io/github/mtrevisan/boxon/semanticversioning/Version.java +++ b/src/main/java/io/github/mtrevisan/boxon/semanticversioning/Version.java @@ -234,7 +234,7 @@ private static void validateToken(final String type, final String token) throws } private static void validatePreRelease(final String[] preRelease) throws VersionException{ - for(int i = 0; i < preRelease.length; i ++) + for(int i = 0, length = preRelease.length; i < length; i ++) validatePreRelease(preRelease[i]); } @@ -247,7 +247,7 @@ private static void validatePreRelease(final String pr){ } private static void validateBuild(final String[] build) throws VersionException{ - for(int i = 0; i < build.length; i ++) + for(int i = 0, length = build.length; i < length; i ++) validateBuild(build[i]); } @@ -404,7 +404,7 @@ private static int compareToIdentifiers(final String[] preRelease, final String[ private static int compareIdentifierArrays(final String[] preRelease, final String[] otherPreRelease){ int result = (otherPreRelease.length - preRelease.length); - for(int i = 0; i < getLeastCommonArrayLength(preRelease, otherPreRelease); i ++){ + for(int i = 0, length = getLeastCommonArrayLength(preRelease, otherPreRelease); i < length; i ++){ result = compareIdentifiers(preRelease[i], otherPreRelease[i]); if(result != 0) break; @@ -440,8 +440,9 @@ private static int compareIdentifiers(final String identifier1, final String ide */ private static boolean containsOnlyValidChars(String text){ text = text.toUpperCase(Locale.ROOT); - for(int i = 0; i < text.length(); i ++){ + for(int i = 0, length = text.length(); i < length; i ++){ final char chr = text.charAt(i); + if(chr != '-' && (chr < 'A' || chr > 'Z')) return false; } diff --git a/src/test/java/io/github/mtrevisan/boxon/MapIterationSpeedTest.java b/src/test/java/io/github/mtrevisan/boxon/MapIterationSpeedTest.java new file mode 100644 index 000000000..e592b5165 --- /dev/null +++ b/src/test/java/io/github/mtrevisan/boxon/MapIterationSpeedTest.java @@ -0,0 +1,55 @@ +package io.github.mtrevisan.boxon; + +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + + +class MapIterationSpeedTest{ + + public static void main(String[] args) { + // Creazione di una mappa con un gran numero di elementi + Map context = generateTestData(1000000); + + // Test del metodo tradizionale + long startTime = System.currentTimeMillis(); + iterateTraditionally(context); + long traditionalTime = System.currentTimeMillis() - startTime; + System.out.println("Tempo impiegato per l'iterazione tradizionale: " + traditionalTime + " ms"); + + // Test del metodo parallelo + startTime = System.currentTimeMillis(); + iterateInParallel(context); + long parallelTime = System.currentTimeMillis() - startTime; + System.out.println("Tempo impiegato per l'iterazione parallela: " + parallelTime + " ms"); + } + + // Genera una mappa di test con un numero specifico di elementi + private static Map generateTestData(int size) { + Map testData = new HashMap<>(); + Random random = new Random(); + for (int i = 0; i < size; i++) { + testData.put("key" + i, random.nextInt()); + } + return testData; + } + + // Iterazione tradizionale sulla mappa + private static void iterateTraditionally(Map context) { + for (Map.Entry entry : context.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + // Operazioni da eseguire su ogni entry + } + } + + // Iterazione parallela sulla mappa + private static void iterateInParallel(Map context) { + context.entrySet().forEach(entry -> { + String key = entry.getKey(); + Object value = entry.getValue(); + // Operazioni da eseguire su ogni entry + }); + } + +} diff --git a/src/test/java/io/github/mtrevisan/boxon/core/ComposerTest.java b/src/test/java/io/github/mtrevisan/boxon/core/ComposerTest.java index a231caacd..ee722b780 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/ComposerTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/ComposerTest.java @@ -46,7 +46,7 @@ class ComposerTest{ @Test void parseAndComposeSingleMessageHex() throws NoSuchMethodException, AnnotationException, TemplateException, ConfigurationException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Core core = CoreBuilder.builder() .withContextPair("deviceTypes", deviceTypes) .withContextFunction(ParserTest.class, "headerLength") @@ -76,7 +76,7 @@ void parseAndComposeSingleMessageHex() throws NoSuchMethodException, AnnotationE @Test void parseAndComposeSingleMessageASCII() throws AnnotationException, TemplateException, ConfigurationException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GV350M", (byte)0xCF); + .with((byte)0xCF, "QUECLINK_GV350M"); Map context = Collections.singletonMap("deviceTypes", deviceTypes); Core core = CoreBuilder.builder() .withContext(context) diff --git a/src/test/java/io/github/mtrevisan/boxon/core/ComposerThreadedTest.java b/src/test/java/io/github/mtrevisan/boxon/core/ComposerThreadedTest.java index fe822164d..897c71dd5 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/ComposerThreadedTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/ComposerThreadedTest.java @@ -48,7 +48,7 @@ class ComposerThreadedTest{ void concurrencySingleParserSingleCore() throws NoSuchMethodException, AnnotationException, TemplateException, ConfigurationException, ExecutionException, InterruptedException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Core core = CoreBuilder.builder() .withContextPair("deviceTypes", deviceTypes) .withContextFunction(ParserTest.class, "headerLength") @@ -74,7 +74,7 @@ void concurrencySingleParserSingleCore() throws NoSuchMethodException, Annotatio void concurrencyMultipleParserSingleCore() throws NoSuchMethodException, AnnotationException, TemplateException, ConfigurationException, ExecutionException, InterruptedException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Core core = CoreBuilder.builder() .withContextPair("deviceTypes", deviceTypes) .withContextFunction(ParserTest.class, "headerLength") @@ -102,7 +102,7 @@ void concurrencyMultipleParserSingleCore() throws NoSuchMethodException, Annotat void concurrencyMultipleParserMultipleCore() throws NoSuchMethodException, AnnotationException, TemplateException, ConfigurationException, ExecutionException, InterruptedException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); //compose: int threadCount = 10; diff --git a/src/test/java/io/github/mtrevisan/boxon/core/ConfiguratorTest.java b/src/test/java/io/github/mtrevisan/boxon/core/ConfiguratorTest.java index c9b7dc409..89157af52 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/ConfiguratorTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/ConfiguratorTest.java @@ -45,7 +45,7 @@ class ConfiguratorTest{ @Test void getConfigurations() throws AnnotationException, ConfigurationException, CodecException, TemplateException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Core core = CoreBuilder.builder() .withDefaultCodecs() .withConfiguration(REGConfigurationASCII.class) @@ -63,14 +63,14 @@ void getConfigurations() throws AnnotationException, ConfigurationException, Cod ConfigurationKey.CONFIGURATION_PROTOCOL_VERSION_BOUNDARIES.toString())); Assertions.assertEquals("{longDescription:The command AT+GTREG is used to do things.,maxProtocol:2.8,shortDescription:AT+GTREG}", jsonHeader); - Assertions.assertEquals("{Operation mode report interval:{minValue:3600,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.21,fieldType:int},Maximum download retry count:{alternatives:[{maxProtocol:1.20,minValue:0,fieldType:int,maxValue:3,defaultValue:0},{minValue:0,fieldType:int,maxValue:3,minProtocol:1.21,defaultValue:1}]},Download timeout:{alternatives:[{maxProtocol:1.18,minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,defaultValue:10},{minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,minProtocol:1.19,defaultValue:20}]},Weekday:{defaultValue:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY],enumeration:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]},Update Over-The-Air:{defaultValue:FALSE,mutuallyExclusive:true,enumeration:[TRUE, FALSE]},Header:{charset:UTF-8,defaultValue:GTREG,fieldType:String},Download protocol:{alternatives:[{maxProtocol:1.35,enumeration:[HTTP, HTTPS],defaultValue:HTTP,mutuallyExclusive:true},{enumeration:[HTTP, HTTPS],minProtocol:1.36,defaultValue:HTTP,mutuallyExclusive:true}]},Download URL:{pattern:.{0,100},charset:UTF-8,fields:{URL:{pattern:https?://.{0,92},fieldType:String},password:{pattern:.{1,32},fieldType:String},username:{pattern:.{1,32},fieldType:String}}},Update mode:{minValue:0,maxValue:1,defaultValue:1,fieldType:int},Message counter:{minValue:0,maxValue:65535,fieldType:int},Operation mode:{minValue:0,maxValue:3,defaultValue:0,fieldType:int},Motion report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int},Password:{charset:UTF-8,defaultValue:gb200s,pattern:[0-9a-zA-Z]{4,20},fieldType:String},Motionless report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int}}", jsonFields); + Assertions.assertEquals("{Operation mode report interval:{minValue:3600,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.21,fieldType:int},Maximum download retry count:{alternatives:[{maxProtocol:1.20,minValue:0,fieldType:int,maxValue:3,defaultValue:0},{minValue:0,fieldType:int,maxValue:3,minProtocol:1.21,defaultValue:1}]},Download timeout:{alternatives:[{maxProtocol:1.18,minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,defaultValue:10},{minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,minProtocol:1.19,defaultValue:20}]},Weekday:{defaultValue:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY],enumeration:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]},Update Over-The-Air:{defaultValue:FALSE,mutuallyExclusive:true,enumeration:[TRUE, FALSE]},Header:{charset:UTF-8,defaultValue:GTREG,fieldType:String},Download protocol:{alternatives:[{maxProtocol:1.35,enumeration:[HTTP, HTTPS],defaultValue:HTTP,mutuallyExclusive:true},{enumeration:[HTTP, HTTPS],minProtocol:1.36,defaultValue:HTTPS,mutuallyExclusive:true}]},Download URL:{pattern:.{0,100},charset:UTF-8,fields:{URL:{pattern:https?://.{0,92},fieldType:String},password:{pattern:.{1,32},fieldType:String},username:{pattern:.{1,32},fieldType:String}}},Update mode:{minValue:0,maxValue:1,defaultValue:1,fieldType:int},Message counter:{minValue:0,maxValue:65535,fieldType:short},Operation mode:{minValue:0,maxValue:3,defaultValue:0,fieldType:int},Motion report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int},Password:{charset:UTF-8,defaultValue:gb200s,pattern:[0-9a-zA-Z]{4,20},fieldType:String},Motionless report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int}}", jsonFields); Assertions.assertEquals("[1.18,1.19,1.20,1.21,1.35,1.36,2.8]", jsonProtocolVersionBoundaries); } @Test void getProtocolVersionBoundaries() throws AnnotationException, ConfigurationException, TemplateException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Core core = CoreBuilder.builder() .withDefaultCodecs() .withConfigurationsFrom(REGConfigurationASCII.class) @@ -87,7 +87,7 @@ void getProtocolVersionBoundaries() throws AnnotationException, ConfigurationExc @Test void getConfigurationsByProtocol() throws AnnotationException, ConfigurationException, CodecException, TemplateException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Core core = CoreBuilder.builder() .withDefaultCodecs() .withConfigurationsFrom(REGConfigurationASCII.class) @@ -103,13 +103,13 @@ void getConfigurationsByProtocol() throws AnnotationException, ConfigurationExce String jsonFields = PrettyPrintMap.toString(configuration.get(ConfigurationKey.CONFIGURATION_FIELDS.toString())); Assertions.assertEquals("{longDescription:The command AT+GTREG is used to do things.,shortDescription:AT+GTREG}", jsonHeader); - Assertions.assertEquals("{Maximum download retry count:{minValue:0,fieldType:int,maxValue:3,defaultValue:0},Download timeout:{minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,defaultValue:20},Weekday:{defaultValue:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY],enumeration:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]},Update Over-The-Air:{defaultValue:FALSE,mutuallyExclusive:true,enumeration:[TRUE, FALSE]},Header:{charset:UTF-8,defaultValue:GTREG,fieldType:String},Download protocol:{enumeration:[HTTP, HTTPS],defaultValue:HTTP,mutuallyExclusive:true},Download URL:{pattern:.{0,100},charset:UTF-8,fields:{URL:{pattern:https?://.{0,92},fieldType:String},password:{pattern:.{1,32},fieldType:String},username:{pattern:.{1,32},fieldType:String}}},Update mode:{minValue:0,maxValue:1,defaultValue:1,fieldType:int},Message counter:{minValue:0,maxValue:65535,fieldType:int},Operation mode:{minValue:0,maxValue:3,defaultValue:0,fieldType:int},Motion report interval:{minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,fieldType:int},Password:{charset:UTF-8,defaultValue:gb200s,pattern:[0-9a-zA-Z]{4,20},fieldType:String},Motionless report interval:{minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,fieldType:int}}", jsonFields); + Assertions.assertEquals("{Maximum download retry count:{minValue:0,fieldType:int,maxValue:3,defaultValue:0},Download timeout:{minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,defaultValue:20},Weekday:{defaultValue:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY],enumeration:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]},Update Over-The-Air:{defaultValue:FALSE,mutuallyExclusive:true,enumeration:[TRUE, FALSE]},Header:{charset:UTF-8,defaultValue:GTREG,fieldType:String},Download protocol:{enumeration:[HTTP, HTTPS],defaultValue:HTTP,mutuallyExclusive:true},Download URL:{pattern:.{0,100},charset:UTF-8,fields:{URL:{pattern:https?://.{0,92},fieldType:String},password:{pattern:.{1,32},fieldType:String},username:{pattern:.{1,32},fieldType:String}}},Update mode:{minValue:0,maxValue:1,defaultValue:1,fieldType:int},Message counter:{minValue:0,maxValue:65535,fieldType:short},Operation mode:{minValue:0,maxValue:3,defaultValue:0,fieldType:int},Motion report interval:{minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,fieldType:int},Password:{charset:UTF-8,defaultValue:gb200s,pattern:[0-9a-zA-Z]{4,20},fieldType:String},Motionless report interval:{minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,fieldType:int}}", jsonFields); } @Test void composeSingleConfigurationMessage() throws NoSuchMethodException, AnnotationException, TemplateException, ConfigurationException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Core core = CoreBuilder.builder() .withDefaultCodecs() .withConfigurationsFrom(REGConfigurationASCII.class) @@ -129,7 +129,7 @@ void composeSingleConfigurationMessage() throws NoSuchMethodException, Annotatio )); configurationData.put("Update mode", 0); configurationData.put("Maximum download retry count", 2); - configurationData.put("Message counter", 123); + configurationData.put("Message counter", (short)123); configurationData.put("Operation mode", 1); configurationData.put("Password", "pass"); configurationData.put("Download timeout", 25); @@ -139,7 +139,7 @@ void composeSingleConfigurationMessage() throws NoSuchMethodException, Annotatio configurationData); Assertions.assertFalse(composeResult.hasError()); - Assertions.assertEquals("AT+GTREG=pass,1,1,0,2,25,0,http://url.com@username@password,3600,3600,6,,7b$", + Assertions.assertEquals("AT+GTREG=pass,1,1,0,2,25,0,http://url.com@username@password,3600,3600,06,,7B$", new String(composeResult.getMessage())); } diff --git a/src/test/java/io/github/mtrevisan/boxon/core/ConfiguratorThreadedTest.java b/src/test/java/io/github/mtrevisan/boxon/core/ConfiguratorThreadedTest.java index dd89bbaf6..7a48a371f 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/ConfiguratorThreadedTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/ConfiguratorThreadedTest.java @@ -46,7 +46,7 @@ class ConfiguratorThreadedTest{ void concurrencySingleParserSingleCore() throws AnnotationException, ConfigurationException, CodecException, TemplateException, ExecutionException, InterruptedException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Core core = CoreBuilder.builder() .withDefaultCodecs() .withConfiguration(REGConfigurationASCII.class) @@ -63,7 +63,7 @@ void concurrencySingleParserSingleCore() throws AnnotationException, Configurati ConfigurationKey.CONFIGURATION_PROTOCOL_VERSION_BOUNDARIES.toString())); Assertions.assertEquals("{longDescription:The command AT+GTREG is used to do things.,maxProtocol:2.8,shortDescription:AT+GTREG}", jsonHeader); - Assertions.assertEquals("{Operation mode report interval:{minValue:3600,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.21,fieldType:int},Maximum download retry count:{alternatives:[{maxProtocol:1.20,minValue:0,fieldType:int,maxValue:3,defaultValue:0},{minValue:0,fieldType:int,maxValue:3,minProtocol:1.21,defaultValue:1}]},Download timeout:{alternatives:[{maxProtocol:1.18,minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,defaultValue:10},{minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,minProtocol:1.19,defaultValue:20}]},Weekday:{defaultValue:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY],enumeration:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]},Update Over-The-Air:{defaultValue:FALSE,mutuallyExclusive:true,enumeration:[TRUE, FALSE]},Header:{charset:UTF-8,defaultValue:GTREG,fieldType:String},Download protocol:{alternatives:[{maxProtocol:1.35,enumeration:[HTTP, HTTPS],defaultValue:HTTP,mutuallyExclusive:true},{enumeration:[HTTP, HTTPS],minProtocol:1.36,defaultValue:HTTP,mutuallyExclusive:true}]},Download URL:{pattern:.{0,100},charset:UTF-8,fields:{URL:{pattern:https?://.{0,92},fieldType:String},password:{pattern:.{1,32},fieldType:String},username:{pattern:.{1,32},fieldType:String}}},Update mode:{minValue:0,maxValue:1,defaultValue:1,fieldType:int},Message counter:{minValue:0,maxValue:65535,fieldType:int},Operation mode:{minValue:0,maxValue:3,defaultValue:0,fieldType:int},Motion report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int},Password:{charset:UTF-8,defaultValue:gb200s,pattern:[0-9a-zA-Z]{4,20},fieldType:String},Motionless report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int}}", jsonFields); + Assertions.assertEquals("{Operation mode report interval:{minValue:3600,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.21,fieldType:int},Maximum download retry count:{alternatives:[{maxProtocol:1.20,minValue:0,fieldType:int,maxValue:3,defaultValue:0},{minValue:0,fieldType:int,maxValue:3,minProtocol:1.21,defaultValue:1}]},Download timeout:{alternatives:[{maxProtocol:1.18,minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,defaultValue:10},{minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,minProtocol:1.19,defaultValue:20}]},Weekday:{defaultValue:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY],enumeration:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]},Update Over-The-Air:{defaultValue:FALSE,mutuallyExclusive:true,enumeration:[TRUE, FALSE]},Header:{charset:UTF-8,defaultValue:GTREG,fieldType:String},Download protocol:{alternatives:[{maxProtocol:1.35,enumeration:[HTTP, HTTPS],defaultValue:HTTP,mutuallyExclusive:true},{enumeration:[HTTP, HTTPS],minProtocol:1.36,defaultValue:HTTPS,mutuallyExclusive:true}]},Download URL:{pattern:.{0,100},charset:UTF-8,fields:{URL:{pattern:https?://.{0,92},fieldType:String},password:{pattern:.{1,32},fieldType:String},username:{pattern:.{1,32},fieldType:String}}},Update mode:{minValue:0,maxValue:1,defaultValue:1,fieldType:int},Message counter:{minValue:0,maxValue:65535,fieldType:short},Operation mode:{minValue:0,maxValue:3,defaultValue:0,fieldType:int},Motion report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int},Password:{charset:UTF-8,defaultValue:gb200s,pattern:[0-9a-zA-Z]{4,20},fieldType:String},Motionless report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int}}", jsonFields); Assertions.assertEquals("[1.18,1.19,1.20,1.21,1.35,1.36,2.8]", jsonProtocolVersionBoundaries); }, 10 @@ -74,7 +74,7 @@ void concurrencySingleParserSingleCore() throws AnnotationException, Configurati void concurrencyMultipleParserSingleCore() throws AnnotationException, ConfigurationException, CodecException, TemplateException, ExecutionException, InterruptedException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Core core = CoreBuilder.builder() .withDefaultCodecs() .withConfiguration(REGConfigurationASCII.class) @@ -93,7 +93,7 @@ void concurrencyMultipleParserSingleCore() throws AnnotationException, Configura ConfigurationKey.CONFIGURATION_PROTOCOL_VERSION_BOUNDARIES.toString())); Assertions.assertEquals("{longDescription:The command AT+GTREG is used to do things.,maxProtocol:2.8,shortDescription:AT+GTREG}", jsonHeader); - Assertions.assertEquals("{Operation mode report interval:{minValue:3600,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.21,fieldType:int},Maximum download retry count:{alternatives:[{maxProtocol:1.20,minValue:0,fieldType:int,maxValue:3,defaultValue:0},{minValue:0,fieldType:int,maxValue:3,minProtocol:1.21,defaultValue:1}]},Download timeout:{alternatives:[{maxProtocol:1.18,minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,defaultValue:10},{minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,minProtocol:1.19,defaultValue:20}]},Weekday:{defaultValue:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY],enumeration:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]},Update Over-The-Air:{defaultValue:FALSE,mutuallyExclusive:true,enumeration:[TRUE, FALSE]},Header:{charset:UTF-8,defaultValue:GTREG,fieldType:String},Download protocol:{alternatives:[{maxProtocol:1.35,enumeration:[HTTP, HTTPS],defaultValue:HTTP,mutuallyExclusive:true},{enumeration:[HTTP, HTTPS],minProtocol:1.36,defaultValue:HTTP,mutuallyExclusive:true}]},Download URL:{pattern:.{0,100},charset:UTF-8,fields:{URL:{pattern:https?://.{0,92},fieldType:String},password:{pattern:.{1,32},fieldType:String},username:{pattern:.{1,32},fieldType:String}}},Update mode:{minValue:0,maxValue:1,defaultValue:1,fieldType:int},Message counter:{minValue:0,maxValue:65535,fieldType:int},Operation mode:{minValue:0,maxValue:3,defaultValue:0,fieldType:int},Motion report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int},Password:{charset:UTF-8,defaultValue:gb200s,pattern:[0-9a-zA-Z]{4,20},fieldType:String},Motionless report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int}}", jsonFields); + Assertions.assertEquals("{Operation mode report interval:{minValue:3600,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.21,fieldType:int},Maximum download retry count:{alternatives:[{maxProtocol:1.20,minValue:0,fieldType:int,maxValue:3,defaultValue:0},{minValue:0,fieldType:int,maxValue:3,minProtocol:1.21,defaultValue:1}]},Download timeout:{alternatives:[{maxProtocol:1.18,minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,defaultValue:10},{minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,minProtocol:1.19,defaultValue:20}]},Weekday:{defaultValue:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY],enumeration:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]},Update Over-The-Air:{defaultValue:FALSE,mutuallyExclusive:true,enumeration:[TRUE, FALSE]},Header:{charset:UTF-8,defaultValue:GTREG,fieldType:String},Download protocol:{alternatives:[{maxProtocol:1.35,enumeration:[HTTP, HTTPS],defaultValue:HTTP,mutuallyExclusive:true},{enumeration:[HTTP, HTTPS],minProtocol:1.36,defaultValue:HTTPS,mutuallyExclusive:true}]},Download URL:{pattern:.{0,100},charset:UTF-8,fields:{URL:{pattern:https?://.{0,92},fieldType:String},password:{pattern:.{1,32},fieldType:String},username:{pattern:.{1,32},fieldType:String}}},Update mode:{minValue:0,maxValue:1,defaultValue:1,fieldType:int},Message counter:{minValue:0,maxValue:65535,fieldType:short},Operation mode:{minValue:0,maxValue:3,defaultValue:0,fieldType:int},Motion report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int},Password:{charset:UTF-8,defaultValue:gb200s,pattern:[0-9a-zA-Z]{4,20},fieldType:String},Motionless report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int}}", jsonFields); Assertions.assertEquals("[1.18,1.19,1.20,1.21,1.35,1.36,2.8]", jsonProtocolVersionBoundaries); }, 10 @@ -104,7 +104,7 @@ void concurrencyMultipleParserSingleCore() throws AnnotationException, Configura void concurrencyMultipleParserMultipleCore() throws AnnotationException, ConfigurationException, CodecException, TemplateException, ExecutionException, InterruptedException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); MultithreadingHelper.testMultithreading( () -> { @@ -123,7 +123,7 @@ void concurrencyMultipleParserMultipleCore() throws AnnotationException, Configu ConfigurationKey.CONFIGURATION_PROTOCOL_VERSION_BOUNDARIES.toString())); Assertions.assertEquals("{longDescription:The command AT+GTREG is used to do things.,maxProtocol:2.8,shortDescription:AT+GTREG}", jsonHeader); - Assertions.assertEquals("{Operation mode report interval:{minValue:3600,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.21,fieldType:int},Maximum download retry count:{alternatives:[{maxProtocol:1.20,minValue:0,fieldType:int,maxValue:3,defaultValue:0},{minValue:0,fieldType:int,maxValue:3,minProtocol:1.21,defaultValue:1}]},Download timeout:{alternatives:[{maxProtocol:1.18,minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,defaultValue:10},{minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,minProtocol:1.19,defaultValue:20}]},Weekday:{defaultValue:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY],enumeration:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]},Update Over-The-Air:{defaultValue:FALSE,mutuallyExclusive:true,enumeration:[TRUE, FALSE]},Header:{charset:UTF-8,defaultValue:GTREG,fieldType:String},Download protocol:{alternatives:[{maxProtocol:1.35,enumeration:[HTTP, HTTPS],defaultValue:HTTP,mutuallyExclusive:true},{enumeration:[HTTP, HTTPS],minProtocol:1.36,defaultValue:HTTP,mutuallyExclusive:true}]},Download URL:{pattern:.{0,100},charset:UTF-8,fields:{URL:{pattern:https?://.{0,92},fieldType:String},password:{pattern:.{1,32},fieldType:String},username:{pattern:.{1,32},fieldType:String}}},Update mode:{minValue:0,maxValue:1,defaultValue:1,fieldType:int},Message counter:{minValue:0,maxValue:65535,fieldType:int},Operation mode:{minValue:0,maxValue:3,defaultValue:0,fieldType:int},Motion report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int},Password:{charset:UTF-8,defaultValue:gb200s,pattern:[0-9a-zA-Z]{4,20},fieldType:String},Motionless report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int}}", jsonFields); + Assertions.assertEquals("{Operation mode report interval:{minValue:3600,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.21,fieldType:int},Maximum download retry count:{alternatives:[{maxProtocol:1.20,minValue:0,fieldType:int,maxValue:3,defaultValue:0},{minValue:0,fieldType:int,maxValue:3,minProtocol:1.21,defaultValue:1}]},Download timeout:{alternatives:[{maxProtocol:1.18,minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,defaultValue:10},{minValue:5,unitOfMeasure:min,fieldType:int,maxValue:30,minProtocol:1.19,defaultValue:20}]},Weekday:{defaultValue:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY],enumeration:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]},Update Over-The-Air:{defaultValue:FALSE,mutuallyExclusive:true,enumeration:[TRUE, FALSE]},Header:{charset:UTF-8,defaultValue:GTREG,fieldType:String},Download protocol:{alternatives:[{maxProtocol:1.35,enumeration:[HTTP, HTTPS],defaultValue:HTTP,mutuallyExclusive:true},{enumeration:[HTTP, HTTPS],minProtocol:1.36,defaultValue:HTTPS,mutuallyExclusive:true}]},Download URL:{pattern:.{0,100},charset:UTF-8,fields:{URL:{pattern:https?://.{0,92},fieldType:String},password:{pattern:.{1,32},fieldType:String},username:{pattern:.{1,32},fieldType:String}}},Update mode:{minValue:0,maxValue:1,defaultValue:1,fieldType:int},Message counter:{minValue:0,maxValue:65535,fieldType:short},Operation mode:{minValue:0,maxValue:3,defaultValue:0,fieldType:int},Motion report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int},Password:{charset:UTF-8,defaultValue:gb200s,pattern:[0-9a-zA-Z]{4,20},fieldType:String},Motionless report interval:{maxProtocol:1.20,minValue:90,unitOfMeasure:s,maxValue:86400,defaultValue:3600,minProtocol:1.19,fieldType:int}}", jsonFields); Assertions.assertEquals("[1.18,1.19,1.20,1.21,1.35,1.36,2.8]", jsonProtocolVersionBoundaries); }, 10 diff --git a/src/test/java/io/github/mtrevisan/boxon/core/DescriptorTest.java b/src/test/java/io/github/mtrevisan/boxon/core/DescriptorTest.java index 8aef6f652..1e3a7d959 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/DescriptorTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/DescriptorTest.java @@ -49,7 +49,7 @@ class DescriptorTest{ @Test void description() throws AnnotationException, ConfigurationException, CodecException, TemplateException, NoSuchMethodException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Core core = CoreBuilder.builder() .withContextPair("deviceTypes", deviceTypes) .withContextFunction(ParserTest.class.getDeclaredMethod("headerLength")) diff --git a/src/test/java/io/github/mtrevisan/boxon/core/DescriptorThreadedTest.java b/src/test/java/io/github/mtrevisan/boxon/core/DescriptorThreadedTest.java index 8ae083307..e0669b2c6 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/DescriptorThreadedTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/DescriptorThreadedTest.java @@ -45,7 +45,7 @@ class DescriptorThreadedTest{ void concurrencySingleParserSingleCore() throws AnnotationException, ConfigurationException, CodecException, TemplateException, NoSuchMethodException, ExecutionException, InterruptedException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Core core = CoreBuilder.builder() .withContextPair("deviceTypes", deviceTypes) .withContextFunction(ParserTest.class.getDeclaredMethod("headerLength")) @@ -69,7 +69,7 @@ void concurrencySingleParserSingleCore() throws AnnotationException, Configurati void concurrencyMultipleParserSingleCore() throws NoSuchMethodException, TemplateException, ConfigurationException, AnnotationException, ExecutionException, InterruptedException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Core core = CoreBuilder.builder() .withContextPair("deviceTypes", deviceTypes) .withContextFunction(ParserTest.class.getDeclaredMethod("headerLength")) @@ -95,7 +95,7 @@ void concurrencyMultipleParserSingleCore() throws NoSuchMethodException, Templat void concurrencyMultipleParserMultipleCore() throws NoSuchMethodException, TemplateException, ConfigurationException, AnnotationException, ExecutionException, InterruptedException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); int threadCount = 10; AtomicInteger counter = new AtomicInteger(); diff --git a/src/test/java/io/github/mtrevisan/boxon/core/ParserTest.java b/src/test/java/io/github/mtrevisan/boxon/core/ParserTest.java index ec6b07641..3d0b5d94e 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/ParserTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/ParserTest.java @@ -44,7 +44,7 @@ class ParserTest{ public static void main(String[] args) throws NoSuchMethodException, AnnotationException, TemplateException, ConfigurationException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Map context = Collections.singletonMap("deviceTypes", deviceTypes); //if it is wanted `headerLength` to be a variable and not a method: //- remove Map context = Collections.singletonMap("deviceTypes", deviceTypes); above @@ -86,7 +86,7 @@ private static int headerLength(){ @Test void parseMultipleMessagesHex() throws NoSuchMethodException, AnnotationException, TemplateException, ConfigurationException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Map context = Collections.singletonMap("deviceTypes", deviceTypes); Core core = CoreBuilder.builder() .withContext(context) @@ -107,7 +107,7 @@ void parseMultipleMessagesHex() throws NoSuchMethodException, AnnotationExceptio @Test void parseMultipleMessagesASCII() throws AnnotationException, TemplateException, ConfigurationException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GV350M", (byte)0xCF); + .with((byte)0xCF, "QUECLINK_GV350M"); Map context = Collections.singletonMap("deviceTypes", deviceTypes); Core core = CoreBuilder.builder() .withContext(context) @@ -127,8 +127,8 @@ void parseMultipleMessagesASCII() throws AnnotationException, TemplateException, @Test void parseMultipleMessagesHexASCII() throws NoSuchMethodException, AnnotationException, TemplateException, ConfigurationException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46) - .with("QUECLINK_GV350M", (byte)0xCF); + .with((byte)0x46, "QUECLINK_GB200S") + .with((byte)0xCF, "QUECLINK_GV350M"); Map context = Collections.singletonMap("deviceTypes", deviceTypes); Core core = CoreBuilder.builder() .withContext(context) @@ -151,8 +151,8 @@ void parseMultipleMessagesHexASCII() throws NoSuchMethodException, AnnotationExc @Test void parseMultipleMessagesASCIIHex() throws AnnotationException, TemplateException, NoSuchMethodException, ConfigurationException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46) - .with("QUECLINK_GV350M", (byte)0xCF); + .with((byte)0x46, "QUECLINK_GB200S") + .with((byte)0xCF, "QUECLINK_GV350M"); Map context = Collections.singletonMap("deviceTypes", deviceTypes); Core core = CoreBuilder.builder() .withContext(context) diff --git a/src/test/java/io/github/mtrevisan/boxon/core/ParserThreadedTest.java b/src/test/java/io/github/mtrevisan/boxon/core/ParserThreadedTest.java index 94d5129a3..e8fb8279c 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/ParserThreadedTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/ParserThreadedTest.java @@ -50,7 +50,7 @@ class ParserThreadedTest{ void concurrencySingleParserSingleCore() throws NoSuchMethodException, TemplateException, ConfigurationException, AnnotationException, ExecutionException, InterruptedException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Map context = Collections.singletonMap("deviceTypes", deviceTypes); Core core = CoreBuilder.builder() .withContext(context) @@ -80,7 +80,7 @@ void concurrencySingleParserSingleCore() throws NoSuchMethodException, TemplateE void concurrencyMultipleParserSingleCore() throws NoSuchMethodException, TemplateException, ConfigurationException, AnnotationException, ExecutionException, InterruptedException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Map context = Collections.singletonMap("deviceTypes", deviceTypes); Core core = CoreBuilder.builder() .withContext(context) @@ -112,7 +112,7 @@ void concurrencyMultipleParserSingleCore() throws NoSuchMethodException, Templat void concurrencyMultipleParserMultipleCore() throws NoSuchMethodException, TemplateException, ConfigurationException, AnnotationException, ExecutionException, InterruptedException{ DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); Map context = Collections.singletonMap("deviceTypes", deviceTypes); AtomicInteger errors = new AtomicInteger(); diff --git a/src/test/java/io/github/mtrevisan/boxon/core/codecs/queclink/DeviceTypes.java b/src/test/java/io/github/mtrevisan/boxon/core/codecs/queclink/DeviceTypes.java index 63452454a..f6e474025 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/codecs/queclink/DeviceTypes.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/codecs/queclink/DeviceTypes.java @@ -32,7 +32,7 @@ public class DeviceTypes{ - private final Map deviceTypes; + private final Map deviceTypes; public static DeviceTypes create(){ @@ -45,8 +45,8 @@ private DeviceTypes(){ } - public DeviceTypes with(final String deviceTypeName, final byte deviceTypeCode){ - deviceTypes.put(deviceTypeName, deviceTypeCode); + public DeviceTypes with(final byte deviceTypeCode, final String deviceTypeName){ + deviceTypes.put(deviceTypeCode, deviceTypeName); return this; } @@ -60,24 +60,33 @@ boolean has(final byte deviceTypeCode){ return false; } - public String getDeviceTypeName(final byte deviceTypeCode){ - for(final Map.Entry deviceType : deviceTypes.entrySet()) - if(deviceType.getValue().equals(deviceTypeCode)) + public byte getDeviceTypeCode(final String deviceTypeName){ + for(final Map.Entry deviceType : deviceTypes.entrySet()) + if(deviceType.getValue().equals(deviceTypeName)) return deviceType.getKey(); - final String actualCode = Integer.toHexString(deviceTypeCode & 0x0000_00FF); - final StringJoiner sj = new StringJoiner(", 0x", "[0x", "]"); - for(final Map.Entry deviceType : deviceTypes.entrySet()) - sj.add(Integer.toHexString(deviceType.getValue() & 0x0000_00FF)); - throw new IllegalArgumentException("Cannot parse message from another device, device type is 0x" + actualCode.toUpperCase(Locale.ROOT) - + ", should be one of " + sj); + throw new IllegalArgumentException("Given device name is not recognized: " + deviceTypeName); + } + + public String getDeviceTypeName(final byte deviceTypeCode){ + final String deviceTypeName = deviceTypes.get(deviceTypeCode); + + if(deviceTypeName == null){ + final String actualCode = Integer.toHexString(deviceTypeCode & 0x0000_00FF); + final StringJoiner sj = new StringJoiner(", 0x", "[0x", "]"); + for(final Map.Entry deviceType : deviceTypes.entrySet()) + sj.add(Integer.toHexString(deviceType.getKey() & 0x0000_00FF)); + throw new IllegalArgumentException("Cannot parse message from another device, device type is 0x" + + actualCode.toUpperCase(Locale.ROOT) + ", should be one of " + sj); + } + return deviceTypeName; } @Override public String toString(){ final StringJoiner sj = new StringJoiner(", ", "[", "]"); - for(final Map.Entry deviceType : deviceTypes.entrySet()) - sj.add(deviceType.getKey() + " (0x" + Integer.toHexString(deviceType.getValue() & 0x0000_00FF).toUpperCase(Locale.ROOT) + ")"); + for(final Map.Entry deviceType : deviceTypes.entrySet()) + sj.add(deviceType.getValue() + " (0x" + Integer.toHexString(deviceType.getKey() & 0x0000_00FF).toUpperCase(Locale.ROOT) + ")"); return sj.toString(); } diff --git a/src/test/java/io/github/mtrevisan/boxon/core/codecs/queclink/REGConfigurationASCII.java b/src/test/java/io/github/mtrevisan/boxon/core/codecs/queclink/REGConfigurationASCII.java index 14a0ceb0d..bea1c4f4e 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/codecs/queclink/REGConfigurationASCII.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/codecs/queclink/REGConfigurationASCII.java @@ -77,7 +77,7 @@ public class REGConfigurationASCII{ shortDescription = "Download protocol", enumeration = DownloadProtocol.class, value = { @AlternativeSubField(maxProtocol = "1.35", defaultValue = "HTTP"), - @AlternativeSubField(minProtocol = "1.36", defaultValue = "HTTP") + @AlternativeSubField(minProtocol = "1.36", defaultValue = "HTTPS") }, terminator = "," ) @@ -116,6 +116,6 @@ public class REGConfigurationASCII{ @ConfigurationSkip(terminator = ",") @ConfigurationField(shortDescription = "Message counter", minValue = "0x0000", maxValue = "0xFFFF", radix = 16) - private Integer messageCounter; + private Short messageCounter; } diff --git a/src/test/java/io/github/mtrevisan/boxon/core/parsers/TemplateParserTest.java b/src/test/java/io/github/mtrevisan/boxon/core/parsers/TemplateParserTest.java index d4bed4431..fd0d4eac2 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/parsers/TemplateParserTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/parsers/TemplateParserTest.java @@ -71,7 +71,7 @@ void parseSingleMessageHex() throws NoSuchMethodException, FieldException{ Assertions.fail("Cannot decode message"); DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); evaluator.addToContext("deviceTypes", deviceTypes); evaluator.addToContext(TemplateParserTest.class.getDeclaredMethod("headerLength")); ACKMessageHex message = templateParser.decode(template, reader, null); @@ -101,7 +101,7 @@ void parseSingleMessageHexByteChecksum() throws NoSuchMethodException, FieldExce Assertions.fail("Cannot decode message"); DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GB200S", (byte)0x46); + .with((byte)0x46, "QUECLINK_GB200S"); evaluator.addToContext("deviceTypes", deviceTypes); evaluator.addToContext(TemplateParserTest.class.getDeclaredMethod("headerLength")); ACKMessageHexByteChecksum message = templateParser.decode(template, reader, null); @@ -135,7 +135,7 @@ void parseSingleMessageASCII() throws FieldException{ Assertions.fail("Cannot decode message"); DeviceTypes deviceTypes = DeviceTypes.create() - .with("QUECLINK_GV350M", (byte)0xCF); + .with((byte)0xCF, "QUECLINK_GV350M"); evaluator.addToContext("deviceTypes", deviceTypes); ACKMessageASCII message = templateParser.decode(template, reader, null); evaluator.addToContext("deviceTypes", null); diff --git a/src/test/java/io/github/mtrevisan/boxon/helpers/StringHelperTest.java b/src/test/java/io/github/mtrevisan/boxon/helpers/StringHelperTest.java index 34ba7c02c..87ac8dda1 100644 --- a/src/test/java/io/github/mtrevisan/boxon/helpers/StringHelperTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/helpers/StringHelperTest.java @@ -36,7 +36,7 @@ private StringHelperTest(){} @Test void byteArrayToHexString(){ - byte[] array = {0x23, 0x5e, 0x40, 0x03, 0x51, 0x10, 0x42, 0x06}; + byte[] array = {0x23, 0x5E, 0x40, 0x03, 0x51, 0x10, 0x42, 0x06}; String hex = StringHelper.toHexString(array); @@ -45,11 +45,11 @@ void byteArrayToHexString(){ @Test void hexStringToByteArray(){ - Assertions.assertArrayEquals(new byte[]{0x23, 0x5e, 0x40, 0x03, 0x51, 0x10, 0x42, 0x06}, + Assertions.assertArrayEquals(new byte[]{0x23, 0x5E, 0x40, 0x03, 0x51, 0x10, 0x42, 0x06}, StringHelper.hexToByteArray("235e400351104206")); Throwable exception = Assertions.assertThrows(IllegalArgumentException.class, - () -> Assertions.assertArrayEquals(new byte[]{0x23, 0x5e, 0x40, 0x03, 0x51, 0x10, 0x42, 0x06}, + () -> Assertions.assertArrayEquals(new byte[]{0x23, 0x5E, 0x40, 0x03, 0x51, 0x10, 0x42, 0x06}, StringHelper.hexToByteArray("235e40035110420"))); Assertions.assertEquals("Input should be of even length, was 15", exception.getMessage()); } From 98d2d7465e25660d407d25bb058f8bb29872eb67 Mon Sep 17 00:00:00 2001 From: Mauro Trevisan Date: Mon, 11 Mar 2024 15:48:08 +0100 Subject: [PATCH 14/15] java 21 --- README.md | 3 +- pom.xml | 10 ++-- .../io/github/mtrevisan/boxon/core/Core.java | 2 - .../CodecCompositeConfigurationField.java | 4 +- .../codecs/CodecConfigurationSubField.java | 4 +- .../boxon/core/codecs/LoaderCodec.java | 2 +- .../helpers/codecs/NumberWriterManager.java | 8 +-- .../configurations/AlternativeManager.java | 7 +-- .../configurations/ConfigurationHelper.java | 2 +- .../configurations/ConfigurationMessage.java | 1 + .../helpers/configurations/PlainManager.java | 10 ++-- .../configurations/ValidationHelper.java | 4 +- .../descriptors/AnnotationDescriptor.java | 2 +- .../core/helpers/extractors/JSONPath.java | 8 +-- .../core/helpers/templates/Template.java | 10 +--- .../core/parsers/LoaderConfiguration.java | 2 +- .../boxon/core/parsers/LoaderTemplate.java | 2 +- .../boxon/core/parsers/ParserContext.java | 8 +-- .../parsers/matchers/BNDMPatternMatcher.java | 2 +- .../parsers/matchers/KMPPatternMatcher.java | 2 +- .../parsers/matchers/KRPatternMatcher.java | 2 +- .../boxon/exceptions/AnnotationException.java | 3 + .../boxon/exceptions/CodecException.java | 3 + .../exceptions/ConfigurationException.java | 3 + .../boxon/exceptions/DecodeException.java | 3 + .../boxon/exceptions/EncodeException.java | 3 + .../boxon/exceptions/FieldException.java | 2 + .../boxon/exceptions/JSONPathException.java | 3 + .../boxon/exceptions/TemplateException.java | 3 + .../mtrevisan/boxon/helpers/Evaluator.java | 4 +- .../boxon/helpers/GenericHelper.java | 12 ++-- .../boxon/helpers/ReflectionHelper.java | 4 -- .../mtrevisan/boxon/helpers/StringHelper.java | 19 ++----- .../boxon/helpers/TextStatistics.java | 14 ++++- .../mtrevisan/boxon/io/ParserDataType.java | 4 +- .../mtrevisan/boxon/logs/EventListener.java | 2 +- .../mtrevisan/boxon/logs/EventLogger.java | 3 +- .../boxon/semanticversioning/Version.java | 7 +-- .../semanticversioning/VersionException.java | 3 + .../boxon/MapIterationSpeedTest.java | 55 ------------------- .../boxon/core/codecs/CodecIntegerTest.java | 4 +- .../boxon/core/parsers/TemplateTest.java | 2 +- .../boxon/semanticversioning/VersionTest.java | 8 --- .../boxon/utils/MultithreadingHelper.java | 48 ++++++++-------- 44 files changed, 127 insertions(+), 180 deletions(-) delete mode 100644 src/test/java/io/github/mtrevisan/boxon/MapIterationSpeedTest.java diff --git a/README.md b/README.md index 23a5e086c..c3bf0bb14 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ Get them [here](https://github.com/mtrevisan/Boxon/releases/). ### Maven dependency -In order to include Boxon in a Maven project add the following dependency to your pom.xml (Java 11 required). +In order to include Boxon in a Maven project add the following dependency to your pom.xml (Java 21 required). Replace `x.y.z` below int the version tag with the latest [release number](https://github.com/mtrevisan/Boxon/releases). @@ -1543,6 +1543,7 @@ Pull requests are welcomed. - added method to map a POJO into a `Map` into `ReflectionHelper`. - added method `Configurator.composeConfiguration` accepting a POJO. - corrected errors in the documentation. +- migrated from java 11 to java 21 for performance. ### version 3.1.2 - 20240302 diff --git a/pom.xml b/pom.xml index 65401123d..40df0fa41 100644 --- a/pom.xml +++ b/pom.xml @@ -50,9 +50,9 @@ UTF-8 UTF-8 - 11 - 11 - 11 + 21 + 21 + 21 -html5 @@ -76,7 +76,7 @@ - 4.8.165 + 4.8.168 @@ -90,7 +90,7 @@ 2.0.12 - 1.5.2 + 1.5.3 diff --git a/src/main/java/io/github/mtrevisan/boxon/core/Core.java b/src/main/java/io/github/mtrevisan/boxon/core/Core.java index e28be4174..6e7f285fd 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/Core.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/Core.java @@ -38,10 +38,8 @@ import io.github.mtrevisan.boxon.logs.EventListener; import java.lang.reflect.Method; -import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.Random; /** diff --git a/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecCompositeConfigurationField.java b/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecCompositeConfigurationField.java index 5c8f6d65d..f59e6de93 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecCompositeConfigurationField.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecCompositeConfigurationField.java @@ -54,8 +54,8 @@ public void encode(final BitWriterInterface writer, final Annotation annotation, value = ParserDataType.getValueOrSelf((Class)fieldType, value); if(value != null){ - if(value instanceof String) - writer.putText((String)value, charset); + if(value instanceof String v) + writer.putText(v, charset); else throw ConfigurationException.create("Cannot handle this type of field: {}, please report to the developer", value.getClass().getSimpleName()); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecConfigurationSubField.java b/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecConfigurationSubField.java index 4bed182dd..6b69932db 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecConfigurationSubField.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/codecs/CodecConfigurationSubField.java @@ -44,10 +44,10 @@ public Object decode(final BitReaderInterface reader, final Annotation annotatio @Override public void encode(final BitWriterInterface writer, final Annotation annotation, final Object charset, final Object value) throws ConfigurationException{ - if(!(value instanceof String)) + if(!(value instanceof String v)) throw ConfigurationException.create("Cannot handle this type of field: {}", value.getClass().getSimpleName()); - writer.putText((String)value, (Charset)charset); + writer.putText(v, (Charset)charset); } } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/codecs/LoaderCodec.java b/src/main/java/io/github/mtrevisan/boxon/core/codecs/LoaderCodec.java index e00b4d541..9a7671ad3 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/codecs/LoaderCodec.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/codecs/LoaderCodec.java @@ -178,7 +178,7 @@ private void addCodecsInner(final CodecInterface... codecs){ } private void addCodecInner(final CodecInterface codec){ - final Class codecType = GenericHelper.resolveGenericTypes(codec.getClass(), CodecInterface.class).get(0); + final Class codecType = GenericHelper.resolveGenericTypes(codec.getClass(), CodecInterface.class).getFirst(); codecs.put(codecType, codec); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/codecs/NumberWriterManager.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/codecs/NumberWriterManager.java index df538e1d3..c2c53da75 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/codecs/NumberWriterManager.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/codecs/NumberWriterManager.java @@ -62,10 +62,10 @@ public void put(final Object value){ : bi.toString(radix)); } } - else if(value instanceof BigDecimal) - writer.putText(((BigDecimal)value).toPlainString()); - else if(value instanceof BigInteger) - writer.putText(((BigInteger)value).toString(radix)); + else if(value instanceof BigDecimal v) + writer.putText(v.toPlainString()); + else if(value instanceof BigInteger v) + writer.putText(v.toString(radix)); } } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/AlternativeManager.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/AlternativeManager.java index c0543db2c..156dfbf05 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/AlternativeManager.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/AlternativeManager.java @@ -193,8 +193,7 @@ private Map extractMap(final Class fieldType) throws Configur } @SuppressWarnings("DuplicatedCode") - private static Map extractMap(final AlternativeSubField binding, final Class fieldType) throws ConfigurationException, - CodecException{ + private static Map extractMap(final AlternativeSubField binding, final Class fieldType) throws ConfigurationException{ final Map map = new HashMap<>(7); ConfigurationHelper.putIfNotEmpty(ConfigurationKey.LONG_DESCRIPTION, binding.longDescription(), map); @@ -232,8 +231,8 @@ public Object convertValue(final Field field, final String dataKey, Object dataV final AlternativeSubField fieldBinding = extractField(protocol); if(fieldBinding != null){ final Class fieldType = field.getType(); - if(dataValue instanceof String) - dataValue = ParserDataType.getValue(fieldType, (String)dataValue); + if(dataValue instanceof String v) + dataValue = ParserDataType.getValue(fieldType, v); final ConfigFieldData configData = ConfigFieldDataBuilder.create(field, annotation); ValidationHelper.validatePattern(configData, dataValue); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationHelper.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationHelper.java index 32de69c47..b2745aca2 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationHelper.java @@ -64,7 +64,7 @@ public static void putIfNotEmpty(final ConfigurationKey key, final Object value, } private static boolean isValidValue(final Object value){ - return (value != null && (!(value instanceof CharSequence) || !StringHelper.isBlank((CharSequence)value))); + return (value != null && (!(value instanceof CharSequence v) || !StringHelper.isBlank(v))); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationMessage.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationMessage.java index 8e71d54b8..f36ec28dd 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationMessage.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ConfigurationMessage.java @@ -102,6 +102,7 @@ private static void removeDuplicates(final Iterable protocolVersions){ final Iterator itr = protocolVersions.iterator(); while(itr.hasNext()){ final String current = itr.next(); + if(current.equals(previous)) itr.remove(); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/PlainManager.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/PlainManager.java index 8e1533d40..fab1fc4e3 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/PlainManager.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/PlainManager.java @@ -138,8 +138,8 @@ public Object convertValue(final Field field, final String dataKey, Object dataV final Class enumeration = annotation.enumeration(); if(ConfigFieldData.hasEnumeration(enumeration)) dataValue = extractEnumerationValue(dataKey, dataValue, field, enumeration); - else if(dataValue instanceof String) - dataValue = ParserDataType.getValue(fieldType, (String)dataValue); + else if(dataValue instanceof String v) + dataValue = ParserDataType.getValue(fieldType, v); } return dataValue; } @@ -149,8 +149,8 @@ private static Object extractEnumerationValue(final String dataKey, Object dataV final Class fieldType = field.getType(); //convert `or` between enumerations - if(dataValue instanceof String) - dataValue = ConfigurationHelper.extractEnumerationValue(fieldType, (String)dataValue, enumeration); + if(dataValue instanceof String v) + dataValue = ConfigurationHelper.extractEnumerationValue(fieldType, v, enumeration); validateEnumerationValue(dataKey, dataValue, enumeration, fieldType); @@ -170,7 +170,7 @@ private static void validateEnumerationValue(final String dataKey, final Object throw EncodeException.create("Data value incompatible with field type {}; found {}[], expected {}[] for enumeration type", dataKey, componentType, enumeration.getSimpleName()); } - else if(!enumeration.isInstance(dataValue) || dataValue instanceof String && !StringHelper.isBlank((CharSequence)dataValue)) + else if(!enumeration.isInstance(dataValue) || dataValue instanceof String v && !StringHelper.isBlank(v)) throw EncodeException.create("Data value incompatible with field type {}; found {}, expected {} for enumeration type", dataKey, dataValueClass, enumeration.getSimpleName()); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ValidationHelper.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ValidationHelper.java index 43b11189a..5a525b8d9 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ValidationHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/configurations/ValidationHelper.java @@ -129,7 +129,7 @@ static void validateMinMaxValues(final ConfigFieldData field, final Object dataV } } - private static Number validateMinValue(final ConfigFieldData field, final Object def) throws AnnotationException, CodecException{ + private static Number validateMinValue(final ConfigFieldData field, final Object def) throws AnnotationException{ Number min = null; final String minValue = field.getMinValue(); if(!StringHelper.isBlank(minValue)){ @@ -147,7 +147,7 @@ private static Number validateMinValue(final ConfigFieldData field, final Object return min; } - private static Number validateMaxValue(final ConfigFieldData field, final Object def) throws AnnotationException, CodecException{ + private static Number validateMaxValue(final ConfigFieldData field, final Object def) throws AnnotationException{ Number max = null; final String maxValue = field.getMaxValue(); if(!StringHelper.isBlank(maxValue)){ diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/descriptors/AnnotationDescriptor.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/descriptors/AnnotationDescriptor.java index 411ab43dc..291b91300 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/descriptors/AnnotationDescriptor.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/descriptors/AnnotationDescriptor.java @@ -447,7 +447,7 @@ private static void describeAlternatives(final ConverterChoices.ConverterChoice[ * @param map The map in which to load the key-value pair. */ public static void putIfNotEmpty(final DescriberKey key, final Object value, @SuppressWarnings("BoundedWildcard") final Map map){ - if(value != null && (!(value instanceof String) || !StringHelper.isBlank((CharSequence)value))) + if(value != null && (!(value instanceof String v) || !StringHelper.isBlank(v))) map.put(key.toString(), value); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/extractors/JSONPath.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/extractors/JSONPath.java index 37c97aa2c..b991a82f6 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/extractors/JSONPath.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/extractors/JSONPath.java @@ -186,15 +186,15 @@ private static String toJSONPath(final String[] path){ } private static Object extractPath(final Object data, final Integer idx){ - return (data instanceof List - ? ((List)data).get(idx) + return (data instanceof List lst + ? lst.get(idx) : Array.get(data, idx)); } private static Object extractPath(final Object data, final String currentPath) throws NoSuchFieldException{ final Object nextData; - if(data instanceof Map) - nextData = ((Map)data).get(currentPath); + if(data instanceof Map m) + nextData = m.get(currentPath); else{ final Field currentField = data.getClass().getDeclaredField(currentPath); currentField.setAccessible(true); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/Template.java b/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/Template.java index 58676f720..dcbe61cc8 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/Template.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/helpers/templates/Template.java @@ -48,18 +48,10 @@ */ public final class Template{ - private static final class Pair{ - private final List boundedFields; - private final List evaluatedFields; - + private record Pair(List boundedFields, List evaluatedFields){ private static Pair of(final List boundedFields, final List evaluatedFields){ return new Pair(boundedFields, evaluatedFields); } - - private Pair(final List boundedFields, final List evaluatedFields){ - this.boundedFields = boundedFields; - this.evaluatedFields = evaluatedFields; - } } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderConfiguration.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderConfiguration.java index 1ed97cdd3..161efed8d 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderConfiguration.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderConfiguration.java @@ -241,7 +241,7 @@ static Object getConfigurationWithDefaults(final ConfigurationMessage configu dataValue = manager.convertValue(foundField.getField(), dataKey, dataValue, protocol); ReflectionHelper.setValue(configurationObject, foundField.getField(), dataValue); - if(dataValue instanceof String && !((String)dataValue).isEmpty() || dataValue != null) + if(dataValue != null) mandatoryFields.remove(foundField); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderTemplate.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderTemplate.java index e919faecb..f617cc78f 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderTemplate.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/LoaderTemplate.java @@ -322,7 +322,7 @@ private static int findNextMessageIndex(final BitReaderInterface reader, final M //select the minimum index with a valid template for(int i = 0, length = messageStarts.length; i < length; i ++){ final int offset = searchNextSequence(reader, messageStarts[i].getBytes(charset)); - if(offset >= 0 && (minOffset < 0 || offset < minOffset)) + if(offset >= 0 && !(0 <= minOffset && minOffset <= offset)) minOffset = offset; } return minOffset; diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/ParserContext.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/ParserContext.java index cfc115d42..6dad83786 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/ParserContext.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/ParserContext.java @@ -95,10 +95,10 @@ void setField(final Object field){ } Object getFieldValue(){ - if(field instanceof BoundedField) - return ((BoundedField)field).getFieldValue(currentObject); - if(field instanceof ConfigField) - return ((ConfigField)field).getFieldValue(currentObject); + if(field instanceof BoundedField f) + return f.getFieldValue(currentObject); + if(field instanceof ConfigField f) + return f.getFieldValue(currentObject); throw new IllegalArgumentException("Field not of type " + BoundedField.class.getSimpleName() + " or " + ConfigField.class.getSimpleName()); diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/BNDMPatternMatcher.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/BNDMPatternMatcher.java index 684ba7aae..d9d593bf1 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/BNDMPatternMatcher.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/BNDMPatternMatcher.java @@ -48,7 +48,7 @@ */ public final class BNDMPatternMatcher implements PatternMatcher{ - private static class SingletonHelper{ + private static final class SingletonHelper{ private static final PatternMatcher INSTANCE = new BNDMPatternMatcher(); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/KMPPatternMatcher.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/KMPPatternMatcher.java index 63d263344..087758918 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/KMPPatternMatcher.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/KMPPatternMatcher.java @@ -39,7 +39,7 @@ */ public final class KMPPatternMatcher implements PatternMatcher{ - private static class SingletonHelper{ + private static final class SingletonHelper{ private static final PatternMatcher INSTANCE = new KMPPatternMatcher(); } diff --git a/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/KRPatternMatcher.java b/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/KRPatternMatcher.java index 7a34a606b..16aa91fd3 100644 --- a/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/KRPatternMatcher.java +++ b/src/main/java/io/github/mtrevisan/boxon/core/parsers/matchers/KRPatternMatcher.java @@ -38,7 +38,7 @@ */ public final class KRPatternMatcher implements PatternMatcher{ - private static class SingletonHelper{ + private static final class SingletonHelper{ private static final PatternMatcher INSTANCE = new KRPatternMatcher(); } diff --git a/src/main/java/io/github/mtrevisan/boxon/exceptions/AnnotationException.java b/src/main/java/io/github/mtrevisan/boxon/exceptions/AnnotationException.java index 7ab7a416e..5e2680530 100644 --- a/src/main/java/io/github/mtrevisan/boxon/exceptions/AnnotationException.java +++ b/src/main/java/io/github/mtrevisan/boxon/exceptions/AnnotationException.java @@ -26,12 +26,15 @@ import io.github.mtrevisan.boxon.helpers.StringHelper; +import java.io.Serial; + /** * Thrown if an annotation is not well formatted. */ public final class AnnotationException extends FieldException{ + @Serial private static final long serialVersionUID = 6429044852678473069L; diff --git a/src/main/java/io/github/mtrevisan/boxon/exceptions/CodecException.java b/src/main/java/io/github/mtrevisan/boxon/exceptions/CodecException.java index de82fefea..7a048b32e 100644 --- a/src/main/java/io/github/mtrevisan/boxon/exceptions/CodecException.java +++ b/src/main/java/io/github/mtrevisan/boxon/exceptions/CodecException.java @@ -26,12 +26,15 @@ import io.github.mtrevisan.boxon.helpers.StringHelper; +import java.io.Serial; + /** * Thrown if no codec is found. */ public final class CodecException extends FieldException{ + @Serial private static final long serialVersionUID = 2879230296103139872L; diff --git a/src/main/java/io/github/mtrevisan/boxon/exceptions/ConfigurationException.java b/src/main/java/io/github/mtrevisan/boxon/exceptions/ConfigurationException.java index a858e1be6..d46a18b30 100644 --- a/src/main/java/io/github/mtrevisan/boxon/exceptions/ConfigurationException.java +++ b/src/main/java/io/github/mtrevisan/boxon/exceptions/ConfigurationException.java @@ -26,12 +26,15 @@ import io.github.mtrevisan.boxon.helpers.StringHelper; +import java.io.Serial; + /** * Thrown if a configuration is not well formatted. */ public final class ConfigurationException extends FieldException{ + @Serial private static final long serialVersionUID = -1344270549034327649L; diff --git a/src/main/java/io/github/mtrevisan/boxon/exceptions/DecodeException.java b/src/main/java/io/github/mtrevisan/boxon/exceptions/DecodeException.java index 973db8f89..7051d0606 100644 --- a/src/main/java/io/github/mtrevisan/boxon/exceptions/DecodeException.java +++ b/src/main/java/io/github/mtrevisan/boxon/exceptions/DecodeException.java @@ -26,6 +26,8 @@ import io.github.mtrevisan.boxon.helpers.JavaHelper; +import java.io.Serial; + /** * Thrown if a parsing (decoding) went bad. @@ -33,6 +35,7 @@ @SuppressWarnings("unused") public final class DecodeException extends Exception{ + @Serial private static final long serialVersionUID = 5375434179637246605L; diff --git a/src/main/java/io/github/mtrevisan/boxon/exceptions/EncodeException.java b/src/main/java/io/github/mtrevisan/boxon/exceptions/EncodeException.java index fc714ae9a..4a06fdcf7 100644 --- a/src/main/java/io/github/mtrevisan/boxon/exceptions/EncodeException.java +++ b/src/main/java/io/github/mtrevisan/boxon/exceptions/EncodeException.java @@ -27,12 +27,15 @@ import io.github.mtrevisan.boxon.helpers.JavaHelper; import io.github.mtrevisan.boxon.helpers.StringHelper; +import java.io.Serial; + /** * Thrown if a composition (encoding) went bad. */ public final class EncodeException extends Exception{ + @Serial private static final long serialVersionUID = 4385865753761318892L; diff --git a/src/main/java/io/github/mtrevisan/boxon/exceptions/FieldException.java b/src/main/java/io/github/mtrevisan/boxon/exceptions/FieldException.java index 1d3a71c4e..6ad08fa8a 100644 --- a/src/main/java/io/github/mtrevisan/boxon/exceptions/FieldException.java +++ b/src/main/java/io/github/mtrevisan/boxon/exceptions/FieldException.java @@ -26,6 +26,7 @@ import io.github.mtrevisan.boxon.helpers.JavaHelper; +import java.io.Serial; import java.lang.reflect.Field; @@ -34,6 +35,7 @@ */ public class FieldException extends Exception{ + @Serial private static final long serialVersionUID = -8863756843240934380L; diff --git a/src/main/java/io/github/mtrevisan/boxon/exceptions/JSONPathException.java b/src/main/java/io/github/mtrevisan/boxon/exceptions/JSONPathException.java index c29fe04e7..25fcc1f7d 100644 --- a/src/main/java/io/github/mtrevisan/boxon/exceptions/JSONPathException.java +++ b/src/main/java/io/github/mtrevisan/boxon/exceptions/JSONPathException.java @@ -26,12 +26,15 @@ import io.github.mtrevisan.boxon.helpers.StringHelper; +import java.io.Serial; + /** * Represents an error in a JSON path. */ public final class JSONPathException extends Exception{ + @Serial private static final long serialVersionUID = 8273242566993098760L; diff --git a/src/main/java/io/github/mtrevisan/boxon/exceptions/TemplateException.java b/src/main/java/io/github/mtrevisan/boxon/exceptions/TemplateException.java index ffeb1774f..40ce87508 100644 --- a/src/main/java/io/github/mtrevisan/boxon/exceptions/TemplateException.java +++ b/src/main/java/io/github/mtrevisan/boxon/exceptions/TemplateException.java @@ -26,12 +26,15 @@ import io.github.mtrevisan.boxon.helpers.StringHelper; +import java.io.Serial; + /** * Thrown if a template is not well formatted. */ public final class TemplateException extends FieldException{ + @Serial private static final long serialVersionUID = 7585594459004613305L; diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/Evaluator.java b/src/main/java/io/github/mtrevisan/boxon/helpers/Evaluator.java index 6d6527c69..235083d3a 100644 --- a/src/main/java/io/github/mtrevisan/boxon/helpers/Evaluator.java +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/Evaluator.java @@ -206,9 +206,9 @@ private static boolean isPositiveInteger(final CharSequence text){ } - private static class ReflectiveProperty extends ReflectivePropertyAccessor{ + private static final class ReflectiveProperty extends ReflectivePropertyAccessor{ @Override - protected final Field findField(final String name, Class cls, final boolean mustBeStatic){ + protected Field findField(final String name, Class cls, final boolean mustBeStatic){ Field field = null; while(field == null && cls != null && cls != Object.class){ field = findFieldInClass(name, cls, mustBeStatic); diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/GenericHelper.java b/src/main/java/io/github/mtrevisan/boxon/helpers/GenericHelper.java index 96aa29a71..9a579a5c1 100644 --- a/src/main/java/io/github/mtrevisan/boxon/helpers/GenericHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/GenericHelper.java @@ -102,10 +102,10 @@ private static List> processAncestors(final Class offs final List> types = new ArrayList<>(0); while(!ancestorsQueue.isEmpty()){ final Type ancestorType = ancestorsQueue.poll(); - if(ancestorType instanceof ParameterizedType) + if(ancestorType instanceof ParameterizedType t) //ancestor is parameterized: process only if the raw type matches the base class - types.addAll(manageParameterizedAncestor((ParameterizedType)ancestorType, base, typeVariables)); - else if(ancestorType instanceof Class && base.isAssignableFrom((Class)ancestorType)) + types.addAll(manageParameterizedAncestor(t, base, typeVariables)); + else if(ancestorType instanceof Class c && base.isAssignableFrom(c)) //ancestor is non-parameterized: process only if it matches the base class ancestorsQueue.add(ancestorType); } @@ -129,7 +129,7 @@ private static List> manageParameterizedAncestor(final Parameterize final Map typeVariables){ final List> types = new ArrayList<>(0); final Type rawType = ancestorType.getRawType(); - if(rawType instanceof Class && base.isAssignableFrom((Class)rawType)){ + if(rawType instanceof Class c && base.isAssignableFrom(c)){ final Class[] resolvedTypes = populateResolvedTypes(ancestorType, typeVariables); final List> result = resolveGenericTypes((Class)rawType, base, resolvedTypes); types.addAll(result); @@ -176,8 +176,8 @@ private static Queue extractAncestors(final Class offspri } private static Type resolveArgumentType(final Map typeVariables, final Type actualTypeArgument){ - final String key = (actualTypeArgument instanceof TypeVariable - ? ((TypeVariable)actualTypeArgument).getName() + final String key = (actualTypeArgument instanceof TypeVariable v + ? v.getName() : null); return typeVariables.getOrDefault(key, actualTypeArgument); } diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java b/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java index bc933ee52..2b59eb767 100644 --- a/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/ReflectionHelper.java @@ -24,19 +24,15 @@ */ package io.github.mtrevisan.boxon.helpers; -import org.springframework.util.StopWatch; - import java.lang.reflect.Field; import java.lang.reflect.InaccessibleObjectException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Random; import java.util.function.BiConsumer; diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/StringHelper.java b/src/main/java/io/github/mtrevisan/boxon/helpers/StringHelper.java index 7b18b0fa6..6fd7c6c6c 100644 --- a/src/main/java/io/github/mtrevisan/boxon/helpers/StringHelper.java +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/StringHelper.java @@ -27,7 +27,6 @@ import org.slf4j.helpers.MessageFormatter; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Locale; @@ -66,20 +65,10 @@ public static String leftPad(final String text, final int size, final char padCh if(pads <= 0) return text; - return repeat(padChar, pads) + text; - } - - /** - * Returns padding using the specified delimiter repeated to a given length. - * - * @param chr Character to repeat. - * @param count Number of times to repeat char. - * @return String with repeated character. - */ - public static String repeat(final char chr, final int count){ - final char[] buf = new char[count]; - Arrays.fill(buf, chr); - return new String(buf); + return new StringBuilder() + .repeat(padChar, pads) + .append(text) + .toString(); } diff --git a/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java b/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java index 04dbe0519..f0f2f633a 100644 --- a/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java +++ b/src/main/java/io/github/mtrevisan/boxon/helpers/TextStatistics.java @@ -26,19 +26,29 @@ */ public final class TextStatistics{ - private final int[] counts = new int[256]; + private final int[] counts = new int[1 << Byte.SIZE]; /** Total number of bytes seen so far. */ private int total; - public void addData(final byte[] buffer, final int offset, final int length){ + public static TextStatistics create(final byte[] buffer){ + return new TextStatistics(buffer, 0, buffer.length); + } + + public static TextStatistics create(final byte[] buffer, final int offset, final int length){ + return new TextStatistics(buffer, offset, length); + } + + + private TextStatistics(final byte[] buffer, final int offset, final int length){ for(int i = 0; i < length; i ++){ counts[buffer[offset + i] & 0xFF] ++; total ++; } } + /** * Checks whether at least one byte was seen and that the bytes that were seen were mostly plain text (i.e. < 2% control, > 90% ASCII * range). diff --git a/src/main/java/io/github/mtrevisan/boxon/io/ParserDataType.java b/src/main/java/io/github/mtrevisan/boxon/io/ParserDataType.java index cc20b3b01..c0a3e70c3 100644 --- a/src/main/java/io/github/mtrevisan/boxon/io/ParserDataType.java +++ b/src/main/java/io/github/mtrevisan/boxon/io/ParserDataType.java @@ -267,8 +267,8 @@ static String describe(){ * @throws CodecException If the value cannot be interpreted as primitive or objective. */ public static Object getValueOrSelf(final Class fieldType, final Object value) throws CodecException{ - return (value instanceof String - ? getValue(fieldType, (String)value) + return (value instanceof String v + ? getValue(fieldType, v) : value); } diff --git a/src/main/java/io/github/mtrevisan/boxon/logs/EventListener.java b/src/main/java/io/github/mtrevisan/boxon/logs/EventListener.java index f941d63a3..e69c70862 100644 --- a/src/main/java/io/github/mtrevisan/boxon/logs/EventListener.java +++ b/src/main/java/io/github/mtrevisan/boxon/logs/EventListener.java @@ -33,7 +33,7 @@ */ public class EventListener{ - private static class SingletonHelper{ + private static final class SingletonHelper{ private static final EventListener INSTANCE = new EventListener(); } diff --git a/src/main/java/io/github/mtrevisan/boxon/logs/EventLogger.java b/src/main/java/io/github/mtrevisan/boxon/logs/EventLogger.java index da9265918..3c1ed5836 100644 --- a/src/main/java/io/github/mtrevisan/boxon/logs/EventLogger.java +++ b/src/main/java/io/github/mtrevisan/boxon/logs/EventLogger.java @@ -33,7 +33,6 @@ import java.util.Collection; import java.util.HashSet; -import java.util.Iterator; import java.util.StringJoiner; @@ -52,7 +51,7 @@ public final class EventLogger extends EventListener{ private static final Logger LOGGER = LoggerFactory.getLogger(EventLogger.class); - private static class SingletonHelper{ + private static final class SingletonHelper{ private static final EventLogger INSTANCE = new EventLogger(); } diff --git a/src/main/java/io/github/mtrevisan/boxon/semanticversioning/Version.java b/src/main/java/io/github/mtrevisan/boxon/semanticversioning/Version.java index 8aae5fd1f..9526ef997 100644 --- a/src/main/java/io/github/mtrevisan/boxon/semanticversioning/Version.java +++ b/src/main/java/io/github/mtrevisan/boxon/semanticversioning/Version.java @@ -221,8 +221,6 @@ private static Integer parseIdentifier(final String[] tokens, final int index, f } private static void validateToken(final String type, final String token) throws VersionException{ - if(hasLeadingZeros(token)) - throw VersionException.create("The {} identifier MUST NOT contain leading zeros", type); try{ final int number = Integer.parseInt(token); if(number < 0) @@ -629,14 +627,11 @@ public Version setBuild(final String... build) throws VersionException{ } - private static boolean hasLeadingZeros(final CharSequence token){ - return (token.length() > 1 && token.charAt(0) == '0'); - } - private static int getLeastCommonArrayLength(final String[] array1, final String[] array2){ return Math.min(array1.length, array2.length); } + @Override public String toString(){ String message = JavaHelper.EMPTY_STRING; diff --git a/src/main/java/io/github/mtrevisan/boxon/semanticversioning/VersionException.java b/src/main/java/io/github/mtrevisan/boxon/semanticversioning/VersionException.java index 79272f01f..31fb13c39 100644 --- a/src/main/java/io/github/mtrevisan/boxon/semanticversioning/VersionException.java +++ b/src/main/java/io/github/mtrevisan/boxon/semanticversioning/VersionException.java @@ -26,12 +26,15 @@ import io.github.mtrevisan.boxon.helpers.StringHelper; +import java.io.Serial; + /** * Represents an error in a version. */ public final class VersionException extends IllegalArgumentException{ + @Serial private static final long serialVersionUID = 6010765672515345324L; diff --git a/src/test/java/io/github/mtrevisan/boxon/MapIterationSpeedTest.java b/src/test/java/io/github/mtrevisan/boxon/MapIterationSpeedTest.java deleted file mode 100644 index e592b5165..000000000 --- a/src/test/java/io/github/mtrevisan/boxon/MapIterationSpeedTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.mtrevisan.boxon; - -import java.util.HashMap; -import java.util.Map; -import java.util.Random; - - -class MapIterationSpeedTest{ - - public static void main(String[] args) { - // Creazione di una mappa con un gran numero di elementi - Map context = generateTestData(1000000); - - // Test del metodo tradizionale - long startTime = System.currentTimeMillis(); - iterateTraditionally(context); - long traditionalTime = System.currentTimeMillis() - startTime; - System.out.println("Tempo impiegato per l'iterazione tradizionale: " + traditionalTime + " ms"); - - // Test del metodo parallelo - startTime = System.currentTimeMillis(); - iterateInParallel(context); - long parallelTime = System.currentTimeMillis() - startTime; - System.out.println("Tempo impiegato per l'iterazione parallela: " + parallelTime + " ms"); - } - - // Genera una mappa di test con un numero specifico di elementi - private static Map generateTestData(int size) { - Map testData = new HashMap<>(); - Random random = new Random(); - for (int i = 0; i < size; i++) { - testData.put("key" + i, random.nextInt()); - } - return testData; - } - - // Iterazione tradizionale sulla mappa - private static void iterateTraditionally(Map context) { - for (Map.Entry entry : context.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - // Operazioni da eseguire su ogni entry - } - } - - // Iterazione parallela sulla mappa - private static void iterateInParallel(Map context) { - context.entrySet().forEach(entry -> { - String key = entry.getKey(); - Object value = entry.getValue(); - // Operazioni da eseguire su ogni entry - }); - } - -} diff --git a/src/test/java/io/github/mtrevisan/boxon/core/codecs/CodecIntegerTest.java b/src/test/java/io/github/mtrevisan/boxon/core/codecs/CodecIntegerTest.java index 5b1a65a81..dae9387f3 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/codecs/CodecIntegerTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/codecs/CodecIntegerTest.java @@ -515,7 +515,9 @@ private static String rightPad(final String text, final int size, final char pad if(pads <= 0) return text; - return text + StringHelper.repeat(padChar, pads); + return new StringBuilder(text) + .repeat(padChar, pads) + .toString(); } @Test diff --git a/src/test/java/io/github/mtrevisan/boxon/core/parsers/TemplateTest.java b/src/test/java/io/github/mtrevisan/boxon/core/parsers/TemplateTest.java index e63ad74cb..4802269da 100644 --- a/src/test/java/io/github/mtrevisan/boxon/core/parsers/TemplateTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/core/parsers/TemplateTest.java @@ -265,7 +265,7 @@ void inheritance() throws AnnotationException{ List boundedFields = template.getBoundedFields(); Assertions.assertNotNull(boundedFields); Assertions.assertEquals(15, boundedFields.size()); - BoundedField childField = boundedFields.get(boundedFields.size() - 1); + BoundedField childField = boundedFields.getLast(); Assertions.assertNotNull(childField); Assertions.assertEquals("anotherNumberInt", childField.getFieldName()); } diff --git a/src/test/java/io/github/mtrevisan/boxon/semanticversioning/VersionTest.java b/src/test/java/io/github/mtrevisan/boxon/semanticversioning/VersionTest.java index 60b3bb1c8..aa3978b35 100644 --- a/src/test/java/io/github/mtrevisan/boxon/semanticversioning/VersionTest.java +++ b/src/test/java/io/github/mtrevisan/boxon/semanticversioning/VersionTest.java @@ -39,14 +39,6 @@ void shouldParseNormalVersion(){ Assertions.assertEquals("1.0.0", version.toString()); } - @Test - void shouldRaiseErrorIfNumericIdentifierHasLeadingZeros(){ - Throwable exception = Assertions.assertThrows(IllegalArgumentException.class, - () -> Version.of("01.1.0")); - - Assertions.assertEquals("The major identifier MUST NOT contain leading zeros", exception.getMessage()); - } - @Test void shouldParsePreReleaseVersion(){ Version version = Version.of("1.1.0-beta"); diff --git a/src/test/java/io/github/mtrevisan/boxon/utils/MultithreadingHelper.java b/src/test/java/io/github/mtrevisan/boxon/utils/MultithreadingHelper.java index 14f293981..4ba2155d6 100644 --- a/src/test/java/io/github/mtrevisan/boxon/utils/MultithreadingHelper.java +++ b/src/test/java/io/github/mtrevisan/boxon/utils/MultithreadingHelper.java @@ -24,6 +24,7 @@ */ package io.github.mtrevisan.boxon.utils; +import java.lang.reflect.Array; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -42,37 +43,38 @@ private MultithreadingHelper(){} public static void testMultithreading(final Callable fun, final Consumer combiner, final int threadCount) throws ExecutionException, InterruptedException{ - final ExecutorService service = Executors.newFixedThreadPool(threadCount); + try(ExecutorService service = Executors.newFixedThreadPool(threadCount)){ - final CountDownLatch latch = new CountDownLatch(1); - final AtomicBoolean running = new AtomicBoolean(); - final AtomicInteger overlaps = new AtomicInteger(); - @SuppressWarnings("unchecked") - final Future[] futures = new Future[threadCount]; - //assure overlaps happens (cycle until some overlaps happens) - while(overlaps.get() == 0){ - for(int t = 0; t < threadCount; t ++) - futures[t] = service.submit(() -> { - latch.await(); + final CountDownLatch latch = new CountDownLatch(1); + final AtomicBoolean running = new AtomicBoolean(); + final AtomicInteger overlaps = new AtomicInteger(); + @SuppressWarnings("unchecked") + final Future[] futures = (Future[])Array.newInstance(Future.class, threadCount); + //assure overlaps happens (cycle until some overlaps happens) + while(overlaps.get() == 0){ + for(int t = 0; t < threadCount; t++) + futures[t] = service.submit(() -> { + latch.await(); + + if(! running.compareAndSet(false, true)) + overlaps.incrementAndGet(); - if(!running.compareAndSet(false, true)) - overlaps.incrementAndGet(); + final T result = fun.call(); - final T result = fun.call(); + running.set(false); - running.set(false); + return result; + }); - return result; - }); + //start all the thread simultaneously + latch.countDown(); + for(int t = 0; t < threadCount; t ++) + futures[t].get(); + } - //start all the thread simultaneously - latch.countDown(); for(int t = 0; t < threadCount; t ++) - futures[t].get(); + combiner.accept(futures[t].get()); } - - for(int t = 0; t < threadCount; t ++) - combiner.accept(futures[t].get()); } } From 637143a787c86bd24346ae56448f31e919581dfc Mon Sep 17 00:00:00 2001 From: mauro <851903+mtrevisan@users.noreply.github.com> Date: Mon, 11 Mar 2024 21:09:01 +0100 Subject: [PATCH 15/15] prepare for release --- README.md | 35 ++++++++++++++++++----------------- pom.xml | 2 +- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index c3bf0bb14..4ae728c07 100644 --- a/README.md +++ b/README.md @@ -146,21 +146,22 @@ You can get pre-built JARs (usable on JRE 11 or newer) from [Sonatype](https://o 2. [Message composer](#example-composer) 11. [Contributing](#contributing) 12. [Changelog](#changelog) - 1. [version 3.1.2](#changelog-3.1.2) - 2. [version 3.1.1](#changelog-3.1.1) - 3. [version 3.1.0](#changelog-3.1.0) - 4. [version 3.0.2](#changelog-3.0.2) - 5. [version 3.0.1](#changelog-3.0.1) - 6. [version 3.0.0](#changelog-3.0.0) - 7. [version 2.1.2](#changelog-2.1.2) - 8. [version 2.1.1](#changelog-2.1.1) - 9. [version 2.1.0](#changelog-2.1.0) - 10. [version 2.0.0](#changelog-2.0.0) - 11. [version 1.1.0](#changelog-1.1.0) - 12. [version 1.0.0](#changelog-1.0.0) - 13. [version 0.0.2](#changelog-0.0.2) - 14. [version 0.0.1](#changelog-0.0.1) - 15. [version 0.0.0](#changelog-0.0.0) + 1. [version 3.1.3](#changelog-3.1.3) + 2. [version 3.1.2](#changelog-3.1.2) + 3. [version 3.1.1](#changelog-3.1.1) + 4. [version 3.1.0](#changelog-3.1.0) + 5. [version 3.0.2](#changelog-3.0.2) + 6. [version 3.0.1](#changelog-3.0.1) + 7. [version 3.0.0](#changelog-3.0.0) + 8. [version 2.1.2](#changelog-2.1.2) + 9. [version 2.1.1](#changelog-2.1.1) + 10. [version 2.1.0](#changelog-2.1.0) + 11. [version 2.0.0](#changelog-2.0.0) + 12. [version 1.1.0](#changelog-1.1.0) + 13. [version 1.0.0](#changelog-1.0.0) + 14. [version 0.0.2](#changelog-0.0.2) + 15. [version 0.0.1](#changelog-0.0.1) + 16. [version 0.0.0](#changelog-0.0.0) 13. [License](#license)
@@ -1535,12 +1536,12 @@ Pull requests are welcomed. ## Changelog -### version 3.1.3 - 202403?? +### version 3.1.3 - 20240311 - fixed duplicated descriptions. - fixed validation on max value while composing a message. - fixed number not written with the correct radix. - made `shortDescription` mandatory in the annotation, as it should have been. -- added method to map a POJO into a `Map` into `ReflectionHelper`. +- added method to map a POJO into a `Map` in `ReflectionHelper`. - added method `Configurator.composeConfiguration` accepting a POJO. - corrected errors in the documentation. - migrated from java 11 to java 21 for performance. diff --git a/pom.xml b/pom.xml index 40df0fa41..d45087698 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.github.mtrevisan boxon - 3.1.2-SNAPSHOT + 3.1.3-SNAPSHOT jar