[Fix] Fixed Strolch exception i18n hierarchy

This commit is contained in:
Robert von Burg 2024-03-25 10:18:43 +01:00
parent a7258f0d06
commit 393659ff19
Signed by: eitch
GPG Key ID: 75DB9C85C74331F7
6 changed files with 99 additions and 122 deletions

View File

@ -24,6 +24,7 @@ import java.util.Locale;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import li.strolch.exception.StrolchException;
import li.strolch.exception.StrolchUserMessageException; import li.strolch.exception.StrolchUserMessageException;
import li.strolch.model.Tags; import li.strolch.model.Tags;
import li.strolch.model.i18n.I18nMessageToJsonVisitor; import li.strolch.model.i18n.I18nMessageToJsonVisitor;
@ -229,10 +230,8 @@ public class ServiceResult {
json.addProperty(EXCEPTION_MSG, getExceptionMessageWithCauses(this.throwable, false)); json.addProperty(EXCEPTION_MSG, getExceptionMessageWithCauses(this.throwable, false));
json.addProperty(THROWABLE, formatException(this.throwable)); json.addProperty(THROWABLE, formatException(this.throwable));
if (this.throwable instanceof StrolchUserMessageException if (this.throwable instanceof StrolchException ex && ex.hasI18n())
&& ((StrolchUserMessageException) this.throwable).hasI18n()) json.add(I_18_N, ex.getI18n().accept(new I18nMessageToJsonVisitor()));
json.add(I_18_N, ((StrolchUserMessageException) this.throwable).getI18n()
.accept(new I18nMessageToJsonVisitor()));
} }
if (!json.has(I_18_N) && this.i18nMessage != null) if (!json.has(I_18_N) && this.i18nMessage != null)

View File

@ -26,14 +26,12 @@ public class StrolchAccessDeniedException extends StrolchException {
private final Certificate certificate; private final Certificate certificate;
private final Restrictable restrictable; private final Restrictable restrictable;
private final I18nMessage i18n;
public StrolchAccessDeniedException(Certificate certificate, Restrictable restrictable, I18nMessage i18n, public StrolchAccessDeniedException(Certificate certificate, Restrictable restrictable, I18nMessage i18n,
Throwable cause) { Throwable cause) {
super(i18n.getMessage(), cause); super(i18n, cause);
this.certificate = certificate; this.certificate = certificate;
this.restrictable = restrictable; this.restrictable = restrictable;
this.i18n = i18n;
} }
public Certificate getCertificate() { public Certificate getCertificate() {
@ -43,8 +41,4 @@ public class StrolchAccessDeniedException extends StrolchException {
public Restrictable getRestrictable() { public Restrictable getRestrictable() {
return restrictable; return restrictable;
} }
public I18nMessage getI18n() {
return this.i18n;
}
} }

View File

@ -15,16 +15,17 @@
*/ */
package li.strolch.exception; package li.strolch.exception;
import java.util.Locale;
import li.strolch.utils.I18nMessage; import li.strolch.utils.I18nMessage;
import java.util.Locale;
import java.util.ResourceBundle;
/** /**
* @author Robert von Burg <eitch@eitchnet.ch> * @author Robert von Burg <eitch@eitchnet.ch>
*/ */
public class StrolchException extends RuntimeException { public class StrolchException extends RuntimeException {
private I18nMessage i18n; protected I18nMessage i18n;
public StrolchException(String message, Throwable cause) { public StrolchException(String message, Throwable cause) {
super(message, cause); super(message, cause);
@ -36,6 +37,41 @@ public class StrolchException extends RuntimeException {
public StrolchException(I18nMessage i18n) { public StrolchException(I18nMessage i18n) {
super(i18n.getMessage(Locale.getDefault())); super(i18n.getMessage(Locale.getDefault()));
this.i18n = i18n;
if (i18n.hasException())
initCause(i18n.getException());
}
public StrolchException(I18nMessage i18n, Throwable cause) {
super(i18n.getMessage(Locale.getDefault()), cause);
this.i18n = i18n;
}
public StrolchException(ResourceBundle bundle, String key) {
this(new I18nMessage(bundle, key));
}
public StrolchException(ResourceBundle bundle, String key, String prop, Object value) {
this(new I18nMessage(bundle, key).value(prop, value));
}
public StrolchException(ResourceBundle bundle, String key, String prop1, Object value1, String prop2,
Object value2) {
this(new I18nMessage(bundle, key).value(prop1, value1).value(prop2, value2));
}
public StrolchException(ResourceBundle bundle, String key, String prop1, Object value1, String prop2, Object value2,
String prop3, Object value3) {
this(new I18nMessage(bundle, key).value(prop1, value1).value(prop2, value2).value(prop3, value3));
}
public StrolchException(ResourceBundle bundle, String key, String prop1, Object value1, String prop2, Object value2,
String prop3, Object value3, String prop4, Object value4) {
this(new I18nMessage(bundle, key)
.value(prop1, value1)
.value(prop2, value2)
.value(prop3, value3)
.value(prop4, value4));
} }
public boolean hasI18n() { public boolean hasI18n() {
@ -54,4 +90,9 @@ public class StrolchException extends RuntimeException {
this.i18n = i18n; this.i18n = i18n;
return this; return this;
} }
public StrolchException cause(Throwable cause) {
initCause(cause);
return this;
}
} }

View File

@ -1,78 +1,40 @@
package li.strolch.exception; package li.strolch.exception;
import li.strolch.utils.I18nMessage;
import java.util.Locale; import java.util.Locale;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import li.strolch.utils.I18nMessage;
public class StrolchUserMessageException extends StrolchException { public class StrolchUserMessageException extends StrolchException {
private I18nMessage i18n;
public StrolchUserMessageException(I18nMessage i18n) { public StrolchUserMessageException(I18nMessage i18n) {
super(i18n.getMessage(Locale.getDefault())); super(i18n);
this.i18n = i18n;
if (i18n.hasException())
initCause(i18n.getException());
} }
public StrolchUserMessageException(I18nMessage i18n, Throwable cause) { public StrolchUserMessageException(I18nMessage i18n, Throwable cause) {
super(i18n.getMessage(Locale.getDefault()), cause); super(i18n, cause);
this.i18n = i18n;
} }
public StrolchUserMessageException(ResourceBundle bundle, String key) { public StrolchUserMessageException(ResourceBundle bundle, String key) {
this(new I18nMessage(bundle, key)); super(bundle, key);
} }
public StrolchUserMessageException(ResourceBundle bundle, String key, String prop, Object value) { public StrolchUserMessageException(ResourceBundle bundle, String key, String prop, Object value) {
this(new I18nMessage(bundle, key) // super(bundle, key, prop, value);
.value(prop, value));
} }
public StrolchUserMessageException(ResourceBundle bundle, String key, String prop1, Object value1, String prop2, public StrolchUserMessageException(ResourceBundle bundle, String key, String prop1, Object value1, String prop2,
Object value2) { Object value2) {
this(new I18nMessage(bundle, key) // super(bundle, key, prop1, value1, prop2, value2);
.value(prop1, value1) //
.value(prop2, value2));
} }
public StrolchUserMessageException(ResourceBundle bundle, String key, String prop1, Object value1, String prop2, public StrolchUserMessageException(ResourceBundle bundle, String key, String prop1, Object value1, String prop2,
Object value2, String prop3, Object value3) { Object value2, String prop3, Object value3) {
this(new I18nMessage(bundle, key) // super(bundle, key, prop1, value1, prop2, value2, prop3, value3);
.value(prop1, value1) //
.value(prop2, value2) //
.value(prop3, value3));
} }
public StrolchUserMessageException(ResourceBundle bundle, String key, String prop1, Object value1, String prop2, public StrolchUserMessageException(ResourceBundle bundle, String key, String prop1, Object value1, String prop2,
Object value2, String prop3, Object value3, String prop4, Object value4) { Object value2, String prop3, Object value3, String prop4, Object value4) {
this(new I18nMessage(bundle, key) // super(bundle, key, prop1, value1, prop2, value2, prop3, value3, prop4, value4);
.value(prop1, value1) //
.value(prop2, value2) //
.value(prop3, value3) //
.value(prop4, value4));
}
public StrolchUserMessageException cause(Throwable cause) {
initCause(cause);
return this;
}
public boolean hasI18n() {
return this.i18n != null;
}
public I18nMessage getI18n() {
return this.i18n;
}
public void setI18n(I18nMessage i18n) {
this.i18n = i18n;
}
public StrolchUserMessageException i18n(I18nMessage i18n) {
this.i18n = i18n;
return this;
} }
} }

View File

@ -40,7 +40,8 @@ public class ExceptionHelper {
public static String getCallerMethod(int depth) { public static String getCallerMethod(int depth) {
return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) // return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) //
.walk(frames -> frames.map((StackWalker.StackFrame sf) -> sf.getClassName() + "." + sf.getMethodName()) .walk(frames -> frames
.map((StackWalker.StackFrame sf) -> sf.getClassName() + "." + sf.getMethodName())
.skip(depth) .skip(depth)
.findFirst()).orElse("UnknownClass.unknownMethod!"); .findFirst()).orElse("UnknownClass.unknownMethod!");
} }
@ -61,8 +62,7 @@ public class ExceptionHelper {
* in such a case * in such a case
* </p> * </p>
* *
* @param t * @param t the {@link Throwable}
* the {@link Throwable}
* *
* @return the exception as string * @return the exception as string
*/ */
@ -80,11 +80,9 @@ public class ExceptionHelper {
* in such a case * in such a case
* </p> * </p>
* *
* @param t * @param t the {@link Throwable}
* the {@link Throwable} * @param withClassName if true, then exception class name is prepended to the exception message, if the exception
* @param withClassName * message is null, then this param is ignored
* if true, then exception class name is prepended to the exception message, if the exception message is null,
* then this param is ignored
* *
* @return the exception as string * @return the exception as string
*/ */
@ -104,8 +102,7 @@ public class ExceptionHelper {
* in such a case * in such a case
* </p> * </p>
* *
* @param t * @param t the {@link Throwable}
* the {@link Throwable}
* *
* @return the exception as string * @return the exception as string
*/ */
@ -123,15 +120,15 @@ public class ExceptionHelper {
* in such a case * in such a case
* </p> * </p>
* *
* @param t * @param t the {@link Throwable}
* the {@link Throwable} * @param withClassName if true, then exception class name is prepended to the exception message, if the exception
* @param withClassName * message is null, then this param is ignored
* if true, then exception class name is prepended to the exception message, if the exception message is null,
* then this param is ignored
* *
* @return the exception as string * @return the exception as string
*/ */
public static String getExceptionMessageWithCauses(Throwable t, boolean withClassName) { public static String getExceptionMessageWithCauses(Throwable t, boolean withClassName) {
if (t == null)
return "(null)";
if (t.getCause() == null) if (t.getCause() == null)
return getExceptionMessage(t, withClassName); return getExceptionMessage(t, withClassName);
@ -142,13 +139,12 @@ public class ExceptionHelper {
/** /**
* Formats the given {@link Throwable}'s stack trace to a string * Formats the given {@link Throwable}'s stack trace to a string
* *
* @param t * @param t the throwable for which the stack trace is to be formatted to string
* the throwable for which the stack trace is to be formatted to string
* *
* @return a string representation of the given {@link Throwable}'s stack trace * @return a string representation of the given {@link Throwable}'s stack trace
*/ */
public static String formatException(Throwable t) { public static String formatException(Throwable t) {
String ls = System.getProperty(PROP_LINE_SEPARATOR); String ls = System.lineSeparator();
if (!ls.equals(UNIX_LINE_SEP)) if (!ls.equals(UNIX_LINE_SEP))
System.setProperty(PROP_LINE_SEPARATOR, UNIX_LINE_SEP); System.setProperty(PROP_LINE_SEPARATOR, UNIX_LINE_SEP);
try { try {
@ -165,8 +161,7 @@ public class ExceptionHelper {
/** /**
* Formats the given {@link Throwable}'s message including causes to a string * Formats the given {@link Throwable}'s message including causes to a string
* *
* @param t * @param t the throwable for which the messages are to be formatted to a string
* the throwable for which the messages are to be formatted to a string
* *
* @return a string representation of the given {@link Throwable}'s messages including causes * @return a string representation of the given {@link Throwable}'s messages including causes
*/ */
@ -177,11 +172,9 @@ public class ExceptionHelper {
/** /**
* Formats the given {@link Throwable}'s message including causes to a string * Formats the given {@link Throwable}'s message including causes to a string
* *
* @param t * @param t the throwable for which the messages are to be formatted to a string
* the throwable for which the messages are to be formatted to a string * @param withClassName if true, then exception class name is prepended to the exception message, if the exception
* @param withClassName * message is null, * then this param is ignored
* if true, then exception class name is prepended to the exception message, if the exception message is null, *
* then this param is ignored
* *
* @return a string representation of the given {@link Throwable}'s messages including causes * @return a string representation of the given {@link Throwable}'s messages including causes
*/ */
@ -196,8 +189,7 @@ public class ExceptionHelper {
/** /**
* Returns the root cause for the given {@link Throwable} * Returns the root cause for the given {@link Throwable}
* *
* @param throwable * @param throwable the {@link Throwable} for which to get the root cause
* the {@link Throwable} for which to get the root cause
* *
* @return the root cause of the given {@link Throwable} * @return the root cause of the given {@link Throwable}
*/ */
@ -213,8 +205,7 @@ public class ExceptionHelper {
/** /**
* Returns {@link #getExceptionMessage(Throwable, boolean)} for the root cause of the given {@link Throwable} * Returns {@link #getExceptionMessage(Throwable, boolean)} for the root cause of the given {@link Throwable}
* *
* @param throwable * @param throwable the throwable for which to get the message of the root cause
* the throwable for which to get the message of the root cause
* *
* @return {@link #getExceptionMessage(Throwable, boolean)} for the root cause of the given {@link Throwable} * @return {@link #getExceptionMessage(Throwable, boolean)} for the root cause of the given {@link Throwable}
*/ */
@ -225,8 +216,7 @@ public class ExceptionHelper {
/** /**
* Walks the causes for the given {@link Throwable} and sees if the given cause exists * Walks the causes for the given {@link Throwable} and sees if the given cause exists
* *
* @param throwable * @param throwable the {@link Throwable} for which to find the given cause type
* the {@link Throwable} for which to find the given cause type
* *
* @return true if the cause was found, false if not * @return true if the cause was found, false if not
*/ */

View File

@ -8,6 +8,7 @@ import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status; import jakarta.ws.rs.core.Response.Status;
import li.strolch.exception.StrolchElementNotFoundException; import li.strolch.exception.StrolchElementNotFoundException;
import li.strolch.exception.StrolchException;
import li.strolch.exception.StrolchNotAuthenticatedException; import li.strolch.exception.StrolchNotAuthenticatedException;
import li.strolch.exception.StrolchUserMessageException; import li.strolch.exception.StrolchUserMessageException;
import li.strolch.model.i18n.I18nMessageToJsonVisitor; import li.strolch.model.i18n.I18nMessageToJsonVisitor;
@ -139,34 +140,24 @@ public class ResponseUtil {
if (svcResult.isOk()) if (svcResult.isOk())
return Response.ok().entity(json).type(MediaType.APPLICATION_JSON).build(); return Response.ok().entity(json).type(MediaType.APPLICATION_JSON).build();
Status status; Status status = switch (t) {
if (t instanceof AccessDeniedException) { case AccessDeniedException ignored -> Status.FORBIDDEN;
status = Status.FORBIDDEN; case PrivilegeException ignored -> Status.UNAUTHORIZED;
} else if (t instanceof PrivilegeModelException) { case StrolchElementNotFoundException ignored -> Status.NOT_FOUND;
status = Status.INTERNAL_SERVER_ERROR; case null, default -> Status.INTERNAL_SERVER_ERROR;
} else if (t instanceof PrivilegeException) { };
status = Status.UNAUTHORIZED;
} else if (t instanceof StrolchElementNotFoundException) {
status = Status.NOT_FOUND;
} else {
status = Status.INTERNAL_SERVER_ERROR;
}
return Response.status(status).entity(json).type(MediaType.APPLICATION_JSON).build(); return Response.status(status).entity(json).type(MediaType.APPLICATION_JSON).build();
} }
public static Response toResponse(Throwable t) { public static Response toResponse(Throwable t) {
if (t instanceof StrolchNotAuthenticatedException) return switch (t) {
return ResponseUtil.toResponse(Status.UNAUTHORIZED, t); case StrolchNotAuthenticatedException ignored -> toResponse(Status.UNAUTHORIZED, t);
if (t instanceof AccessDeniedException) case AccessDeniedException ignored -> toResponse(Status.FORBIDDEN, t);
return ResponseUtil.toResponse(Status.FORBIDDEN, t); case StrolchElementNotFoundException ignored -> toResponse(Status.NOT_FOUND, t);
if (t instanceof StrolchElementNotFoundException) case PrivilegeException ignored -> toResponse(Status.FORBIDDEN, t);
return ResponseUtil.toResponse(Status.NOT_FOUND, t); case null, default -> toResponse(Status.INTERNAL_SERVER_ERROR, t);
if (t instanceof PrivilegeModelException) };
return ResponseUtil.toResponse(Status.INTERNAL_SERVER_ERROR, t);
if (t instanceof PrivilegeException)
return ResponseUtil.toResponse(Status.FORBIDDEN, t);
return toResponse(Status.INTERNAL_SERVER_ERROR, t);
} }
public static Response toResponse(Status status, String msg) { public static Response toResponse(Status status, String msg) {
@ -180,13 +171,13 @@ public class ResponseUtil {
public static Response toResponse(Status status, Throwable t) { public static Response toResponse(Status status, Throwable t) {
JsonObject response = new JsonObject(); JsonObject response = new JsonObject();
if (t instanceof StrolchUserMessageException ex && ((StrolchUserMessageException) t).hasI18n()) { switch (t) {
response.add("i18n", ex.getI18n().accept(new I18nMessageToJsonVisitor())); case StrolchException ex when ex.hasI18n() ->
} else { response.add("i18n", ex.getI18n().accept(new I18nMessageToJsonVisitor()));
Throwable rootCause = getRootCause(t); case null, default -> {
if (rootCause instanceof StrolchUserMessageException ex && Throwable rootCause = getRootCause(t);
((StrolchUserMessageException) rootCause).hasI18n()) { if (rootCause instanceof StrolchUserMessageException ex && ex.hasI18n())
response.add("i18n", ex.getI18n().accept(new I18nMessageToJsonVisitor())); response.add("i18n", ex.getI18n().accept(new I18nMessageToJsonVisitor()));
} }
} }