Skip to content

Add UpgradeTwilio_13 to migrate the Twilio Java SDK to 13.x - #1434

Open
krlittle wants to merge 1 commit into
mainfrom
twilio-sdk-migration
Open

krlittle wants to merge 1 commit into
mainfrom
twilio-sdk-migration

Conversation

@krlittle

@krlittle krlittle commented Nov 4, 2026 •

Copy link
Copy Markdown

No recipe migrated com.twilio.sdk:twilio across major versions. org.openrewrite.java.migrate.twilio.UpgradeTwilio_13 takes an application on 7.x or later to 13.x.

The breaking changes come from comparing the jars with japicmp at each major boundary, rather than from Twilio's upgrade guide alone. The guide misses several: for example, AccessToken.Builder changed its secret from String to byte[] in the 10.8.0 minor release, which only CHANGES.md mentions.

What it changes

  • Raises com.twilio.sdk:twilio to 13.x, including through properties and version ranges, on Maven and Gradle.
  • Passes the secret of AccessToken.Builder, ClientCapability.Builder and TaskRouterCapability.Builder as byte[] (TwilioJwtSecretToByteArray, the only Java recipe). The SDK used to call getBytes() itself. This uses StandardCharsets.UTF_8, which gives the same bytes for Twilio's ASCII secrets.
  • Gives NetworkHttpClient an HttpClient 5 HttpClientBuilder, only in source files that pass one to it.
  • Applies the renames from 8.0.0: the ssml* methods of Say.Builder, referSip, ConversationsGrant, and configurationProfileSid of VideoGrant.
  • Removes unused imports of Autopilot, Authy and Fax, which no longer compile even when nothing uses them.
  • Declares Guava, Joda-Time or HttpClient 4 where a project used them only because Twilio brought them along.

What it leaves alone, and why

  • Joda getters, ListenableFuture from the *Async methods, Range date filters, getPrice() becoming a String, and real use of removed products. These need a decision, the compiler points each one out, and none of them occur in the repositories below. ChangeMethodInvocationReturnType also can't help with the futures, since its fixed type string would drop the type argument.
  • The Java version. 13.x needs Java 8, but UpgradeJavaVersion changed Java settings in 11 of 17 repositories, none of them on Java 7. Most of that was 1.8 becoming 8, and in two it turned <source>/<target> into <release>, which javac 8 rejects.
  • Versions a project declares itself. AddDependency raises them, taking Guava to 33.8 in 5 repositories, from as far back as 27.0, so each one is gated on DoesNotIncludeDependency.
  • gradle.lockfile. I found no recipe that writes it again, so the description says to.

The description also lists what no compiler reports: JJWT 0.12 refuses an HMAC secret under 256 bits, a mocked TwilioRestClient needs getAccountSid() stubbed, and a plain ObjectMapper needs JavaTimeModule on Java 17 or later with an old Jackson.

Verification

./gradlew check recipeCsvValidate passes, with 2,816 tests including 33 new ones.

I ran the recipe locally over the 18 repositories a saved search found using the SDK (changeset 20261104205527-mYSzg), not as a run in Moderne. OpenUnison is already on 13.0.2, so it changed 17, and I compiled each before and after, confirming that the classes of the sources importing Twilio were built:

Result Repositories
Compile before and after 14
Needs a new gradle.lockfile and Jwts.parserBuilder() changed to Jwts.parser(), as Twilio raises JJWT to 0.12; compiles once both are done CDCgov/prime-simplereport
Can't resolve Spring Boot 2.2.6 even unchanged, so not verified sureshsk-hub/servicefile, devendra-suntechno/vedikamerge

Tests are thinner evidence. Only two repositories have tests that touch Twilio, and nothing here made a real Twilio API call. In tedyoung/kid-bank all 121 pass. In sflpro/notifier, 17 of the 19 tests in its Twilio module pass with the recipe alone, and all 19 once its mock has the two stubs described above. Its verify needs Docker, which that machine didn't have.

The runtime behaviour was also checked outside any repository, by running the SDK's request, parsing, TwiML and token paths on the Jackson and HttpClient versions Spring Boot 2.1, 2.7, 3.3 and 3.5 pin. The real client works on all of them, so no Spring Boot change is needed.

Worth a look

  • This could have gone to rewrite-third-party, but that repository bundles recipes other projects publish (Adopt upstream sh.stubborn:stubborn-migration recipes and drop the copy in rewrite-spring rewrite-third-party#95), and Twilio publishes none. A library migration filed there was closed with the suggestion of a module of its own (Unirest 4.x rewrite-third-party#111). A migration this size seemed too small for one, and DataNucleus and fastjson2 live here, but say if you'd rather put it elsewhere.
  • twilio-recordings-decrypter gets an httpclient dependency it no longer needs: AddDependency scans before the NetworkHttpClient change lands. It's harmless, and excluding it would mean listing org.apache.http packages one by one.
  • recipes.csv has only the 11 new rows. recipeCsvGenerate also rewrites about 150 stale rows, which I left out of this diff.
  • Regenerating classpath.tsv.gz also adds mockito-all:1.10.19, already declared in build.gradle.kts since Fix legacy Mockito and Java 25 agent migration #1393 but missing from the committed table. No existing rows changed.

No recipe covered `com.twilio.sdk:twilio`. This raises it to 13.x, declares
what the SDK stopped bringing along, and changes the calls that have a
mechanical replacement. Calls that need a decision are left for the compiler.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

1 participant