Skip to content

Commit 33c4443

Browse files
stainless-app[bot]damokwhinnery-openaiTomerAberbach
authored
release: 2.9.1 (#514)
* empty-properties: improved docs and error message. * chore(internal): add tests for breaking change detection * chore: updated readme link * release: 2.9.1 --------- Co-authored-by: D Gardner <[email protected]> Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: Kevin Whinnery <[email protected]> Co-authored-by: Tomer Aberbach <[email protected]>
1 parent 56edf49 commit 33c4443

File tree

10 files changed

+146
-33
lines changed

10 files changed

+146
-33
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: CI
2+
on:
3+
pull_request:
4+
branches:
5+
- main
6+
- next
7+
8+
jobs:
9+
detect_breaking_changes:
10+
runs-on: 'ubuntu-latest'
11+
name: detect-breaking-changes
12+
if: github.repository == 'openai/openai-java'
13+
steps:
14+
- name: Calculate fetch-depth
15+
run: |
16+
echo "FETCH_DEPTH=$(expr ${{ github.event.pull_request.commits }} + 1)" >> $GITHUB_ENV
17+
18+
- uses: actions/checkout@v4
19+
with:
20+
# Ensure we can check out the pull request base in the script below.
21+
fetch-depth: ${{ env.FETCH_DEPTH }}
22+
23+
- name: Set up Java
24+
uses: actions/setup-java@v4
25+
with:
26+
distribution: temurin
27+
java-version: |
28+
8
29+
21
30+
cache: gradle
31+
- name: Set up Gradle
32+
uses: gradle/gradle-build-action@v2
33+
34+
- name: Detect breaking changes
35+
run: ./scripts/detect-breaking-changes ${{ github.event.pull_request.base.sha }}

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "2.9.0"
2+
".": "2.9.1"
33
}

.stats.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 86
22
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-ef4ecb19eb61e24c49d77fef769ee243e5279bc0bdbaee8d0f8dba4da8722559.yml
33
openapi_spec_hash: 1b8a9767c9f04e6865b06c41948cdc24
4-
config_hash: fd2af1d5eff0995bb7dc02ac9a34851d
4+
config_hash: cae2d1f187b5b9f8dfa00daa807da42a

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Changelog
22

3+
## 2.9.1 (2025-06-25)
4+
5+
Full Changelog: [v2.9.0...v2.9.1](https://github.com/openai/openai-java/compare/v2.9.0...v2.9.1)
6+
7+
### Chores
8+
9+
* **internal:** add tests for breaking change detection ([b0a6eeb](https://github.com/openai/openai-java/commit/b0a6eebc67688d38769809efaef7ebc23f519969))
10+
* updated readme link ([c0992cd](https://github.com/openai/openai-java/commit/c0992cdf475ce4a7f5225d849affb1b449c37cf1))
11+
312
## 2.9.0 (2025-06-23)
413

514
Full Changelog: [v2.8.1...v2.9.0](https://github.com/openai/openai-java/compare/v2.8.1...v2.9.0)

README.md

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@
22

33
<!-- x-release-please-start-version -->
44

5-
[![Maven Central](https://img.shields.io/maven-central/v/com.openai/openai-java)](https://central.sonatype.com/artifact/com.openai/openai-java/2.9.0)
6-
[![javadoc](https://javadoc.io/badge2/com.openai/openai-java/2.9.0/javadoc.svg)](https://javadoc.io/doc/com.openai/openai-java/2.9.0)
5+
[![Maven Central](https://img.shields.io/maven-central/v/com.openai/openai-java)](https://central.sonatype.com/artifact/com.openai/openai-java/2.9.1)
6+
[![javadoc](https://javadoc.io/badge2/com.openai/openai-java/2.9.1/javadoc.svg)](https://javadoc.io/doc/com.openai/openai-java/2.9.1)
77

88
<!-- x-release-please-end -->
99

1010
The OpenAI Java SDK provides convenient access to the [OpenAI REST API](https://platform.openai.com/docs) from applications written in Java.
1111

1212
<!-- x-release-please-start-version -->
1313

14-
The REST API documentation can be found on [platform.openai.com](https://platform.openai.com/docs). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.openai/openai-java/2.9.0).
14+
The REST API documentation can be found on [platform.openai.com](https://platform.openai.com/docs). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.openai/openai-java/2.9.1).
1515

1616
<!-- x-release-please-end -->
1717

@@ -22,7 +22,7 @@ The REST API documentation can be found on [platform.openai.com](https://platfor
2222
### Gradle
2323

2424
```kotlin
25-
implementation("com.openai:openai-java:2.9.0")
25+
implementation("com.openai:openai-java:2.9.1")
2626
```
2727

2828
### Maven
@@ -31,7 +31,7 @@ implementation("com.openai:openai-java:2.9.0")
3131
<dependency>
3232
<groupId>com.openai</groupId>
3333
<artifactId>openai-java</artifactId>
34-
<version>2.9.0</version>
34+
<version>2.9.1</version>
3535
</dependency>
3636
```
3737

@@ -363,7 +363,8 @@ response will then be converted automatically to an instance of that Java class.
363363
example of the use of Structured Outputs with arbitrary Java classes can be seen in
364364
[`StructuredOutputsExample`](openai-java-example/src/main/java/com/openai/example/StructuredOutputsExample.java).
365365

366-
Java classes can contain fields declared to be instances of other classes and can use collections:
366+
Java classes can contain fields declared to be instances of other classes and can use collections
367+
(see [Defining JSON schema properties](#defining-json-schema-properties) for more details):
367368

368369
```java
369370
class Person {
@@ -506,12 +507,38 @@ the latter when `ResponseCreateParams.Builder.text(Class<T>)` is called.
506507
For a full example of the usage of _Structured Outputs_ with the Responses API, see
507508
[`ResponsesStructuredOutputsExample`](openai-java-example/src/main/java/com/openai/example/ResponsesStructuredOutputsExample.java).
508509

510+
### Defining JSON schema properties
511+
512+
When a JSON schema is derived from your Java classes, all properties represented by `public` fields
513+
or `public` getter methods are included in the schema by default. Non-`public` fields and getter
514+
methods are _not_ included by default. You can exclude `public`, or include non-`public` fields or
515+
getter methods, by using the `@JsonIgnore` or `@JsonProperty` annotations respectively (see
516+
[Annotating classes and JSON schemas](#annotating-classes-and-json-schemas) for details).
517+
518+
If you do not want to define `public` fields, you can define `private` fields and corresponding
519+
`public` getter methods. For example, a `private` field `myValue` with a `public` getter method
520+
`getMyValue()` will result in a `"myValue"` property being included in the JSON schema. If you
521+
prefer not to use the conventional Java "get" prefix for the name of the getter method, then you
522+
_must_ annotate the getter method with the `@JsonProperty` annotation and the full method name will
523+
be used as the property name. You do not have to define any corresponding setter methods if you do
524+
not need them.
525+
526+
Each of your classes _must_ define at least one property to be included in the JSON schema. A
527+
validation error will occur if any class contains no fields or getter methods from which schema
528+
properties can be derived. This may occur if, for example:
529+
530+
- There are no fields or getter methods in the class.
531+
- All fields and getter methods are `public`, but all are annotated with `@JsonIgnore`.
532+
- All fields and getter methods are non-`public`, but none are annotated with `@JsonProperty`.
533+
- A field or getter method is declared with a `Map` type. A `Map` is treated like a separate class
534+
with no named properties, so it will result in an empty `"properties"` field in the JSON schema.
535+
509536
### Annotating classes and JSON schemas
510537

511538
You can use annotations to add further information to the JSON schema derived from your Java
512-
classes, or to exclude individual fields from the schema. Details from annotations captured in the
513-
JSON schema may be used by the AI model to improve its response. The SDK supports the use of
514-
[Jackson Databind](https://github.com/FasterXML/jackson-databind) annotations.
539+
classes, or to control which fields or getter methods will be included in the schema. Details from
540+
annotations captured in the JSON schema may be used by the AI model to improve its response. The SDK
541+
supports the use of [Jackson Databind](https://github.com/FasterXML/jackson-databind) annotations.
515542

516543
```java
517544
import com.fasterxml.jackson.annotation.JsonClassDescription;
@@ -541,8 +568,12 @@ class BookList {
541568
```
542569

543570
- Use `@JsonClassDescription` to add a detailed description to a class.
544-
- Use `@JsonPropertyDescription` to add a detailed description to a field of a class.
545-
- Use `@JsonIgnore` to omit a field of a class from the generated JSON schema.
571+
- Use `@JsonPropertyDescription` to add a detailed description to a field or getter method of a
572+
class.
573+
- Use `@JsonIgnore` to exclude a `public` field or getter method of a class from the generated JSON
574+
schema.
575+
- Use `@JsonProperty` to include a non-`public` field or getter method of a class in the generated
576+
JSON schema.
546577

547578
If you use `@JsonProperty(required = false)`, the `false` value will be ignored. OpenAI JSON schemas
548579
must mark all properties as _required_, so the schema generated from your Java classes will respect
@@ -577,9 +608,11 @@ _Function Calling_ with Java classes to define function parameters can be seen i
577608
[`FunctionCallingExample`](openai-java-example/src/main/java/com/openai/example/FunctionCallingExample.java).
578609

579610
Like for [Structured Outputs](#structured-outputs-with-json-schemas), Java classes can contain
580-
fields declared to be instances of other classes and can use collections. Optionally, annotations
581-
can be used to set the descriptions of the function (class) and its parameters (fields) to assist
582-
the AI model in understanding the purpose of the function and the possible values of its parameters.
611+
fields declared to be instances of other classes and can use collections (see
612+
[Defining JSON schema properties](#defining-json-schema-properties) for more details). Optionally,
613+
annotations can be used to set the descriptions of the function (class) and its parameters (fields)
614+
to assist the AI model in understanding the purpose of the function and the possible values of its
615+
parameters.
583616

584617
```java
585618
import com.fasterxml.jackson.annotation.JsonClassDescription;
@@ -724,24 +757,31 @@ validation and under what circumstances you might want to disable it.
724757
### Annotating function classes
725758

726759
You can use annotations to add further information about functions to the JSON schemas that are
727-
derived from your function classes, or to exclude individual fields from the parameters to the
728-
function. Details from annotations captured in the JSON schema may be used by the AI model to
729-
improve its response. The SDK supports the use of
760+
derived from your function classes, or to control which fields or getter methods will be used as
761+
parameters to the function. Details from annotations captured in the JSON schema may be used by the
762+
AI model to improve its response. The SDK supports the use of
730763
[Jackson Databind](https://github.com/FasterXML/jackson-databind) annotations.
731764

732765
- Use `@JsonClassDescription` to add a description to a function class detailing when and how to use
733766
that function.
734767
- Use `@JsonTypeName` to set the function name to something other than the simple name of the class,
735768
which is used by default.
736-
- Use `@JsonPropertyDescription` to add a detailed description to function parameter (a field of
737-
a function class).
738-
- Use `@JsonIgnore` to omit a field of a class from the generated JSON schema for a function's
739-
parameters.
769+
- Use `@JsonPropertyDescription` to add a detailed description to function parameter (a field or
770+
getter method of a function class).
771+
- Use `@JsonIgnore` to exclude a `public` field or getter method of a class from the generated JSON
772+
schema for a function's parameters.
773+
- Use `@JsonProperty` to include a non-`public` field or getter method of a class in the generated
774+
JSON schema for a function's parameters.
740775

741776
OpenAI provides some
742777
[Best practices for defining functions](https://platform.openai.com/docs/guides/function-calling#best-practices-for-defining-functions)
743778
that may help you to understand how to use the above annotations effectively for your functions.
744779

780+
See also [Defining JSON schema properties](#defining-json-schema-properties) for more details on how
781+
to use fields and getter methods and combine access modifiers and annotations to define the
782+
parameters of your functions. The same rules apply to function classes and to the structured output
783+
classes described in that section.
784+
745785
## File uploads
746786

747787
The SDK defines methods that accept files.

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ repositories {
88

99
allprojects {
1010
group = "com.openai"
11-
version = "2.9.0" // x-release-please-version
11+
version = "2.9.1" // x-release-please-version
1212
}
1313

1414
subprojects {

openai-java-core/src/main/kotlin/com/openai/core/JsonSchemaValidator.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ import com.openai.core.JsonSchemaValidator.Companion.UNRESTRICTED_ENUM_VALUES_LI
1919
internal class JsonSchemaValidator private constructor() {
2020

2121
companion object {
22+
private const val NO_PROPERTIES_DOC =
23+
"https://github.com/openai/openai-java#defining-json-schema-properties"
24+
2225
// The names of the supported schema keywords. All other keywords will be rejected.
2326
private const val SCHEMA = "\$schema"
2427
private const val ID = "\$id"
@@ -409,7 +412,10 @@ internal class JsonSchemaValidator private constructor() {
409412
verify(
410413
properties != null && properties.isObject && !properties.isEmpty,
411414
path,
412-
{ "'$PROPS' field is missing, empty or not an object." },
415+
{
416+
"'$PROPS' field is missing, empty or not an object. " +
417+
"At least one named property must be defined. See: $NO_PROPERTIES_DOC"
418+
},
413419
) {
414420
return
415421
}

openai-java-core/src/test/kotlin/com/openai/core/StructuredOutputsTest.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ internal class StructuredOutputsTest {
8484
// AI. It can only reply with values to _named_ properties, so there must be at least one.
8585
assertThat(validator.errors()).hasSize(1)
8686
assertThat(validator.errors()[0])
87-
.isEqualTo("#: 'properties' field is missing, empty or not an object.")
87+
.startsWith("#: 'properties' field is missing, empty or not an object.")
8888
}
8989

9090
@Test
@@ -98,15 +98,15 @@ internal class StructuredOutputsTest {
9898
// no named `"properties"` and no `"required"` array. Only the first problem is reported.
9999
assertThat(validator.errors()).hasSize(1)
100100
assertThat(validator.errors()[0])
101-
.isEqualTo("#/properties/m: 'properties' field is missing, empty or not an object.")
101+
.startsWith("#/properties/m: 'properties' field is missing, empty or not an object.")
102102

103103
// Do this check of `toString()` once for a validation failure, but do not repeat it in
104104
// other tests.
105105
assertThat(validator.toString())
106-
.isEqualTo(
106+
.startsWith(
107107
"JsonSchemaValidator{isValidationComplete=true, totalStringLength=1, " +
108108
"totalObjectProperties=1, totalEnumValues=0, errors=[" +
109-
"#/properties/m: 'properties' field is missing, empty or not an object.]}"
109+
"#/properties/m: 'properties' field is missing, empty or not an object."
110110
)
111111
}
112112

@@ -700,7 +700,7 @@ internal class StructuredOutputsTest {
700700
// be allowed and the AI model will have nothing it can populate.
701701
assertThat(validator.errors()).hasSize(1)
702702
assertThat(validator.errors()[0])
703-
.isEqualTo("#: 'properties' field is missing, empty or not an object.")
703+
.startsWith("#: 'properties' field is missing, empty or not an object.")
704704
}
705705

706706
@Test
@@ -721,7 +721,7 @@ internal class StructuredOutputsTest {
721721

722722
assertThat(validator.errors()).hasSize(1)
723723
assertThat(validator.errors()[0])
724-
.isEqualTo("#: 'properties' field is missing, empty or not an object.")
724+
.startsWith("#: 'properties' field is missing, empty or not an object.")
725725
}
726726

727727
@Test
@@ -742,7 +742,7 @@ internal class StructuredOutputsTest {
742742

743743
assertThat(validator.errors()).hasSize(1)
744744
assertThat(validator.errors()[0])
745-
.isEqualTo("#: 'properties' field is missing, empty or not an object.")
745+
.startsWith("#: 'properties' field is missing, empty or not an object.")
746746
}
747747

748748
@Test

openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseOutputItemTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ internal class StructuredResponseOutputItemTest {
6060
ResponseCodeInterpreterToolCall.builder()
6161
.id(STRING)
6262
.code(STRING)
63-
.addLogsResult(STRING)
63+
.containerId(STRING)
64+
.outputs(listOf())
6465
.status(ResponseCodeInterpreterToolCall.Status.COMPLETED)
6566
.build()
6667
private val IMAGE_GENERATION_CALL =

scripts/detect-breaking-changes

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
cd "$(dirname "$0")/.."
6+
7+
echo "==> Detecting breaking changes"
8+
9+
TEST_PATHS=(
10+
openai-java-core/src/test/kotlin/com/openai/models
11+
openai-java-core/src/test/kotlin/com/openai/services
12+
)
13+
14+
for PATHSPEC in "${TEST_PATHS[@]}"; do
15+
# Try to check out previous versions of the test files
16+
# with the current SDK.
17+
git checkout "$1" -- "${PATHSPEC}" 2>/dev/null || true
18+
done
19+
20+
# Instead of running the tests, use the linter to check if an
21+
# older test is no longer compatible with the latest SDK.
22+
./scripts/lint

0 commit comments

Comments
 (0)