Skip to content

Commit eb21ef9

Browse files
authored
java/kotlin: Send empty struct instead of empty string (#1786)
Fixes regression introduced in #1783
2 parents 6cc1505 + 4cf0d1f commit eb21ef9

File tree

15 files changed

+190
-48
lines changed

15 files changed

+190
-48
lines changed

java/lib/src/main/java/com/svix/api/Message.java

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
11
// this file is @generated
22
package com.svix.api;
33

4+
import com.fasterxml.jackson.annotation.JsonInclude;
5+
import com.fasterxml.jackson.annotation.JsonProperty;
46
import com.svix.SvixHttpClient;
57
import com.svix.Utils;
68
import com.svix.exceptions.ApiException;
9+
import com.svix.models.*;
710
import com.svix.models.ExpungeAllContentsOut;
811
import com.svix.models.ListResponseMessageOut;
912
import com.svix.models.MessageIn;
1013
import com.svix.models.MessageOut;
1114

15+
import lombok.*;
16+
1217
import okhttp3.Headers;
1318
import okhttp3.HttpUrl;
1419

1520
import java.io.IOException;
1621
import java.util.Collections;
1722
import java.util.HashMap;
1823
import java.util.Map;
24+
import java.util.Set;
1925

2026
public class Message {
2127
private final SvixHttpClient client;
@@ -135,22 +141,23 @@ public MessageOut create(
135141
if (options.idempotencyKey != null) {
136142
headers.put("idempotency-key", options.idempotencyKey);
137143
}
138-
if (messageIn.getTransformationsParams() != null) {
139-
if (messageIn.getTransformationsParams().get("rawPayload") == null) {
144+
MessageInInternal msgInInternal = new MessageInInternal(messageIn);
145+
if (msgInInternal.transformationsParams != null) {
146+
if (msgInInternal.transformationsParams.get("rawPayload") == null) {
140147
// transformationsParams may be immutable
141148
HashMap<String, Object> trParams =
142-
new HashMap<>(messageIn.getTransformationsParams());
143-
trParams.put("rawPayload", messageIn.getPayload());
144-
messageIn.setTransformationsParams(trParams);
149+
new HashMap<>(msgInInternal.transformationsParams);
150+
trParams.put("rawPayload", msgInInternal.payload);
151+
msgInInternal.transformationsParams = trParams;
145152
}
146153
} else {
147154
HashMap<String, Object> trParam = new HashMap<>();
148-
trParam.put("rawPayload", messageIn.getPayload());
149-
messageIn.setTransformationsParams(trParam);
155+
trParam.put("rawPayload", msgInInternal.payload);
156+
msgInInternal.transformationsParams = trParam;
150157
}
151-
messageIn.setPayload("");
158+
msgInInternal.payload = new HashMap<>();
152159
return this.client.executeRequest(
153-
"POST", url.build(), Headers.of(headers), messageIn, MessageOut.class);
160+
"POST", url.build(), Headers.of(headers), msgInInternal, MessageOut.class);
154161
}
155162

156163
/**
@@ -251,4 +258,34 @@ public static MessageIn messageInRaw(final String payload, final String contentT
251258
msg.setTransformationsParams(trParam);
252259
return msg;
253260
}
261+
262+
@ToString
263+
@EqualsAndHashCode
264+
@JsonInclude(JsonInclude.Include.NON_NULL)
265+
@NoArgsConstructor
266+
// we use this because we need payload to be an object while the public `MessageIn.payload` is a
267+
// string
268+
private class MessageInInternal {
269+
@JsonProperty private ApplicationIn application;
270+
@JsonProperty private Set<String> channels;
271+
@JsonProperty private String eventId;
272+
@JsonProperty private String eventType;
273+
@JsonProperty private Object payload;
274+
@JsonProperty private Long payloadRetentionHours;
275+
@JsonProperty private Long payloadRetentionPeriod;
276+
@JsonProperty private Set<String> tags;
277+
@JsonProperty private Map<String, Object> transformationsParams;
278+
279+
private MessageInInternal(MessageIn messageIn) {
280+
this.application = messageIn.getApplication();
281+
this.channels = messageIn.getChannels();
282+
this.eventId = messageIn.getEventId();
283+
this.eventType = messageIn.getEventType();
284+
this.payload = messageIn.getPayload();
285+
this.payloadRetentionHours = messageIn.getPayloadRetentionHours();
286+
this.payloadRetentionPeriod = messageIn.getPayloadRetentionPeriod();
287+
this.tags = messageIn.getTags();
288+
this.transformationsParams = messageIn.getTransformationsParams();
289+
}
290+
}
254291
}

java/lib/src/test/com/svix/test/WiremockTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ public void msgInRaw() throws Exception {
438438
svx.getMessage().create("app1", msg);
439439

440440
String expectedBody =
441-
"{\"eventType\":\"event.ended\",\"payload\":\"\",\"transformationsParams\":{\"rawPayload\":\"<xml>{no"
441+
"{\"eventType\":\"event.ended\",\"payload\":{},\"transformationsParams\":{\"rawPayload\":\"<xml>{no"
442442
+ " json here}\"}}";
443443
wireMockRule.verify(
444444
1,
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"payload":"","transformationsParams":{"rawPayload":"{\"key1\":\"val\",\"key2\":\"val\",\"key\":\"val\"}"}}
1+
{"payload":{},"transformationsParams":{"rawPayload":"{\"key1\":\"val\",\"key2\":\"val\",\"key\":\"val\"}"}}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"eventType":"event.type","payload":"","transformationsParams":{"rawPayload":"{\"key\":\"val\",\"key1\":[\"list\"]}"}}
1+
{"eventType":"event.type","payload":{},"transformationsParams":{"rawPayload":"{\"key\":\"val\",\"key1\":[\"list\"]}"}}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"eventType":"event.type","payload":"","transformationsParams":{"rawPayload":"{\"key\":\"val\",\"key1\":[\"list\"]}","headers":{"header-key":"header-val"}}}
1+
{"eventType":"event.type","payload":{},"transformationsParams":{"rawPayload":"{\"key\":\"val\",\"key1\":[\"list\"]}","headers":{"header-key":"header-val"}}}

java/templates/api_extra/message.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,34 @@ public static MessageIn messageInRaw(final String payload, final String contentT
3232
msg.setTransformationsParams(trParam);
3333
return msg;
3434
}
35+
36+
37+
@ToString
38+
@EqualsAndHashCode
39+
@JsonInclude(JsonInclude.Include.NON_NULL)
40+
@NoArgsConstructor
41+
// we use this because we need payload to be an object while the public `MessageIn.payload` is a
42+
// string
43+
private class MessageInInternal {
44+
@JsonProperty private ApplicationIn application;
45+
@JsonProperty private Set<String> channels;
46+
@JsonProperty private String eventId;
47+
@JsonProperty private String eventType;
48+
@JsonProperty private Object payload;
49+
@JsonProperty private Long payloadRetentionHours;
50+
@JsonProperty private Long payloadRetentionPeriod;
51+
@JsonProperty private Set<String> tags;
52+
@JsonProperty private Map<String, Object> transformationsParams;
53+
54+
private MessageInInternal(MessageIn messageIn) {
55+
this.application = messageIn.getApplication();
56+
this.channels = messageIn.getChannels();
57+
this.eventId = messageIn.getEventId();
58+
this.eventType = messageIn.getEventType();
59+
this.payload = messageIn.getPayload();
60+
this.payloadRetentionHours = messageIn.getPayloadRetentionHours();
61+
this.payloadRetentionPeriod = messageIn.getPayloadRetentionPeriod();
62+
this.tags = messageIn.getTags();
63+
this.transformationsParams = messageIn.getTransformationsParams();
64+
}
65+
}
Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
if (messageIn.getTransformationsParams() != null) {
2-
if (messageIn.getTransformationsParams().get("rawPayload") == null) {
1+
MessageInInternal msgInInternal = new MessageInInternal(messageIn);
2+
if (msgInInternal.transformationsParams != null) {
3+
if (msgInInternal.transformationsParams.get("rawPayload") == null) {
34
// transformationsParams may be immutable
4-
HashMap<String, Object> trParams = new HashMap<>(messageIn.getTransformationsParams());
5-
trParams.put("rawPayload",messageIn.getPayload());
6-
messageIn.setTransformationsParams(trParams);
5+
HashMap<String, Object> trParams =
6+
new HashMap<>(msgInInternal.transformationsParams);
7+
trParams.put("rawPayload", msgInInternal.payload);
8+
msgInInternal.transformationsParams = trParams;
79
}
810
} else {
911
HashMap<String, Object> trParam = new HashMap<>();
10-
trParam.put("rawPayload", messageIn.getPayload());
11-
messageIn.setTransformationsParams(trParam);
12+
trParam.put("rawPayload", msgInInternal.payload);
13+
msgInInternal.transformationsParams = trParam;
1214
}
13-
messageIn.setPayload("");
15+
msgInInternal.payload = new HashMap<>();

java/templates/api_resource.java.jinja

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,25 @@
22
// this file is @generated
33
package com.svix.api;
44

5+
import com.fasterxml.jackson.annotation.JsonInclude;
6+
import com.fasterxml.jackson.annotation.JsonProperty;
57
import com.svix.SvixHttpClient;
68
import com.svix.Utils;
79
import com.svix.exceptions.ApiException;
810

11+
import okhttp3.Headers;
12+
import okhttp3.HttpUrl;
13+
914
import java.io.IOException;
1015
import java.util.Collections;
11-
import java.util.Map;
1216
import java.util.HashMap;
17+
import java.util.Map;
18+
import java.util.Set;
1319

14-
import okhttp3.Headers;
15-
import okhttp3.HttpUrl;
20+
{% if resource.name == "message"%}
21+
import lombok.*;
22+
import com.svix.models.*;
23+
{% endif -%}
1624
{% for c in referenced_components -%}
1725
import com.svix.models.{{ c | to_upper_camel_case }};
1826
{% endfor -%}
@@ -140,10 +148,14 @@ public class {{ resource_type_name }} {
140148
null,
141149
{% endif -%}
142150
{# request body -#}
143-
{% if op.request_body_schema_name is defined -%}
144-
{{ req_body_field_name }},
151+
{% if op.id == "v1.message.create" -%}
152+
msgInInternal,
145153
{% else -%}
146-
null,
154+
{% if op.request_body_schema_name is defined -%}
155+
{{ req_body_field_name }},
156+
{% else -%}
157+
null,
158+
{% endif -%}
147159
{% endif -%}
148160
{# response body class -#}
149161
{% if op.response_body_schema_name is defined -%}

kotlin/lib/src/main/kotlin/Message.kt

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.svix.kotlin.models.ListResponseMessageOut
77
import com.svix.kotlin.models.MessageIn
88
import com.svix.kotlin.models.MessageOut
99
import kotlinx.datetime.Instant
10+
import kotlinx.serialization.Serializable
1011
import kotlinx.serialization.json.JsonElement
1112
import kotlinx.serialization.json.JsonObject
1213
import kotlinx.serialization.json.JsonPrimitive
@@ -99,23 +100,35 @@ class Message(private val client: SvixHttpClient) {
99100
options.withContent?.let { url.addQueryParameter("with_content", serializeQueryParam(it)) }
100101
val headers = Headers.Builder()
101102
options.idempotencyKey?.let { headers.add("idempotency-key", it) }
102-
if (messageIn.transformationsParams != null) {
103+
var msgInInternal =
104+
MessageInInternal(
105+
messageIn.application,
106+
messageIn.channels,
107+
messageIn.eventId,
108+
messageIn.eventType,
109+
mapOf(),
110+
messageIn.payloadRetentionHours,
111+
messageIn.payloadRetentionPeriod,
112+
messageIn.tags,
113+
messageIn.transformationsParams,
114+
)
115+
if (msgInInternal.transformationsParams != null) {
103116
// only set rawPayload if not already set
104-
if (messageIn.transformationsParams!!["rawPayload"] == null) {
105-
var trParams = (messageIn.transformationsParams as Map<String, Any>).toMutableMap()
117+
if (msgInInternal.transformationsParams!!["rawPayload"] == null) {
118+
var trParams =
119+
(msgInInternal.transformationsParams as Map<String, Any>).toMutableMap()
106120
trParams["rawPayload"] = messageIn.payload
107-
messageIn.transformationsParams = trParams.toMap()
121+
msgInInternal.transformationsParams = trParams.toMap()
108122
}
109123
} else {
110124
val trParams = mapOf("rawPayload" to messageIn.payload)
111-
messageIn.transformationsParams = trParams
125+
msgInInternal.transformationsParams = trParams
112126
}
113-
messageIn.payload = ""
114-
return client.executeRequest<MessageIn, MessageOut>(
127+
return client.executeRequest<MessageInInternal, MessageOut>(
115128
"POST",
116129
url.build(),
117130
headers = headers.build(),
118-
reqBody = messageIn,
131+
reqBody = msgInInternal,
119132
)
120133
}
121134

@@ -206,3 +219,17 @@ fun messageInRaw(
206219
transformationsParams = JsonObject(transformationsParams),
207220
)
208221
}
222+
223+
@Serializable
224+
private data class MessageInInternal(
225+
val application: ApplicationIn? = null,
226+
val channels: Set<String>? = null,
227+
val eventId: String? = null,
228+
val eventType: String,
229+
@Serializable(with = StringAnyMapSerializer::class) var payload: Map<String, Any>,
230+
val payloadRetentionHours: Long? = null,
231+
val payloadRetentionPeriod: Long? = null,
232+
val tags: Set<String>? = null,
233+
@Serializable(with = StringAnyMapSerializer::class)
234+
var transformationsParams: Map<String, Any>? = null,
235+
)

kotlin/lib/src/main/kotlin/SvixHttpClient.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ internal constructor(
5757
if (res.code in 200..299) {
5858
return Json.decodeFromString<Res>(bodyString)
5959
}
60-
throw ApiException("None 200 status code", res.code, bodyString)
60+
throw ApiException("Non 200 status code ${res.code}", res.code, bodyString)
6161
}
6262

6363
suspend fun executeRequestWithRetry(request: Request): Response {

kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import kotlin.test.Test
1111
import kotlin.test.assertEquals
1212
import kotlinx.coroutines.runBlocking
1313
import kotlinx.serialization.encodeToString
14+
import kotlinx.serialization.json.JsonPrimitive
1415

1516
class BasicTest {
1617
companion object {
@@ -38,10 +39,10 @@ class BasicTest {
3839
MessageIn(
3940
eventType = "invoice.paid",
4041
payload = kotlinx.serialization.json.Json.encodeToString(
41-
mapOf<String, Any>(
42-
"id" to "invoice_WF7WtCLFFtd8ubcTgboSFNql",
43-
"status" to "paid",
44-
"attempt" to 2,
42+
mapOf<String, JsonPrimitive>(
43+
"id" to JsonPrimitive("invoice_WF7WtCLFFtd8ubcTgboSFNql"),
44+
"status" to JsonPrimitive("paid"),
45+
"attempt" to JsonPrimitive(2),
4546
)
4647
),
4748
),

kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ class WiremockTests {
416416
runBlocking { svx.message.create("app1", msg) }
417417

418418
val expectedBody =
419-
"""{"eventType":"event.type","payload":"","transformationsParams":{"headers":{"header-key":"header-val"},"rawPayload":"{\"key\":\"val\",\"key1\":[\"list\"]}"}}"""
419+
"""{"eventType":"event.type","payload":{},"transformationsParams":{"headers":{"header-key":"header-val"},"rawPayload":"{\"key\":\"val\",\"key1\":[\"list\"]}"}}"""
420420
wireMockServer.verify(
421421
1,
422422
postRequestedFor(urlEqualTo("/api/v1/app/app1/msg"))
@@ -437,7 +437,7 @@ class WiremockTests {
437437
runBlocking { svx.message.create("app1", msg) }
438438

439439
val expectedBody =
440-
"""{"eventType":"event.type","payload":"","transformationsParams":{"rawPayload":"{\"key\":\"val\",\"key1\":[\"list\"]}"}}"""
440+
"""{"eventType":"event.type","payload":{},"transformationsParams":{"rawPayload":"{\"key\":\"val\",\"key1\":[\"list\"]}"}}"""
441441

442442
wireMockServer.verify(
443443
1,

kotlin/templates/api_extra/message.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,18 @@ fun messageInRaw(
4343
transformationsParams = JsonObject(transformationsParams),
4444
)
4545
}
46+
47+
@Serializable
48+
private data class MessageInInternal(
49+
val application: ApplicationIn? = null,
50+
val channels: Set<String>? = null,
51+
val eventId: String? = null,
52+
val eventType: String,
53+
@Serializable(with = StringAnyMapSerializer::class)
54+
var payload: Map<String, Any>,
55+
val payloadRetentionHours: Long? = null,
56+
val payloadRetentionPeriod: Long? = null,
57+
val tags: Set<String>? = null,
58+
@Serializable(with = StringAnyMapSerializer::class)
59+
var transformationsParams: Map<String, Any>? = null
60+
)

kotlin/templates/api_extra/message_create_body.kt

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
1-
if (messageIn.transformationsParams != null) {
1+
var msgInInternal =
2+
MessageInInternal(
3+
messageIn.application,
4+
messageIn.channels,
5+
messageIn.eventId,
6+
messageIn.eventType,
7+
mapOf(),
8+
messageIn.payloadRetentionHours,
9+
messageIn.payloadRetentionPeriod,
10+
messageIn.tags,
11+
messageIn.transformationsParams,
12+
)
13+
if (msgInInternal.transformationsParams != null) {
214
// only set rawPayload if not already set
3-
if (messageIn.transformationsParams!!["rawPayload"] == null) {
4-
var trParams = (messageIn.transformationsParams as Map<String, Any>).toMutableMap();
15+
if (msgInInternal.transformationsParams!!["rawPayload"] == null) {
16+
var trParams =
17+
(msgInInternal.transformationsParams as Map<String, Any>).toMutableMap()
518
trParams["rawPayload"] = messageIn.payload
6-
messageIn.transformationsParams = trParams.toMap()
19+
msgInInternal.transformationsParams = trParams.toMap()
720
}
821
} else {
922
val trParams = mapOf("rawPayload" to messageIn.payload)
10-
messageIn.transformationsParams = trParams
23+
msgInInternal.transformationsParams = trParams
1124
}
12-
messageIn.payload = ""

0 commit comments

Comments
 (0)