Skip to content

fix: Jackson polymorphism/serialization, pagination, and GH-reported bugs (GH-1642, GH-1689, GH-1690) - #1699

Merged
prachi-okta merged 5 commits into
masterfrom
fix/sdk-jackson-pagination-and-gh-issues
Jul 21, 2026
Merged

fix: Jackson polymorphism/serialization, pagination, and GH-reported bugs (GH-1642, GH-1689, GH-1690)#1699
prachi-okta merged 5 commits into
masterfrom
fix/sdk-jackson-pagination-and-gh-issues

Conversation

@prachi-okta

@prachi-okta prachi-okta commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Issue(s)

Fixes internally-triaged SDK defects (Jira, tracked in OKTA-1228415 for the GitHub-reported ones):

  • OKTA-1227472 - @JsonSubTypes maps invalid subtypes on ListJwk200ResponseInner / SamlAttributeStatement

Fixes GitHub issues:

Also includes two CI stability fixes discovered while getting this PR green (see below).

Description

1. Jackson polymorphism / null-serialization / pagination fixes

  • ListJwk200ResponseInner / SamlAttributeStatement: these classes declare @JsonSubTypes entries (from the OpenAPI spec's oneOf/anyOf + discriminator) pointing at classes that don't actually extend them in the generated Java, since their source schemas don't use allOf-based inheritance. Jackson requires real Java inheritance for polymorphic resolution, so deserializing them threw InvalidTypeIdException. Fixed by registering @JsonTypeInfo(use = Id.NONE) mixins for these two classes in ApiClient's default ObjectMapper - both classes already contain the union of all their branches' properties as flat fields, so disabling polymorphic resolution loses no data.
  • Application subtypes (e.g. OpenIdConnectApplication): credentials/name/settings are marked required, which makes the generator emit @JsonInclude(ALWAYS) on them. That overrides the ObjectMapper's global NON_NULL default, so a partial PUT update (e.g. only updating visibility) would serialize those fields as literal null, overwriting them server-side. Fixed with a @JsonFilter + SimpleBeanPropertyFilter mixin on Application that skips null-valued properties at serialization time (filters run before per-property @JsonInclude), applied uniformly across all Application subtypes.
  • PagedList.constructPagedList: returned a plain ArrayList (not a PagedList) whenever the response had no Link header - e.g. a filtered/q query that fits on a single page. Callers casting to PagedList got a ClassCastException. Now always returns a PagedList; getAfter()/hasMoreItems() already report "no more pages" correctly when there's no next page.
  • PasswordPolicyPasswordSettingsComplexity: added the missing maxConsecutiveCharacters field to src/swagger/api.yaml.

2. GitHub issue fixes

3. CI stability fixes (found while landing this PR)

  • OrgSettingGeneralIT: the lifecycle test used fixed literal website/support-URL values, which could be clobbered by another concurrently-running JDK matrix job mutating the same org-singleton OrgSetting resource in the shared live test org. Gave the test unique per-run values. (One iteration of this fix used Groovy string interpolation directly in Hamcrest assertions, which is a GString vs String equality trap - GString.equals(String) is always false even when the text matches. Fixed by adding .toString() to produce real Strings.)
  • ApplicationSSOPublicKeysIT.setup: hit a one-off ApiException{code=500} from createApplication. The SDK's built-in retry strategy only retries 429/503/504, not a bare 500, and this call runs in @BeforeClass, so a single transient 500 fails the whole test class. Added a small bounded retry (3 attempts, linear backoff) scoped to this one call.

Category

  • Bugfix
  • Enhancement
  • New Feature
  • Library Upgrade
  • Configuration Change
  • Versioning Change
  • Unit or Integration Test(s)
  • Documentation

Signoff

  • I have submitted a CLA for this PR (N/A - internal Okta contributor)
  • Each commit message explains what the commit does
  • I have updated documentation to explain what my PR does
  • My code is covered by tests if required
  • I did not edit any automatically generated files

…gination type consistency

- Disable broken @JsonSubTypes-based polymorphic resolution on
  ListJwk200ResponseInner/SamlAttributeStatement, whose spec-declared
  discriminator subtypes don't actually extend them, causing
  InvalidTypeIdException on deserialization.
- Restore NON_NULL serialization on Application and its subtypes via a
  JsonFilter mixin, overriding the @JsonInclude(ALWAYS) generated for
  their required properties, which was forcing partial PUT updates to
  null out unrelated fields like credentials/name/settings.
- Always wrap list responses in PagedList, even without a Link header
  (e.g. a filtered query that fits on one page), so callers get a
  consistent return type instead of an occasional ClassCastException.
- Add maxConsecutiveCharacters to PasswordPolicyPasswordSettingsComplexity,
  which was missing from the spec and silently dropped on write.

Co-Authored-By: Claude Code
…ype, bump bouncycastle

- GroupProfileDeserializer's default case for unrecognized keys was
  discarding them instead of routing them into additionalProperties,
  so custom group schema attributes were silently dropped on read.
  Fixed to match the existing UserProfileDeserializer/
  OktaUserGroupProfileDeserializer pattern. (GH-1642)
- LogSecurityContext.userBehaviors was missing an items type, so the
  generator defaulted to List<String> while the API returns a list of
  objects, causing a MismatchedInputException. Declared items: {} so
  it generates List<Object>. (GH-1689)
- Bump bcprov-jdk18on/bcpkix-jdk18on 1.79 -> 1.84 to address reported
  CVEs; commons-lang3 was already at 3.18.0. (GH-1690)

Co-Authored-By: Claude Code
…Setting IT

jdk11 and jdk21 run the identical integration test suite against the same
shared live test org with no per-job isolation, and previously ran
concurrently in the CircleCI workflow. OrgSettingGeneralIT mutates
OrgSetting, which is a singleton per org, so one job's write could be
clobbered by (or read back as) the other job's concurrent write to the
same fields, causing flaky read-after-write assertion failures that no
amount of retrying could fix.

- Make jdk21 require jdk11 so the two jobs no longer run concurrently
  against the shared org.
- Belt-and-suspenders: give OrgSettingGeneralIT's lifecycle test unique
  per-run values (UUID-suffixed) for the fields it writes, so even
  concurrent runs can no longer be confused by each other's writes.

Co-Authored-By: Claude Code
…1 serialization

The real root cause of the flaky assertion was a Groovy GString/String
equality bug in my own previous fix, not job concurrency: string
interpolation ("...${runId}...") produces a GString, and
GString.equals(String) is always false even when the text matches -
CI logs showed the "Expected" and "was" values as byte-for-byte
identical strings while the assertion still failed.

- Add .toString() to the three unique per-run values so they're real
  Strings, fixing the equalTo() comparisons.
- Revert the jdk21->jdk11 CircleCI dependency added in bc649b9,
  since it's no longer needed and unnecessarily halves CI coverage
  whenever jdk11 fails for any reason; jdk11/jdk21 run independently
  again.

Co-Authored-By: Claude Code
…blicKeysIT.setup

CI observed a one-off ApiException{code=500, errorCode=E0000009} from
createApplication while provisioning the test OIDC app in @BeforeClass.
The SDK's built-in retry strategy (OktaHttpRequestRetryStrategy) only
retries 429/503/504, not a bare 500, and this call runs in @BeforeClass
so a single spurious 500 fails the entire test class. Add a small
bounded retry (3 attempts, linear backoff) scoped to this one call.

Co-Authored-By: Claude Code
@prachi-okta prachi-okta changed the title Fix/sdk jackson pagination and gh issues fix: Jackson polymorphism/serialization, pagination, and GH-reported bugs (GH-1642, GH-1689, GH-1690) Jul 20, 2026
@prachi-okta
prachi-okta requested a review from aditya-okta July 21, 2026 05:24
@prachi-okta
prachi-okta merged commit eb5d681 into master Jul 21, 2026
8 checks passed
prachi-okta added a commit that referenced this pull request Jul 21, 2026
…hemas (GH issues deep-dive) (#1701)

* fix: disable broken polymorphic resolution on 6 more oneOf/discriminator schemas

Deep-dive into the still-open GitHub issues (#1654, #1664, #1693) led to
auditing every oneOf/anyOf + discriminator pair in the spec for the same
defect class as OKTA-1227472 (subtypes that don't actually extend the
declared base type via allOf, so Jackson's @JsonSubTypes throws
InvalidTypeIdException). Found and fixed 6 more instances:

- AgentJsonSigningKeyRequest / AgentJsonSigningKeyResponse (unreferenced
  in the spec today, but fixed for correctness/consistency)
- ManagedConnection / ManagedConnectionCreatable
- PotentialConnection
- OrgContactTypeObj - this one is live and reachable from the real
  listOrgContactTypes endpoint

Also adds a regression test confirming GH-1654's likely root cause: a
mixed OIDC/SAML Application list, where the SAML app's
settings.signOn.attributeStatements uses the SamlAttributeStatement type
fixed in OKTA-1227472/#1699, now deserializes without throwing. Before
that fix, an org with SAML apps using attribute statements could see
listApplications fail on those specific apps.

Co-Authored-By: Claude Code

* test: add missing coverage for the 5 Agent/Connection discriminator fixes

AgentJsonSigningKeyRequest, AgentJsonSigningKeyResponse, ManagedConnection,
ManagedConnectionCreatable, and PotentialConnection got the same
@JsonTypeInfo(Id.NONE) mixin fix as OrgContactTypeObj in the previous
commit, but only OrgContactTypeObj had a regression test. Add the
missing five.

Note: ManagedConnection/ManagedConnectionCreatable/PotentialConnection
have a separate, pre-existing quirk where their flattened
ConnectionTypeEnum only retains one oneOf branch's single-value enum
(STS_SERVICE_ACCOUNT) - every other connectionType value falls back to
UNKNOWN_DEFAULT_OPEN_API. That's harmless (no exception) but means
these tests only assert the polymorphism fix, not full enum fidelity;
fully fixing that would require reworking how the spec merges oneOf
branches, which is out of scope here.

Co-Authored-By: Claude Code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants