88import java .util .function .Supplier ;
99
1010/**
11- * Provides fluent support to any type of throwable.
11+ * Abstract base class providing a fluent builder pattern for creating and configuring exceptions.
12+ * This class implements a two-stage builder pattern for creating exceptions with customizable
13+ * messages and causes.
14+ *
15+ * <p>This class serves as the foundation for implementing custom exceptions with fluent APIs.
16+ * It provides methods for setting messages, causes, and creating exceptions in a type-safe manner.
1217 */
1318@ NonNullByDefault
1419public abstract class AbstractFluentExceptionSupport <T extends Throwable > implements ExceptionDetailsStage <T > {
@@ -23,42 +28,118 @@ public abstract class AbstractFluentExceptionSupport<T extends Throwable> implem
2328 @ Nullable
2429 private Throwable cause ;
2530
31+ /**
32+ * Creates a new exception builder with a default message of "Something went wrong."
33+ */
2634 protected AbstractFluentExceptionSupport () {
2735 this .defaultMessage = FALLBACK_DEFAULT_MESSAGE ;
2836 }
2937
38+ /**
39+ * Creates a new exception builder with the specified default message.
40+ * This message will be used when no specific message is provided through
41+ * the builder methods.
42+ *
43+ * @param defaultMessage the message to use when no specific message is set
44+ */
3045 protected AbstractFluentExceptionSupport (String defaultMessage ) {
3146 this .defaultMessage = defaultMessage ;
3247 }
3348
34- // Generic factory methods - to be used by concrete exception classes
49+ /**
50+ * Creates a new exception builder that wraps an existing throwable as its cause.
51+ * This factory method is intended to be used by concrete exception implementations
52+ * to provide their fluent API.
53+ *
54+ * @param <T> the type of exception to create
55+ * @param cause the underlying cause of the exception
56+ * @param builderFactory supplier for creating new builder instances
57+ * @return a builder stage for constructing the exception with additional details
58+ */
3559 public static <T extends Throwable > ExceptionDetailsStage <T > withCause (
3660 Throwable cause , Supplier <AbstractFluentExceptionSupport <T >> builderFactory ) {
3761 AbstractFluentExceptionSupport <T > builder = builderFactory .get ();
3862 builder .setCause (cause );
3963 return builder ;
4064 }
4165
66+ /**
67+ * Creates a new exception builder for exceptions that represent a root cause
68+ * (with no underlying cause).
69+ *
70+ * @param <T> the type of exception to create
71+ * @param builderFactory supplier for creating new builder instances
72+ * @return a builder stage for constructing the exception with additional details
73+ */
4274 public static <T extends Throwable > ExceptionDetailsStage <T > asRootCause (
4375 Supplier <AbstractFluentExceptionSupport <T >> builderFactory ) {
4476 return builderFactory .get ();
4577 }
4678
79+ /**
80+ * Returns the currently set exception message.
81+ *
82+ * <p>The message is optional and may return an empty Optional if no message has been set.
83+ * In such cases, when the exception is created, it will use the default message specified
84+ * in the constructor.
85+ *
86+ * <p>This is a protected method intended for use by subclasses that need to access
87+ * the raw message value during exception creation.
88+ *
89+ * @return an Optional containing the current exception message, or an empty Optional if no message is set
90+ */
4791 protected Optional <String > message () {
4892 return Optional .ofNullable (message );
4993 }
5094
51- // @deprecated Use withCause(Throwable) or asRootCause() instead
95+ /**
96+ * Sets the cause for this exception.
97+ *
98+ * @deprecated Use {@link withCause(Throwable)} to create exceptions with a cause, or {@link #asRootCause()}
99+ * for exceptions without a cause. These methods provide a clearer and more structured approach to exception creation.
100+ *
101+ * <p>Example of preferred usage:
102+ * <pre>{@code
103+ * // Instead of:
104+ * MyException.fluent().cause(e).message("Failed").exception();
105+ *
106+ * // Use:
107+ * MyException.withCause(e).message("Failed").exception();
108+ * }</pre>
109+ *
110+ * @param cause the throwable that caused this exception
111+ * @return this builder instance for method chaining
112+ */
52113 @ Deprecated
53114 public AbstractFluentExceptionSupport <T > cause (Throwable cause ) {
54115 this .cause = cause ;
55116 return this ;
56117 }
57118
119+ /**
120+ * Returns the currently set cause of the exception.
121+ *
122+ * <p>The cause is optional and may return an empty Optional if no cause has been set.
123+ * This typically occurs when the exception is created using {@link #asRootCause()}.
124+ *
125+ * <p>This is a protected method intended for use by subclasses that need to access
126+ * the cause during exception creation.
127+ *
128+ * @return an Optional containing the current exception cause, or an empty Optional if no cause is set
129+ */
58130 protected Optional <Throwable > cause () {
59131 return Optional .ofNullable (cause );
60132 }
61133
134+ /**
135+ * Sets the exception message with optional formatting arguments.
136+ * If formatting arguments are provided, they will be applied using
137+ * {@link String#format(String, Object...)}.
138+ *
139+ * @param message the message template
140+ * @param messageArgs optional formatting arguments
141+ * @return this builder instance for method chaining
142+ */
62143 @ Override
63144 public ExceptionDetailsStage <T > message (String message , Object ... messageArgs ) {
64145 if (messageArgs .length > 0 ) {
@@ -69,22 +150,39 @@ public ExceptionDetailsStage<T> message(String message, Object... messageArgs) {
69150 return this ;
70151 }
71152
153+ /**
154+ * Sets the exception message using a supplier.
155+ * The supplier will be evaluated immediately to get the message.
156+ *
157+ * @param messageSupplier supplier that provides the exception message
158+ * @return this builder instance for method chaining
159+ */
72160 @ Override
73161 public ExceptionDetailsStage <T > message (Supplier <String > messageSupplier ) {
74162 this .message = messageSupplier .get ();
75163 return this ;
76164 }
77165
78- // Throws exception if condition not satisfied.
79- // Note: IntelliJ understands that this throws an exception but may need extra null checks for null checking
80- // conditions.
166+ /**
167+ * Throws the configured exception if the specified condition is true.
168+ * This is a convenience method for conditional exception throwing.
169+ *
170+ * @param condition the condition to evaluate
171+ * @throws T the configured exception if the condition is true
172+ */
81173 @ Override
82174 public void throwIf (boolean condition ) throws T {
83175 if (condition ) {
84176 throw exception ();
85177 }
86178 }
87179
180+ /**
181+ * Creates and returns the exception instance with all configured properties.
182+ * If no message was set, uses the default message.
183+ *
184+ * @return the configured exception instance
185+ */
88186 @ Override
89187 public T exception () {
90188 String exceptionMessage = message ().orElse (defaultMessage );
@@ -122,9 +220,25 @@ private static String ensureEndsWithPeriod(String exceptionMessage) {
122220 return exceptionMessage .endsWith ("." ) ? exceptionMessage : exceptionMessage + "." ;
123221 }
124222
125- // The following abstract methods are the reason why we had to go abstract on this
223+ /**
224+ * Creates an exception instance with the specified message.
225+ * This method must be implemented by concrete subclasses to create
226+ * their specific exception type.
227+ *
228+ * @param message the exception message
229+ * @return a new exception instance
230+ */
126231 protected abstract T createExceptionWith (String message );
127232
233+ /**
234+ * Creates an exception instance with the specified message and cause.
235+ * This method must be implemented by concrete subclasses to create
236+ * their specific exception type.
237+ *
238+ * @param message the exception message
239+ * @param cause the underlying cause of the exception
240+ * @return a new exception instance
241+ */
128242 protected abstract T createExceptionWith (String message , Throwable cause );
129243
130244 // Used by the concrete exception classes
0 commit comments