Skip to content

Commit 0980a34

Browse files
committed
Sync open source content 🐝 (from 04ffca7aac108a871024d69503f3acfe6e45d9c3)
1 parent 43bd99d commit 0980a34

File tree

1 file changed

+92
-70
lines changed

1 file changed

+92
-70
lines changed

docs/languages/java/methodology-java.mdx

Lines changed: 92 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ The Speakeasy Java SDK is designed to be easy to use and debug. This includes ge
1414
The core features of the SDK include:
1515

1616
- **Type-safety**: Strong typing is used extensively so that problems are seen at compile time, not runtime.
17-
- **Null-safety**: Primitive types are used where possible, improving **compile-time** null safety. For non-required and nullable fields, the `java.util.Optional` and `JSONNullable` classes are used. Passing Java `null` arguments will provoke an exception.
17+
- **Null-safety**: Primitive types are used where possible, improving **compile-time** null safety. For non-required and nullable fields, the `java.util.Optional` and `JSONNullable` classes are used. Passing Java `null` arguments will provoke an exception.
1818
- **Builders and method chaining for all SDK objects.** For example, to create a `Person` object:
1919

2020
```java
@@ -28,19 +28,19 @@ Person person = Person.builder()
2828
- All-field constructors are available for most SDK objects, so a user can get a compile-time indication of changes to the OpenAPI document if required.
2929
- **Readability**: Appropriately formatted method chaining is more understandable and maintainable.
3030
- **Discoverability**: Method chaining and favorable naming strategies make life easier. For example, to build a `Person` object, you call `Person.builder()` and **not** `new Builders.PersonFactory()`.
31-
- **Convenient overloads in builders.** For example, a `long` can be passed directly when the underlying field is `Optional<Long>`.
31+
- **Convenient overloads in builders.** For example, a `long` can be passed directly when the underlying field is `Optional<Long>`.
3232
- The `java.util.Optional` class is used for non-required arguments.
33-
- The `JsonNullable` class is used for nullable arguments.
34-
- The Java platform `OffsetDateTime` and `LocalDate` types are used for `date-time` and `date`.
33+
- The `JsonNullable` class is used for nullable arguments.
34+
- The Java platform `OffsetDateTime` and `LocalDate` types are used for `date-time` and `date`.
3535
- A `utils` package provides shared code used by generated classes, making the generated code easier to follow.
3636
- Authentication support for OAuth flows and other standard security mechanisms.
3737
- Custom enum types using string or integer values.
38-
- Pagination support, including the option to return `java.util.Stream` so that paging is auto-handled.
38+
- Pagination support, including the option to return `java.util.Stream` so that paging is auto-handled.
3939
- Well-formatted source code to make debugging easier.
4040

4141
The SDK includes minimal dependencies. It requires:
4242

43-
- [Jackson Library](https://github.com/FasterXML/jackson) to serialize and deserialize data over the wire.
43+
- [Jackson Library](https://github.com/FasterXML/jackson) to serialize and deserialize data over the wire.
4444
- [Apache HttpClient](https://hc.apache.org/httpcomponents-client-4.5.x/index.html) to make HTTP requests.
4545
- [Jayway JsonPath](https://github.com/json-path/JsonPath) to support JSON path expressions in Speakeasy metadata fields in OpenAPI documents.
4646

@@ -61,7 +61,7 @@ The SDK includes minimal dependencies. It requires:
6161
| | | └-- ...
6262
| | └-- shared # package for shared component models
6363
| | └-- ...
64-
| └-- utils # package for shared utility classes
64+
| └-- utils # package for shared utility classes
6565
| └-- ...
6666
|-- docs # Markdown files for the SDK's documentation
6767
|-- gradlew # Gradle shellscript to build/install the SDK
@@ -71,6 +71,7 @@ The SDK includes minimal dependencies. It requires:
7171
| └-- ... # other Gradle-related files
7272
└-- ...
7373
```
74+
7475
## Build customization
7576

7677
The `build.gradle` file should not be edited because generation updates will overwrite changes. However, customization of `build.gradle` is possible:
@@ -82,34 +83,33 @@ The `build.gradle` file should not be edited because generation updates will ove
8283
java:
8384
version: 0.2.0
8485
artifactID: openapi
85-
...
86-
additionalPlugins:
87-
- 'id("java")'
86+
---
87+
additionalPlugins:
88+
- 'id("java")'
8889
```
8990
9091
Dependencies can be customized in two ways:
9192
9293
- You can add a `dependencies` block to `build-extras.gradle`. Note that with standard Gradle techniques, you can exclude dependencies, exclude transitive dependencies, and modify dependencies in `build-extras.gradle`.
9394

94-
- You can use the `additionalDependencies` property in `gen.yaml`. For example, the fragment below overrides the `jackson-databind` and adds `commons-compress`:
95+
- You can use the `additionalDependencies` property in `gen.yaml`. For example, the fragment below overrides the `jackson-databind` and adds `commons-compress`:
9596

9697
```yaml
9798
java:
9899
version: 0.2.0
99-
...
100-
addditionalDependencies:
101-
- implementation:com.fasterxml.jackson.core:jackson-databind:2.16.0
102-
- api:org.apache.commons:commons-compress:1.26.1
100+
---
101+
addditionalDependencies:
102+
- implementation:com.fasterxml.jackson.core:jackson-databind:2.16.0
103+
- api:org.apache.commons:commons-compress:1.26.1
103104
```
104-
105105

106106
## HTTP client
107107

108108
The Java SDK HTTP client is configurable using a class implementing the following interface and is found in the `util` package of the generated code:
109109

110110
```java
111111
public interface HTTPClient {
112-
public HTTPResponse<byte[]> send(HTTPRequest request)
112+
public HTTPResponse<byte[]> send(HTTPRequest request)
113113
throws IOException, InterruptedException, URISyntaxException
114114
}
115115
```
@@ -126,7 +126,7 @@ This gives developers using your Java SDK the flexibility to set up proxies, coo
126126

127127
## Serialization and deserialization
128128

129-
Low-level customizations like request and response hooks or `HTTPClient`-based interceptions may require the serialization and deserialization of generated objects to and from JSON.
129+
Low-level customizations like request and response hooks or `HTTPClient`-based interceptions may require the serialization and deserialization of generated objects to and from JSON.
130130

131131
You **must** use the generated custom Jackson `ObjectMapper` for these actions. The `ObjectMapper` is available as a Singleton in the generated `utils` package via `JSON.getMapper()`.
132132

@@ -147,47 +147,47 @@ Where possible, the Java SDK uses native types from the language and uses primit
147147
- `double` (or `java.lang.Double`)
148148
- `boolean` (or `java.lang.Boolean`)
149149

150-
151150
### Unlimited-precision numerics
152151

153152
Using high-precision decimal or integer types is crucial in certain applications, such as in code that manipulates monetary amounts and in situations where overflow, underflow, or truncation caused by precision loss can lead to significant incidents.
154153

155154
To mark a field as an unlimited-precision integer, you can use either an integer:
156155

157156
```yaml
158-
type: integer
159-
format: bigint
160-
```
157+
type: integer
158+
format: bigint
159+
```
161160

162161
Or a string:
163162

164163
```yaml
165-
type: string
166-
format: bigint
164+
type: string
165+
format: bigint
167166
```
168167

169168
The above types are mapped to `java.math.BigInteger` in the generated SDK. Object builders have convenient overloads that allow for passing integer values directly without wrapping them in `BigInteger`.
170169

171170
Similarly, for an unlimited-precision decimal, you can use either a number:
172171

173172
```yaml
174-
type: number
175-
format: decimal
173+
type: number
174+
format: decimal
176175
```
177176

178-
Or a string:
177+
Or a string:
179178

180179
```yaml
181-
type: string
182-
format: decimal
180+
type: string
181+
format: decimal
183182
```
183+
184184
The above types are mapped to `java.math.BigDecimal` in the generated SDK and object builders have convenient overloads that allow passing float and double values directly without wrapping them in `BigDecimal`.
185185

186186
**Note:** SDKs in other languages may choose to map to native high-precision types rather than unlimited-precision types. Check the documentation of the language you are interested in.
187187

188188
### Union types
189189

190-
Support for polymorphic types is critical to most production applications. In OpenAPI, these types are defined using the `oneOf` keyword.
190+
Support for polymorphic types is critical to most production applications. In OpenAPI, these types are defined using the `oneOf` keyword.
191191

192192
#### Non-discriminated `oneOf`
193193

@@ -196,10 +196,10 @@ The subtypes of a non-discriminated `oneOf` type may be objects or primitives, s
196196
Consider this OpenAPI fragment:
197197

198198
```yaml
199-
Pet:
200-
oneOf:
201-
- $ref: "#/components/schemas/Cat"
202-
- $ref: "#/components/schemas/Dog"
199+
Pet:
200+
oneOf:
201+
- $ref: "#/components/schemas/Cat"
202+
- $ref: "#/components/schemas/Dog"
203203
```
204204

205205
Here's how a `Pet` is created in Java code:
@@ -209,8 +209,8 @@ Cat cat = ...;
209209
Dog dog = ...;
210210
211211
// Pet.of only accepts Cat or Dog types, and throws if passed null.
212-
Pet pet = Pet.of(cat);
213-
```
212+
Pet pet = Pet.of(cat);
213+
```
214214

215215
Here is how a `Pet` is inspected:
216216

@@ -245,19 +245,19 @@ if (pet.value() instanceof Cat cat) {
245245
In some circumstances, the `of` static factory method of a `oneOf` class may need to be differentiated by a suffix to avoid type erasure. For example, you would need to use a suffix to differentiate the two array subtypes in the following fragment:
246246

247247
```yaml
248-
Info:
249-
oneOf:
250-
- type: array
251-
items:
252-
type: integer
253-
x-speakeasy-name-override: counts
254-
- type: array
255-
items:
256-
type: string
257-
x-speakeasy-name-override: descriptions
248+
Info:
249+
oneOf:
250+
- type: array
251+
items:
252+
type: integer
253+
x-speakeasy-name-override: counts
254+
- type: array
255+
items:
256+
type: string
257+
x-speakeasy-name-override: descriptions
258258
```
259259

260-
Without accounting for this scenario, the static factory methods `Info.of(List<Long>)` and `Info.of(List<String>)` would conflict due to generic type erasure by the Java compiler and cause a compile error in the generated code. Code generation detects this scenario and adds an `of` method suffix. For the fragment above, the generated static factory methods are the following:
260+
Without accounting for this scenario, the static factory methods `Info.of(List<Long>)` and `Info.of(List<String>)` would conflict due to generic type erasure by the Java compiler and cause a compile error in the generated code. Code generation detects this scenario and adds an `of` method suffix. For the fragment above, the generated static factory methods are the following:
261261

262262
- `ofCounts(List<Long>)`
263263
- `ofDescriptions(List<String>)`
@@ -276,15 +276,15 @@ The subtypes of a discriminated `oneOf` type must be objects, so an interface-ba
276276
Consider this OpenAPI fragment:
277277

278278
```yaml
279-
Pet:
280-
oneOf:
281-
- $ref: "#/components/schemas/Cat"
282-
- $ref: "#/components/schemas/Dog"
283-
discriminator:
284-
propertyName: petType
285-
mapping:
286-
cat: '#/components/schemas/Cat'
287-
dog: '#/components/schemas/Dog'
279+
Pet:
280+
oneOf:
281+
- $ref: "#/components/schemas/Cat"
282+
- $ref: "#/components/schemas/Dog"
283+
discriminator:
284+
propertyName: petType
285+
mapping:
286+
cat: "#/components/schemas/Cat"
287+
dog: "#/components/schemas/Dog"
288288
```
289289

290290
Here's how a `Pet` is created in Java code:
@@ -294,7 +294,7 @@ Pet cat = Cat.builder().name("Moggie").build();
294294
Pet dog = Dog.builder().name("Fido").build();
295295
```
296296

297-
`Pet` is a Java interface with a single `petType()` method, and `Cat` and `Dog` both implement that interface.
297+
`Pet` is a Java interface with a single `petType()` method, and `Cat` and `Dog` both implement that interface.
298298

299299
The `discriminator` property should be marked as required in the `oneOf` subtypes. Considering the discriminator has a constant value in each `oneOf` subtype, it also makes sense to use a Singleton `enum` or a `const` for the `discriminator` property type.
300300

@@ -390,15 +390,15 @@ Be aware that migrating a closed enum to an open enum may bring about compile er
390390

391391
## Parameters
392392

393-
If parameters are defined in the OpenAPI document, Speakeasy will generate methods with parameters as part of the method call itself rather than as part of a separate request object.
393+
If parameters are defined in the OpenAPI document, Speakeasy will generate methods with parameters as part of the method call itself rather than as part of a separate request object.
394394

395395
The number of parameters defined should not exceed the `maxMethodParams` value configured in the `gen.yaml` file. If they do or the `maxMethodParams` value is absent or set to `0`, all generated methods require a single request object that contains all the parameters that may be used to call an endpoint in the API.
396396

397397
## Default values
398398

399-
The `default` keyword in the OpenAPI specification allows a user to omit a field or parameter and it will be set with a given default value.
399+
The `default` keyword in the OpenAPI specification allows a user to omit a field or parameter and it will be set with a given default value.
400400

401-
Default values are represented in the Java SDK with `java.util.Optional` wrappers. Passing `Optional.empty()`, or if you're using a builder, not setting the field or parameter, will mean that the default value in the OpenAPI document is used.
401+
Default values are represented in the Java SDK with `java.util.Optional` wrappers. Passing `Optional.empty()`, or if you're using a builder, not setting the field or parameter, will mean that the default value in the OpenAPI document is used.
402402

403403
Bear in mind that it's lazy-loaded (only loaded once) and that if the default value is not valid for the given type, an `IllegalArgumentException` will be thrown. For example, if `default: abc` is specified for `type: integer`, the exception is thrown.
404404

@@ -416,21 +416,45 @@ The `const` keyword in the OpenAPI specification ensures that a field is essenti
416416
To handle errors in the Java SDK, you need to check the status code of the response. If it is an error response, the `error` field of the response will contain the decoded error value.
417417

418418
<Callout title="Coming Soon" type="info">
419-
Support for throwing unsuccessful status codes as exceptions is coming soon.
419+
Support for throwing unsuccessful status codes as exceptions is coming soon.
420420
</Callout>
421421

422422
## Pagination and `java.util.Stream`
423423

424-
Enabling pagination for an operation in your API is described [here](/docs/customize/runtime/pagination).
424+
Enabling pagination for an operation in your API is described [here](/docs/customize/runtime/pagination).
425425

426-
If pagination is enabled for an operation, you have the option to run `.call()`, `.callAsStream()`, or `.callAsStreamUnwrapped()` when using the operation builder.
426+
If pagination is enabled for an operation, you have the option to run `.call()`, `.callAsIterable()`, `.callAsStream()`, or `.callAsStreamUnwrapped()` when using the operation builder.
427427

428-
- The `.call()` method will return the first page, and you will have to repeatedly check for the existence of another page and retrieve it.
428+
- The `.call()` method will return the first page, and you will have to repeatedly check for the existence of another page and retrieve it.
429+
- The `.callAsIterable()` method returns an `Iterable<>` that can be used with for-each iteration style. Page retrieval is handled automatically as the iteration progresses.
429430
- The `callAsStream()` method returns a `java.util.Stream` of the pages, allowing you to use the convenient `java.util.Stream` API. Retrieving more pages when required and available is handled automatically.
430431
- The `callAsStreamUnwrapped()` method returns a `java.util.Stream` of the concatenated items in the lists on each page. Concatenation and page retrieval are handled automatically.
431432

433+
Below is an example of `callAsIterable()`:
434+
435+
```java
436+
SDK sdk = SDK.builder() ... ;
437+
438+
var iterable = sdk.searchDocuments()
439+
.contains("simple") // parameter
440+
.minSize(200) // parameter
441+
.maxSize(400) // parameter
442+
.callAsIterable(); // returns Iterable<DocumentsPageResponse>
443+
444+
for (var response : iterable) {
445+
List<Document> documents = response.res()
446+
.map(page -> page.documents())
447+
.orElse(Collections.emptyList());
448+
for (Document document : documents) {
449+
if ("fiction".equals(document.category())) {
450+
System.out.println(document.name());
451+
}
452+
}
453+
}
454+
```
455+
432456
Below is an example of `callAsStream()`:
433-
457+
434458
```java
435459
SDK sdk = SDK.builder() ... ;
436460
@@ -456,19 +480,17 @@ sdk.searchDocuments() // builder for the request
456480
.contains("simple") // parameter
457481
.minSize(200) // parameter
458482
.maxSize(400) // parameter
459-
.callAsStreamUnwrapped()
483+
.callAsStreamUnwrapped()
460484
// we are now dealing with a Stream<Document>
461485
.filter(document -> "fiction".equals(document.category())
462486
.limit(200) // no more than 200 documents
463487
.map(document -> document.name())
464488
.forEach(System.out::println);
465489
```
466490

467-
The `callAsStream` and `callAsStreamUnwrapped` methods throw an exception if a response page has a status code of 300 or higher. If you require a different behavior, use the `call` method to manually retrieve each page.
468-
469491
## Server-sent events
470492

471-
General Speakeasy support for server-sent events (SSE) is described [here](/docs/customize-sdks/server-sent-events).
493+
General Speakeasy support for server-sent events (SSE) is described [here](/docs/customize-sdks/server-sent-events).
472494

473495
When an operation response has a content type of `text/event-stream`, the generated response class will have an `events()` method.
474496

@@ -503,7 +525,7 @@ events.forEach(event -> processEvent(event));
503525

504526
## User agent strings
505527

506-
The Java SDK will include a [user agent](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) string in all requests that can be used to track SDK usage among broader API usage. The format is as follows:
528+
The Java SDK will include a [user agent](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) string in all requests that can be used to track SDK usage among broader API usage. The format is as follows:
507529

508530
```stmpl
509531
speakeasy-sdk/java {{SDKVersion}} {{GenVersion}} {{DocVersion}} {{groupId.artifactId}}

0 commit comments

Comments
 (0)