diff --git a/core/src/main/java/io/github/mmm/base/exception/ApplicationException.java b/core/src/main/java/io/github/mmm/base/exception/ApplicationException.java
index 77cbd6d..fc2cf94 100644
--- a/core/src/main/java/io/github/mmm/base/exception/ApplicationException.java
+++ b/core/src/main/java/io/github/mmm/base/exception/ApplicationException.java
@@ -57,7 +57,7 @@ public ApplicationException(Localizable message) {
* The constructor.
*
* @param message the {@link #getMessage() message} describing the problem briefly.
- * @param cause is the {@link #getCause() cause} of this exception.
+ * @param cause the {@link #getCause() cause} of this exception.
*/
public ApplicationException(String message, Throwable cause) {
@@ -67,8 +67,8 @@ public ApplicationException(String message, Throwable cause) {
/**
* The constructor.
*
- * @param message the {@link #getLocalizedMessage() message} describing the problem briefly.
- * @param cause is the {@link #getCause() cause} of this exception.
+ * @param message the {@link #getNlsMessage() NLS message} describing the problem briefly.
+ * @param cause the {@link #getCause() cause} of this exception.
*/
public ApplicationException(Localizable message, Throwable cause) {
@@ -79,7 +79,7 @@ public ApplicationException(Localizable message, Throwable cause) {
* The constructor.
*
* @param message the {@link #getMessage() message} describing the problem briefly.
- * @param cause is the {@link #getCause() cause} of this exception. May be null
.
+ * @param cause the {@link #getCause() cause} of this exception. May be null
.
* @param uuid the explicit {@link #getUuid() UUID} or null
to initialize by default (from given
* {@link Throwable} or as new {@link UUID}).
*/
@@ -91,8 +91,8 @@ protected ApplicationException(String message, Throwable cause, UUID uuid) {
/**
* The constructor.
*
- * @param message the {@link #getLocalizedMessage() message} describing the problem briefly.
- * @param cause is the {@link #getCause() cause} of this exception. May be null
.
+ * @param message the {@link #getNlsMessage() NLS message} describing the problem briefly.
+ * @param cause the {@link #getCause() cause} of this exception. May be null
.
* @param uuid the explicit {@link #getUuid() UUID} or null
to initialize by default (from given
* {@link Throwable} or as new {@link UUID}).
*/
@@ -136,18 +136,28 @@ public final UUID getUuid() {
return this.uuid;
}
+ /**
+ * ATTENTION: Logging frameworks like logback do not follow Java exception standards and write {@link #toString()} but
+ * only {@link #getMessage()} of the {@link Exception} together with the stacktrace into the log. Since an
+ * {@link ApplicationException} contains additional information like {@link #getUuid() UUID} and {@link #getCode()
+ * code} that needs to be logged we are forced to return the message from this method in the following form:
+ *
+ *
[{@link #getCode() «code»}: ]{@link #getNlsMessage() «message»}
+ * «uuid»
+ *
+ *
+ * Please note that the {@link #getCode() code} is omitted if the {@link #getCode()} method is not overridden and
+ * returning a custom code.
+ * In case you want to get the plain exception message, you therefore need to either call
+ * {@link #getLocalizedMessage()} or use {@link #getNlsMessage()}.
+ *
+ * @return the untranslated message in the form specified above.
+ */
@Override
public String getMessage() {
StringBuilder buffer = new StringBuilder();
- getLocalizedMessage(Locale.ROOT, buffer);
- buffer.append(System.lineSeparator());
- buffer.append(this.uuid);
- String code = getCode();
- if (!getClass().getSimpleName().equals(code)) {
- buffer.append(":");
- buffer.append(code);
- }
+ toString(Locale.ROOT, buffer, true);
return buffer.toString();
}
@@ -161,6 +171,12 @@ public Localizable getNlsMessage() {
return this.message;
}
+ @Override
+ public String getLocalizedMessage() {
+
+ return getLocalizedMessage(Locale.getDefault());
+ }
+
@Override
public String getLocalizedMessage(Locale locale) {
@@ -196,22 +212,14 @@ private static void printStackTrace(ApplicationException throwable, Locale local
try {
synchronized (buffer) {
- buffer.append(throwable.getClass().getName());
- buffer.append(": ");
- throwable.getLocalizedMessage(locale, buffer);
- buffer.append(System.lineSeparator());
- UUID uuid = throwable.getUuid();
- if (uuid != null) {
- buffer.append(uuid.toString());
- buffer.append(System.lineSeparator());
- }
+ throwable.toString(locale, buffer);
StackTraceElement[] trace = throwable.getStackTrace();
for (int i = 0; i < trace.length; i++) {
buffer.append("\tat ");
buffer.append(trace[i].toString());
buffer.append(System.lineSeparator());
}
- for (Throwable suppressed : ((Throwable) throwable).getSuppressed()) {
+ for (Throwable suppressed : throwable.getSuppressed()) {
buffer.append("Suppressed: ");
buffer.append(System.lineSeparator());
printStackTraceCause(suppressed, locale, buffer);
@@ -342,14 +350,21 @@ public String toString(Locale locale) {
*/
public Appendable toString(Locale locale, Appendable appendable) {
+ return toString(locale, appendable, false);
+ }
+
+ private Appendable toString(Locale locale, Appendable appendable, boolean omitClass) {
+
Appendable buffer = appendable;
if (buffer == null) {
buffer = new StringBuilder(32);
}
try {
Class> myClass = getClass();
- buffer.append(myClass.getName());
- buffer.append(": ");
+ if (!omitClass) {
+ buffer.append(myClass.getName());
+ buffer.append(": ");
+ }
String code = getCode();
if (!myClass.getSimpleName().equals(code)) {
buffer.append(code);
diff --git a/core/src/main/java/io/github/mmm/base/exception/ObjectNotFoundException.java b/core/src/main/java/io/github/mmm/base/exception/ObjectNotFoundException.java
index 89f66a0..be7031f 100644
--- a/core/src/main/java/io/github/mmm/base/exception/ObjectNotFoundException.java
+++ b/core/src/main/java/io/github/mmm/base/exception/ObjectNotFoundException.java
@@ -2,6 +2,8 @@
* http://www.apache.org/licenses/LICENSE-2.0 */
package io.github.mmm.base.exception;
+import java.util.Collection;
+
import io.github.mmm.base.i18n.Localizable;
/**
@@ -24,7 +26,7 @@ public class ObjectNotFoundException extends ApplicationException {
/**
* The constructor.
*
- * @param object is a description (e.g. the classname) of the object that was required but could not be found.
+ * @param object the description (e.g. the classname) of the object that was required but could NOT be found.
*/
public ObjectNotFoundException(Object object) {
@@ -34,8 +36,8 @@ public ObjectNotFoundException(Object object) {
/**
* The constructor.
*
- * @param object is a description (e.g. the classname) of the object that was required but could not be found.
- * @param key is the key to the required object.
+ * @param object the description (e.g. the classname) of the object that was required but could NOT be found.
+ * @param key the key to the required object.
*/
public ObjectNotFoundException(Object object, Object key) {
@@ -45,16 +47,30 @@ public ObjectNotFoundException(Object object, Object key) {
/**
* The constructor.
*
- * @param object is a description (e.g. the classname) of the object that was required but could NOT be found.
- * @param key is the key to the required object.
- * @param cause is the {@link #getCause() cause} of this exception.
+ * @param object the description (e.g. the classname) of the object that was required but could NOT be found.
+ * @param key the key to the required object.
+ * @param cause the {@link #getCause() cause} of this exception.
*/
public ObjectNotFoundException(Object object, Object key, Throwable cause) {
- super(createMessage(object, key), cause);
+ this(object, key, null, cause);
}
- private static String createMessage(Object object, Object key) {
+ /**
+ * The constructor.
+ *
+ * @param object the description (e.g. the classname) of the object that was required but could NOT be found.
+ * @param key the key to the required object.
+ * @param options the available options (e.g. {@link Collection} of comma separated {@link String} of the available
+ * keys).
+ * @param cause the {@link #getCause() cause} of this exception.
+ */
+ public ObjectNotFoundException(Object object, Object key, Object options, Throwable cause) {
+
+ super(createMessage(object, key, options), cause);
+ }
+
+ private static String createMessage(Object object, Object key, Object options) {
StringBuilder sb = new StringBuilder("Could not find ");
sb.append(object);
@@ -64,7 +80,10 @@ private static String createMessage(Object object, Object key) {
sb.append(key);
sb.append('\'');
}
- sb.append(".");
+ if (options != null) {
+ sb.append(" in ");
+ sb.append(options);
+ }
return sb.toString();
}
@@ -72,7 +91,7 @@ private static String createMessage(Object object, Object key) {
* The constructor.
*
* @param message the {@link #getNlsMessage() NLS message}.
- * @param cause is the {@link #getCause() cause} of this exception. May be null
.
+ * @param cause the {@link #getCause() cause} of this exception. May be null
.
*/
protected ObjectNotFoundException(Localizable message, Throwable cause) {
diff --git a/core/src/test/java/io/github/mmm/base/exception/ApplicationExceptionTest.java b/core/src/test/java/io/github/mmm/base/exception/ApplicationExceptionTest.java
new file mode 100644
index 0000000..433dfc5
--- /dev/null
+++ b/core/src/test/java/io/github/mmm/base/exception/ApplicationExceptionTest.java
@@ -0,0 +1,45 @@
+package io.github.mmm.base.exception;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Locale;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test of {@link ApplicationException}.
+ */
+public class ApplicationExceptionTest extends Assertions {
+
+ @Test
+ public void testWithCode() {
+
+ // arrange
+ String message = "Something went wrong.";
+ String code = "MagicCode";
+ // act
+ ApplicationException exception = new ApplicationException(message) {
+ @Override
+ public String getCode() {
+
+ return code;
+ }
+ };
+ StringWriter sw = new StringWriter(1024);
+ PrintWriter pw = new PrintWriter(sw);
+ exception.printStackTrace(pw);
+ String stackTrace = sw.toString();
+ // assert
+ assertThat(exception.getLocalizedMessage()).isEqualTo(message);
+ assertThat(exception.getLocalizedMessage(Locale.ROOT)).isEqualTo(message);
+ assertThat(exception.getNlsMessage().getMessage()).isEqualTo(message);
+ String msg = code + ": " + message + System.lineSeparator() + exception.getUuid();
+ assertThat(exception.getMessage()).isEqualTo(msg);
+ String toString = exception.getClass().getName() + ": " + msg;
+ assertThat(exception.toString()).isEqualTo(toString);
+ assertThat(stackTrace).startsWith(toString)
+ .contains("io.github.mmm.base.exception.ApplicationExceptionTest.testWithCode(");
+ }
+
+}
diff --git a/core/src/test/java/io/github/mmm/base/exception/ObjectNotFoundExceptionTest.java b/core/src/test/java/io/github/mmm/base/exception/ObjectNotFoundExceptionTest.java
new file mode 100644
index 0000000..0147918
--- /dev/null
+++ b/core/src/test/java/io/github/mmm/base/exception/ObjectNotFoundExceptionTest.java
@@ -0,0 +1,51 @@
+package io.github.mmm.base.exception;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test of {@link ObjectNotFoundException}.
+ */
+public class ObjectNotFoundExceptionTest extends Assertions {
+
+ @Test
+ public void testSimple() {
+
+ // arrange
+ String name = "io.github.mmm.UndefinedObject";
+ // act
+ ObjectNotFoundException exception = new ObjectNotFoundException(name);
+ // assert
+ assertThat(exception.getLocalizedMessage()).isEqualTo("Could not find " + name);
+ }
+
+ @Test
+ public void testWithKey() {
+
+ // arrange
+ String name = "Entity";
+ String key = "MagicKey";
+ // act
+ ObjectNotFoundException exception = new ObjectNotFoundException(name, key);
+ // assert
+ assertThat(exception.getLocalizedMessage()).isEqualTo("Could not find " + name + " for key '" + key + "'");
+ }
+
+ @Test
+ public void testWithKeyAndOptions() {
+
+ // arrange
+ String name = "Entity";
+ String key = "MagicKey";
+ Collection options = List.of("NormalKey", "Key", "HolyKey");
+ // act
+ ObjectNotFoundException exception = new ObjectNotFoundException(name, key, options, null);
+ // assert
+ assertThat(exception.getLocalizedMessage())
+ .isEqualTo("Could not find " + name + " for key '" + key + "' in [NormalKey, Key, HolyKey]");
+ }
+
+}
diff --git a/metainfo/src/test/java/io/github/mmm/base/metadata/MetaInfoTest.java b/metainfo/src/test/java/io/github/mmm/base/metadata/MetaInfoTest.java
index d5ec47b..7c07c7e 100644
--- a/metainfo/src/test/java/io/github/mmm/base/metadata/MetaInfoTest.java
+++ b/metainfo/src/test/java/io/github/mmm/base/metadata/MetaInfoTest.java
@@ -55,7 +55,7 @@ public void testGetRequired() {
metaInfo.getRequired("key2");
failBecauseExceptionWasNotThrown(ObjectNotFoundException.class);
} catch (ObjectNotFoundException e) {
- assertThat(e).hasMessageContaining("Could not find MetaInfo-value for key 'key2'.");
+ assertThat(e).hasMessageContaining("Could not find MetaInfo-value for key 'key2'");
}
}
@@ -167,7 +167,7 @@ public void testWithPrefix() {
metaInfo.getRequired("key2");
failBecauseExceptionWasNotThrown(ObjectNotFoundException.class);
} catch (ObjectNotFoundException e) {
- assertThat(e.getNlsMessage().getMessage()).isEqualTo("Could not find MetaInfo-value for key 'prefix.key2'.");
+ assertThat(e.getNlsMessage().getMessage()).isEqualTo("Could not find MetaInfo-value for key 'prefix.key2'");
}
// and act