Skip to content

Commit a6faf12

Browse files
authored
RemoteException.getMessage includes SerializableError parameters (#633)
RemoteException.getMessage (unsafe message) includes SerializableError parameters. RemoteException.getLogMessage (safe) is not impacted.
1 parent c5c3227 commit a6faf12

File tree

3 files changed

+78
-8
lines changed

3 files changed

+78
-8
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type: improvement
2+
improvement:
3+
description: RemoteException.getMessage (unsafe message) includes SerializableError parameters. RemoteException.getLogMessage (safe) is not impacted.
4+
links:
5+
- https://github.com/palantir/conjure-java-runtime-api/pull/633

errors/src/main/java/com/palantir/conjure/java/api/errors/RemoteException.java

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ public final class RemoteException extends RuntimeException implements SafeLogga
3030
private static final String ERROR_CODE = "errorCode";
3131
private static final String ERROR_NAME = "errorName";
3232

33-
private final String message;
3433
private final String stableMessage;
3534
private final SerializableError error;
3635
private final int status;
3736
private final List<Arg<?>> args;
37+
// Lazily evaluated based on the stableMessage, errorInstanceId, and args.
38+
@SuppressWarnings("MutableException")
39+
private String unsafeMessage;
3840

3941
/** Returns the error thrown by a remote process which caused an RPC call to fail. */
4042
public SerializableError getError() {
@@ -48,9 +50,8 @@ public int getStatus() {
4850

4951
public RemoteException(SerializableError error, int status) {
5052
this.stableMessage = error.errorCode().equals(error.errorName())
51-
? String.format("RemoteException: %s", error.errorCode())
52-
: String.format("RemoteException: %s (%s)", error.errorCode(), error.errorName());
53-
this.message = this.stableMessage + " with instance ID " + error.errorInstanceId();
53+
? "RemoteException: " + error.errorCode()
54+
: "RemoteException: " + error.errorCode() + " (" + error.errorName() + ")";
5455
this.error = error;
5556
this.status = status;
5657
this.args = Collections.unmodifiableList(Arrays.asList(
@@ -61,7 +62,31 @@ public RemoteException(SerializableError error, int status) {
6162

6263
@Override
6364
public String getMessage() {
64-
return message;
65+
// This field is not used in most environments so the cost of computation may be avoided.
66+
String messageValue = unsafeMessage;
67+
if (messageValue == null) {
68+
messageValue = renderUnsafeMessage();
69+
unsafeMessage = messageValue;
70+
}
71+
return messageValue;
72+
}
73+
74+
private String renderUnsafeMessage() {
75+
StringBuilder builder = new StringBuilder()
76+
.append(stableMessage)
77+
.append(" with instance ID ")
78+
.append(error.errorInstanceId());
79+
if (!error.parameters().isEmpty()) {
80+
builder.append(": {");
81+
error.parameters()
82+
.forEach((name, unsafeValue) ->
83+
builder.append(name).append('=').append(unsafeValue).append(", "));
84+
// remove the trailing space
85+
builder.setLength(builder.length() - 1);
86+
// replace the trailing comma with a close curly brace
87+
builder.setCharAt(builder.length() - 1, '}');
88+
}
89+
return builder.toString();
6590
}
6691

6792
@Override

errors/src/test/java/com/palantir/conjure/java/api/errors/RemoteExceptionTest.java

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,19 @@ public void testJavaSerialization() {
4747
}
4848

4949
@Test
50-
public void testSuperMessage() {
50+
public void testUnsafeMessage_differentCodeAndName() {
5151
SerializableError error = new SerializableError.Builder()
5252
.errorCode("errorCode")
5353
.errorName("errorName")
5454
.errorInstanceId("errorId")
5555
.build();
5656
assertThat(new RemoteException(error, 500).getMessage())
5757
.isEqualTo("RemoteException: errorCode (errorName) with instance ID errorId");
58+
}
5859

59-
error = new SerializableError.Builder()
60+
@Test
61+
public void testUnsafeMessage_sameCodeAndName() {
62+
SerializableError error = new SerializableError.Builder()
6063
.errorCode("errorCode")
6164
.errorName("errorCode")
6265
.errorInstanceId("errorId")
@@ -65,6 +68,31 @@ public void testSuperMessage() {
6568
.isEqualTo("RemoteException: errorCode with instance ID errorId");
6669
}
6770

71+
@Test
72+
public void testUnsafeMessage_oneParameter() {
73+
SerializableError error = new SerializableError.Builder()
74+
.errorCode("errorCode")
75+
.errorName("errorName")
76+
.errorInstanceId("errorId")
77+
.putParameters("foo", "bar")
78+
.build();
79+
assertThat(new RemoteException(error, 500).getMessage())
80+
.isEqualTo("RemoteException: errorCode (errorName) with instance ID errorId: {foo=bar}");
81+
}
82+
83+
@Test
84+
public void testUnsafeMessage_multipleParameters() {
85+
SerializableError error = new SerializableError.Builder()
86+
.errorCode("errorCode")
87+
.errorName("errorName")
88+
.errorInstanceId("errorId")
89+
.putParameters("a", "b")
90+
.putParameters("c", "d")
91+
.build();
92+
assertThat(new RemoteException(error, 500).getMessage())
93+
.isEqualTo("RemoteException: errorCode (errorName) with instance ID errorId: {a=b, c=d}");
94+
}
95+
6896
@Test
6997
public void testLogMessageMessage() {
7098
SerializableError error = new SerializableError.Builder()
@@ -77,7 +105,19 @@ public void testLogMessageMessage() {
77105
}
78106

79107
@Test
80-
public void testArgsIsEmpty() {
108+
public void testLogMessageMessageDoesNotIncludeParameters() {
109+
SerializableError error = new SerializableError.Builder()
110+
.errorCode("errorCode")
111+
.errorName("errorName")
112+
.errorInstanceId("errorId")
113+
.putParameters("param", "value")
114+
.build();
115+
RemoteException remoteException = new RemoteException(error, 500);
116+
assertThat(remoteException.getLogMessage()).isEqualTo("RemoteException: errorCode (errorName)");
117+
}
118+
119+
@Test
120+
public void testArgsContainsOnlyErrorInstanceId() {
81121
RemoteException remoteException = new RemoteException(
82122
new SerializableError.Builder()
83123
.errorCode("errorCode")

0 commit comments

Comments
 (0)