Skip to content

Commit 902cb37

Browse files
tstanmay13iamnamananand996
authored andcommitted
fix(java): complete form-urlencoded support by fixing wire test generation (#9977)
1 parent 16d21ca commit 902cb37

File tree

52 files changed

+5326
-10
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+5326
-10
lines changed

generators/java-v2/sdk/src/sdk-wire-tests/builders/TestMethodBuilder.ts

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,18 +74,37 @@ export class TestMethodBuilder {
7474
writer.writeLine("// Validate request body");
7575
writer.writeLine("String actualRequestBody = request.getBody().readUtf8();");
7676

77-
this.jsonValidator.formatMultilineJson(writer, "expectedRequestBody", expectedRequestJson);
77+
const isFormEncoded = this.isFormUrlEncodedEndpoint(endpoint);
78+
79+
if (isFormEncoded) {
80+
// For form-urlencoded requests, validate the raw form data format
81+
const formDataPairs: string[] = [];
82+
if (typeof expectedRequestJson === "object" && expectedRequestJson !== null) {
83+
for (const [key, value] of Object.entries(expectedRequestJson)) {
84+
formDataPairs.push(`${key}=${encodeURIComponent(String(value))}`);
85+
}
86+
}
87+
const expectedFormData = formDataPairs.join("&");
88+
89+
writer.writeLine(`String expectedRequestBody = ${JSON.stringify(expectedFormData)};`);
90+
writer.writeLine(
91+
'Assertions.assertEquals(expectedRequestBody, actualRequestBody, "Form-urlencoded request body does not match expected");'
92+
);
93+
} else {
94+
// Standard JSON validation
95+
this.jsonValidator.formatMultilineJson(writer, "expectedRequestBody", expectedRequestJson);
7896

79-
writer.writeLine("JsonNode actualJson = objectMapper.readTree(actualRequestBody);");
80-
writer.writeLine("JsonNode expectedJson = objectMapper.readTree(expectedRequestBody);");
97+
writer.writeLine("JsonNode actualJson = objectMapper.readTree(actualRequestBody);");
98+
writer.writeLine("JsonNode expectedJson = objectMapper.readTree(expectedRequestBody);");
8199

82-
this.jsonValidator.generateEnhancedJsonValidation(
83-
writer,
84-
endpoint,
85-
"request",
86-
"actualJson",
87-
"expectedJson"
88-
);
100+
this.jsonValidator.generateEnhancedJsonValidation(
101+
writer,
102+
endpoint,
103+
"request",
104+
"actualJson",
105+
"expectedJson"
106+
);
107+
}
89108
}
90109

91110
if (hasResponseBody && expectedResponseJson && responseStatusCode < 400) {
@@ -129,6 +148,33 @@ export class TestMethodBuilder {
129148
};
130149
}
131150

151+
/**
152+
* Checks if the endpoint uses application/x-www-form-urlencoded content type.
153+
*/
154+
private isFormUrlEncodedEndpoint(endpoint: HttpEndpoint): boolean {
155+
const requestBody = endpoint.requestBody;
156+
if (!requestBody) {
157+
return false;
158+
}
159+
160+
// Check inlined request body
161+
if (requestBody.type === "inlinedRequestBody") {
162+
return requestBody.contentType === "application/x-www-form-urlencoded";
163+
}
164+
165+
// Check referenced request body
166+
if (requestBody.type === "reference") {
167+
return requestBody.contentType === "application/x-www-form-urlencoded";
168+
}
169+
170+
// Check bytes request body
171+
if (requestBody.type === "bytes") {
172+
return requestBody.contentType === "application/x-www-form-urlencoded";
173+
}
174+
175+
return false;
176+
}
177+
132178
/**
133179
* Converts a name to a valid Java method name.
134180
*/

generators/java/sdk/versions.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
- version: 3.8.12
2+
changelogEntry:
3+
- summary: |
4+
Fixed wire test generation for application/x-www-form-urlencoded requests. Wire tests now correctly
5+
validate form-encoded request bodies instead of attempting to parse them as JSON, eliminating
6+
JsonParseException failures in generated test suites.
7+
type: fix
8+
createdAt: "2025-10-20"
9+
irVersion: 60
10+
111
- version: 3.8.11
212
changelogEntry:
313
- summary: |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// service_
2+
"/submit"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"type": "object",
3+
"properties": {
4+
"status": {
5+
"oneOf": [
6+
{
7+
"type": "string"
8+
},
9+
{
10+
"type": "null"
11+
}
12+
]
13+
},
14+
"message": {
15+
"oneOf": [
16+
{
17+
"type": "string"
18+
},
19+
{
20+
"type": "null"
21+
}
22+
]
23+
}
24+
},
25+
"additionalProperties": false,
26+
"definitions": {}
27+
}
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
{
2+
"version": "1.0.0",
3+
"types": {
4+
"type_:PostSubmitResponse": {
5+
"type": "object",
6+
"declaration": {
7+
"name": {
8+
"originalName": "PostSubmitResponse",
9+
"camelCase": {
10+
"unsafeName": "postSubmitResponse",
11+
"safeName": "postSubmitResponse"
12+
},
13+
"snakeCase": {
14+
"unsafeName": "post_submit_response",
15+
"safeName": "post_submit_response"
16+
},
17+
"screamingSnakeCase": {
18+
"unsafeName": "POST_SUBMIT_RESPONSE",
19+
"safeName": "POST_SUBMIT_RESPONSE"
20+
},
21+
"pascalCase": {
22+
"unsafeName": "PostSubmitResponse",
23+
"safeName": "PostSubmitResponse"
24+
}
25+
},
26+
"fernFilepath": {
27+
"allParts": [],
28+
"packagePath": [],
29+
"file": null
30+
}
31+
},
32+
"properties": [
33+
{
34+
"name": {
35+
"name": {
36+
"originalName": "status",
37+
"camelCase": {
38+
"unsafeName": "status",
39+
"safeName": "status"
40+
},
41+
"snakeCase": {
42+
"unsafeName": "status",
43+
"safeName": "status"
44+
},
45+
"screamingSnakeCase": {
46+
"unsafeName": "STATUS",
47+
"safeName": "STATUS"
48+
},
49+
"pascalCase": {
50+
"unsafeName": "Status",
51+
"safeName": "Status"
52+
}
53+
},
54+
"wireValue": "status"
55+
},
56+
"typeReference": {
57+
"type": "optional",
58+
"value": {
59+
"type": "primitive",
60+
"value": "STRING"
61+
}
62+
},
63+
"propertyAccess": null,
64+
"variable": null
65+
},
66+
{
67+
"name": {
68+
"name": {
69+
"originalName": "message",
70+
"camelCase": {
71+
"unsafeName": "message",
72+
"safeName": "message"
73+
},
74+
"snakeCase": {
75+
"unsafeName": "message",
76+
"safeName": "message"
77+
},
78+
"screamingSnakeCase": {
79+
"unsafeName": "MESSAGE",
80+
"safeName": "MESSAGE"
81+
},
82+
"pascalCase": {
83+
"unsafeName": "Message",
84+
"safeName": "Message"
85+
}
86+
},
87+
"wireValue": "message"
88+
},
89+
"typeReference": {
90+
"type": "optional",
91+
"value": {
92+
"type": "primitive",
93+
"value": "STRING"
94+
}
95+
},
96+
"propertyAccess": null,
97+
"variable": null
98+
}
99+
],
100+
"additionalProperties": false
101+
}
102+
},
103+
"headers": [],
104+
"endpoints": {
105+
"endpoint_.submitFormData": {
106+
"auth": null,
107+
"declaration": {
108+
"name": {
109+
"originalName": "submitFormData",
110+
"camelCase": {
111+
"unsafeName": "submitFormData",
112+
"safeName": "submitFormData"
113+
},
114+
"snakeCase": {
115+
"unsafeName": "submit_form_data",
116+
"safeName": "submit_form_data"
117+
},
118+
"screamingSnakeCase": {
119+
"unsafeName": "SUBMIT_FORM_DATA",
120+
"safeName": "SUBMIT_FORM_DATA"
121+
},
122+
"pascalCase": {
123+
"unsafeName": "SubmitFormData",
124+
"safeName": "SubmitFormData"
125+
}
126+
},
127+
"fernFilepath": {
128+
"allParts": [],
129+
"packagePath": [],
130+
"file": null
131+
}
132+
},
133+
"location": {
134+
"method": "POST",
135+
"path": "/submit"
136+
},
137+
"request": {
138+
"type": "inlined",
139+
"declaration": {
140+
"name": {
141+
"originalName": "PostSubmitRequest",
142+
"camelCase": {
143+
"unsafeName": "postSubmitRequest",
144+
"safeName": "postSubmitRequest"
145+
},
146+
"snakeCase": {
147+
"unsafeName": "post_submit_request",
148+
"safeName": "post_submit_request"
149+
},
150+
"screamingSnakeCase": {
151+
"unsafeName": "POST_SUBMIT_REQUEST",
152+
"safeName": "POST_SUBMIT_REQUEST"
153+
},
154+
"pascalCase": {
155+
"unsafeName": "PostSubmitRequest",
156+
"safeName": "PostSubmitRequest"
157+
}
158+
},
159+
"fernFilepath": {
160+
"allParts": [],
161+
"packagePath": [],
162+
"file": null
163+
}
164+
},
165+
"pathParameters": [],
166+
"queryParameters": [],
167+
"headers": [],
168+
"body": {
169+
"type": "properties",
170+
"value": [
171+
{
172+
"name": {
173+
"name": {
174+
"originalName": "username",
175+
"camelCase": {
176+
"unsafeName": "username",
177+
"safeName": "username"
178+
},
179+
"snakeCase": {
180+
"unsafeName": "username",
181+
"safeName": "username"
182+
},
183+
"screamingSnakeCase": {
184+
"unsafeName": "USERNAME",
185+
"safeName": "USERNAME"
186+
},
187+
"pascalCase": {
188+
"unsafeName": "Username",
189+
"safeName": "Username"
190+
}
191+
},
192+
"wireValue": "username"
193+
},
194+
"typeReference": {
195+
"type": "primitive",
196+
"value": "STRING"
197+
},
198+
"propertyAccess": null,
199+
"variable": null
200+
},
201+
{
202+
"name": {
203+
"name": {
204+
"originalName": "email",
205+
"camelCase": {
206+
"unsafeName": "email",
207+
"safeName": "email"
208+
},
209+
"snakeCase": {
210+
"unsafeName": "email",
211+
"safeName": "email"
212+
},
213+
"screamingSnakeCase": {
214+
"unsafeName": "EMAIL",
215+
"safeName": "EMAIL"
216+
},
217+
"pascalCase": {
218+
"unsafeName": "Email",
219+
"safeName": "Email"
220+
}
221+
},
222+
"wireValue": "email"
223+
},
224+
"typeReference": {
225+
"type": "primitive",
226+
"value": "STRING"
227+
},
228+
"propertyAccess": null,
229+
"variable": null
230+
}
231+
]
232+
},
233+
"metadata": {
234+
"includePathParameters": false,
235+
"onlyPathParameters": false
236+
}
237+
},
238+
"response": {
239+
"type": "json"
240+
},
241+
"examples": null
242+
}
243+
},
244+
"pathParameters": [],
245+
"environments": null,
246+
"variables": null,
247+
"generatorConfig": null
248+
}

0 commit comments

Comments
 (0)