From db9ea45530a2c2c81fe53660fc8ee31ed74705b0 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Mon, 30 Mar 2026 12:06:52 +0200 Subject: [PATCH 1/7] Add: Exception to throw when required Parameter is not found --- .../network/parser/MissingParameterException.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/MissingParameterException.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/MissingParameterException.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/MissingParameterException.java new file mode 100644 index 0000000..85080ef --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/MissingParameterException.java @@ -0,0 +1,14 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network.parser; + +public class MissingParameterException extends RuntimeException { + private final String parameterKey; + + public MissingParameterException(String message, String parameterKey) { + super(message); + this.parameterKey = parameterKey; + } + + public String getParameterKey() { + return parameterKey; + } +} From ed914941297f8b0a6c692bddadb23cc51f4705da Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Mon, 30 Mar 2026 12:38:44 +0200 Subject: [PATCH 2/7] Add: Exception to throw when error during parsing occurs --- .../server/network/parser/ParameterParseException.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ParameterParseException.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ParameterParseException.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ParameterParseException.java new file mode 100644 index 0000000..e4e31e7 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ParameterParseException.java @@ -0,0 +1,7 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network.parser; + +public class ParameterParseException extends RuntimeException { + public ParameterParseException(String message, Throwable cause) { + super(message, cause); + } +} From 160ec55957d4aaf9c0dabd52f9ec35d07adc59d9 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Mon, 30 Mar 2026 12:39:37 +0200 Subject: [PATCH 3/7] Add: ThrowingParser interface used to implicitly convert --- .../cs108/casono/server/network/parser/ThrowingParser.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ThrowingParser.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ThrowingParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ThrowingParser.java new file mode 100644 index 0000000..52f76b0 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ThrowingParser.java @@ -0,0 +1,6 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network.parser; + +@FunctionalInterface +interface ThrowingParser { + T parse(String value) throws Exception; +} \ No newline at end of file From 2feb0579e2b054ee1da30a0ebf5c3617463f4754 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Mon, 30 Mar 2026 12:40:59 +0200 Subject: [PATCH 4/7] Add: RequestParameterAccessor as utility class for simplified access of parameters of PrimitiveRequest --- .../parser/RequestParameterAccessor.java | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java new file mode 100644 index 0000000..ce5ddd8 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java @@ -0,0 +1,59 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network.parser; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class RequestParameterAccessor { + private final Map index; + + public RequestParameterAccessor(List parameters) { + this.index = parameters.stream() + .collect(Collectors.toUnmodifiableMap( + Parameter::key, + Parameter::value + )); + } + + public String require(String key) throws MissingParameterException { + String value = index.get(key); + if (value == null) { + throw new MissingParameterException("Required parameter with key '" + key + "' is missing.", key); + } + return value; + } + + public T require(String key, ThrowingParser parser) throws MissingParameterException, ParameterParseException { + String value = require(key); + try { + return parser.parse(value); + } catch (Exception e) { + throw new ParameterParseException("Error while parsing with specified parser", e); + } + } + + public String optional(String key, String defaultValue) { + String value = index.get(key); + if (value == null) { + return defaultValue; + } + return value; + } + + public T optional(String key, T defaultValue, ThrowingParser parser) throws ParameterParseException { + String value = index.get(key); + if (value == null) { + return defaultValue; + } + + try { + return parser.parse(value); + } catch (Exception e) { + throw new ParameterParseException("Error while parsing with specified parser", e); + } + } + + public boolean containsKey(String key) { + return index.containsKey(key); + } +} From e6b62726bd52d65dff7a9f2862d1f22eb32336ec Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Mon, 30 Mar 2026 12:56:15 +0200 Subject: [PATCH 5/7] Docs: Add JavaDoc to all new interfaces, classes and methods Co-authored-by: Copilot --- .../parser/MissingParameterException.java | 12 +++++ .../parser/ParameterParseException.java | 7 +++ .../parser/RequestParameterAccessor.java | 51 +++++++++++++++++++ .../server/network/parser/ThrowingParser.java | 14 ++++- 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/MissingParameterException.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/MissingParameterException.java index 85080ef..55e32fa 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/MissingParameterException.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/MissingParameterException.java @@ -1,13 +1,25 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.parser; +/** Exception thrown when a required parameter key is not found. */ public class MissingParameterException extends RuntimeException { private final String parameterKey; + /** + * Creates a new exception for a missing required parameter. + * + * @param message human-readable description of the missing parameter + * @param parameterKey key of the parameter that could not be found + */ public MissingParameterException(String message, String parameterKey) { super(message); this.parameterKey = parameterKey; } + /** + * Returns the missing parameter key. + * + * @return key of the parameter that could not be found + */ public String getParameterKey() { return parameterKey; } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ParameterParseException.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ParameterParseException.java index e4e31e7..af727bd 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ParameterParseException.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ParameterParseException.java @@ -1,6 +1,13 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.parser; +/** Exception thrown when a parameter value cannot be converted to the requested type. */ public class ParameterParseException extends RuntimeException { + /** + * Creates a new parse exception with a root cause. + * + * @param message human-readable description of the parsing failure + * @param cause original exception thrown during parsing + */ public ParameterParseException(String message, Throwable cause) { super(message, cause); } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java index ce5ddd8..cb1998d 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java @@ -4,9 +4,20 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +/** + * Provides typed access to a request's parameters by indexing them by key. + * + *

Supports required and optional lookups, with optional conversion from {@link String} values to + * domain-specific types via parser functions. + */ public class RequestParameterAccessor { private final Map index; + /** + * Creates an accessor + * + * @param parameters to use + */ public RequestParameterAccessor(List parameters) { this.index = parameters.stream() .collect(Collectors.toUnmodifiableMap( @@ -15,6 +26,13 @@ public class RequestParameterAccessor { )); } + /** + * Returns the raw value for a required parameter key. + * + * @param key parameter key to look up + * @return raw parameter value + * @throws MissingParameterException if no parameter with the given key exists + */ public String require(String key) throws MissingParameterException { String value = index.get(key); if (value == null) { @@ -23,6 +41,16 @@ public class RequestParameterAccessor { return value; } + /** + * Returns a parsed value for a required parameter key. + * + * @param key parameter key to look up + * @param parser parser used to convert the raw value + * @param target type returned by the parser + * @return parsed parameter value + * @throws MissingParameterException if no parameter with the given key exists + * @throws ParameterParseException if parsing the raw value fails + */ public T require(String key, ThrowingParser parser) throws MissingParameterException, ParameterParseException { String value = require(key); try { @@ -32,6 +60,13 @@ public class RequestParameterAccessor { } } + /** + * Returns the raw value for a parameter key or the provided default value if missing. + * + * @param key parameter key to look up + * @param defaultValue value returned when the key does not exist + * @return found parameter value or {@code defaultValue} if absent + */ public String optional(String key, String defaultValue) { String value = index.get(key); if (value == null) { @@ -40,6 +75,16 @@ public class RequestParameterAccessor { return value; } + /** + * Returns a parsed value for a parameter key or the provided default value if missing. + * + * @param key parameter key to look up + * @param defaultValue value returned when the key does not exist + * @param parser parser used to convert the raw value + * @param target type returned by the parser + * @return parsed parameter value or {@code defaultValue} if absent + * @throws ParameterParseException if parsing the raw value fails + */ public T optional(String key, T defaultValue, ThrowingParser parser) throws ParameterParseException { String value = index.get(key); if (value == null) { @@ -53,6 +98,12 @@ public class RequestParameterAccessor { } } + /** + * Checks whether a parameter with the given key exists. + * + * @param key parameter key to check + * @return {@code true} if the key exists, otherwise {@code false} + */ public boolean containsKey(String key) { return index.containsKey(key); } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ThrowingParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ThrowingParser.java index 52f76b0..af1ec9b 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ThrowingParser.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ThrowingParser.java @@ -1,6 +1,18 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.parser; +/** + * Functional parser interface used to convert a raw string parameter into a target type. + * + * @param target type produced by the parser + */ @FunctionalInterface interface ThrowingParser { + /** + * Parses the provided raw parameter value. + * + * @param value raw parameter value + * @return parsed value + * @throws Exception if the value cannot be parsed + */ T parse(String value) throws Exception; -} \ No newline at end of file +} From d990e37a686868ec9ba91a0289a1ece308c45054 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Mon, 30 Mar 2026 13:01:42 +0200 Subject: [PATCH 6/7] Add: parameterKey field to ParameterParseException (docstrings included) --- .../network/parser/ParameterParseException.java | 15 ++++++++++++++- .../network/parser/RequestParameterAccessor.java | 4 ++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ParameterParseException.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ParameterParseException.java index af727bd..97628a6 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ParameterParseException.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/ParameterParseException.java @@ -2,13 +2,26 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.parser; /** Exception thrown when a parameter value cannot be converted to the requested type. */ public class ParameterParseException extends RuntimeException { + private final String parameterKey; + /** * Creates a new parse exception with a root cause. * * @param message human-readable description of the parsing failure + * @param parameterKey key for whose value the error occured * @param cause original exception thrown during parsing */ - public ParameterParseException(String message, Throwable cause) { + public ParameterParseException(String message, String parameterKey, Throwable cause) { super(message, cause); + this.parameterKey = parameterKey; + } + + /** + * Returns the missing parameter key. + * + * @return key for whose value the error occured + */ + public String getParameterKey() { + return parameterKey; } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java index cb1998d..79ceac6 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java @@ -56,7 +56,7 @@ public class RequestParameterAccessor { try { return parser.parse(value); } catch (Exception e) { - throw new ParameterParseException("Error while parsing with specified parser", e); + throw new ParameterParseException("Error while parsing '" + key + "' with specified parser", key, e); } } @@ -94,7 +94,7 @@ public class RequestParameterAccessor { try { return parser.parse(value); } catch (Exception e) { - throw new ParameterParseException("Error while parsing with specified parser", e); + throw new ParameterParseException("Error while parsing '" + key + "' with specified parser", key, e); } } From 9390c3503ae8cdfaf2591101a22e4dbefc93cb1e Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Mon, 30 Mar 2026 13:02:16 +0200 Subject: [PATCH 7/7] Style: Formatting by Spotless --- .../parser/RequestParameterAccessor.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java index 79ceac6..a79f7b1 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/parser/RequestParameterAccessor.java @@ -19,11 +19,9 @@ public class RequestParameterAccessor { * @param parameters to use */ public RequestParameterAccessor(List parameters) { - this.index = parameters.stream() - .collect(Collectors.toUnmodifiableMap( - Parameter::key, - Parameter::value - )); + this.index = + parameters.stream() + .collect(Collectors.toUnmodifiableMap(Parameter::key, Parameter::value)); } /** @@ -36,7 +34,8 @@ public class RequestParameterAccessor { public String require(String key) throws MissingParameterException { String value = index.get(key); if (value == null) { - throw new MissingParameterException("Required parameter with key '" + key + "' is missing.", key); + throw new MissingParameterException( + "Required parameter with key '" + key + "' is missing.", key); } return value; } @@ -51,7 +50,8 @@ public class RequestParameterAccessor { * @throws MissingParameterException if no parameter with the given key exists * @throws ParameterParseException if parsing the raw value fails */ - public T require(String key, ThrowingParser parser) throws MissingParameterException, ParameterParseException { + public T require(String key, ThrowingParser parser) + throws MissingParameterException, ParameterParseException { String value = require(key); try { return parser.parse(value); @@ -85,7 +85,8 @@ public class RequestParameterAccessor { * @return parsed parameter value or {@code defaultValue} if absent * @throws ParameterParseException if parsing the raw value fails */ - public T optional(String key, T defaultValue, ThrowingParser parser) throws ParameterParseException { + public T optional(String key, T defaultValue, ThrowingParser parser) + throws ParameterParseException { String value = index.get(key); if (value == null) { return defaultValue;