
Announcing Vonage Java SDK v9.0.0
Introduction
A lot has changed in the Java SDK since the last announcement post - over 39 thousand lines of code in fact! This major release has been a long time coming, with a ton of improvements and yes, the inevitable breaking changes as a result of removals and refactorings. I am excited to finally share these updates with you, as the SDK's quality has levelled up even further, with 100% test coverage as a result - the same is true for our Kotlin SDK!
Up-to-date Implementations
Naturally, keeping up to date with the latest SDK version is the best way to ensure all the functionality of supported APIs is available, along with bug fixes and security updates of course. In particular, several updates have been made to Messages API, with additional optional properties on inbound and outbound messages, new supported message types for MMS, WhatsApp Reaction & Button messages, the ability to mark WhatsApp messages as read, and, of course, support for RCS messaging. On the Video API, the implementation has been updated to support Live Captions, Audio Connector, Experience Composer, the Publisher-only role in session tokens, end-to-end encryption, maximum bitrate and quantization parameters for Archives, and various bug and inconsistency fixes.
Webhooks have been overhauled and simplified too, being moved into the appropriate packages for their respective APIs. For Voice, you can use AnswerWebhook and EventWebhook for deserialising webhooks depending on the type (since the answer and event URLs are usually sent to different endpoints). For SMS API, use MessageEvent to parse inbound message webhooks.
New APIs
Three new supported APIs have been added since the last major release:
Conversation API
The long-awaited implementation of Conversation API was initially added to the Java SDK in v8.4.0 but has since been improved with support for nearly all event types. This low-level API underpins the inner workings of the Voice API, offering more powerful capabilities to handle multi-participant omni-channel calls and chats. It is undoubtedly the biggest and most complex API supported in the SDK, which advanced / power users can now make use of with a fully-fledged, strongly typed implementation rather than relying on the REST API reference.
SIM Swap
The SIM Swap API is one of Vonage's network APIs. This allows you to check whether the SIM card associated with a number has been swapped to a different device. By default, this checks within the past 10 days, but can be set to any period within the past 100 days, to the nearest hour. Note that this is currently only available for German and Spanish numbers (see availability for Network APIs). Still, you can try it out using our Playground with Virtual Operators. Although the API call is a 3-step process due to OAuth, the SDK simplifies this into a single method call which automates all of this for you.
Number Verification
Not to be confused with Number Insight, the Number Verification API is another network API which enables developers to check whether the user's device matches their mobile number. This is integrated already into the Silent Authentication workflow in Verify API - see the code snippets for example usage. The Number Verification API is slightly more complex since it requires multiple API calls. The first stage builds a URL that you can pass on to the user to follow on their device connected to the network. This will then result in a callback with a code being sent to your server, which you then pass to the API to verify the number and device match. Currently, the same restrictions apply as SIM Swap API described above.
Quality of Life Improvements
Major releases provide a great opportunity to address technical debt that naturally accrues over the SDK's lifecycle as it evolves. This release is no exception, with a slew of deprecations since the last major release. These deprecations - except VonageClient.Builder#setHttpClient - have all been removed. The setHttpClient method still exists for customers who need more bespoke options, but many can be achieved using httpConfig instead, such as proxying, request timeouts, and setting base URIs; all of which are available on HttpConfig.Builder.
Besides the removal of sunset APIs - Meetings and Proactive Connect - this release also tidies up the rough edges around the SDK and further encapsulates internal methods, classes, and constructors to provide a more consistent and streamlined way to interact with the SDK and minimise confusion. To borrow from the Python mantra:
"There should be one - and preferably only one - obvious way to do it."
Consequently, this release's breaking changes are mostly around addressing inconsistencies. The majority of refactorings and changes won't affect most users and the ones that do require minimal refactorings. The main things to watch out for are relocated enums (elaborated further below), more specific return types instead of String where applicable, and a few places where methods have been renamed in favour of more consistent or simpler alternatives. Hopefully, these should be relatively straightforward to resolve, especially with help from your IDE and with the comprehensive Javadocs, however, it may be helpful to refer to the changelog for an overview of any changes not described in this article. For most deprecations which have been removed, the alternative will have been described in the Javadoc, so it may be easier to focus on addressing deprecated usages first before upgrading to v9.0.0 for a smoother transition.
Logging
Debugging and traceability are important in any application, so this aspect was improved in v8.16.0. Given the myriad of logging frameworks in the Java ecosystem and the now infamous Log4j vulnerability that was discovered a few years ago, the Java SDK relies on the built-in java.util.logging facility, further minimising dependencies, and potential compatibility issues. Logging is mainly performed in AbstractMethod#execute(REQ) if the log level is set to FINE. The request is logged prior to the API call being made - including the full URI, request method, query parameters, and request body. If the call was successful, the response body is also logged, if present. For even finer level logging, see DynamicEndpoint.parseResponse.
Standardised JSON objects
Since version 7.7.0, a substantial refactoring of the SDK introduced the Jsonable interface for request and response objects. Now, these objects all extend the JsonableBaseObject class. This implements the equals, hashCode, and toString methods reflectively based on the object's fields, and you can both serialise and deserialise JSON payloads based on the object's data model using the toJson and fromJson methods. The latter is implemented as a static method on the Jsonable interface.
Standardised Enum Parsing
One of the main breaking changes in this release is how enums are handled. Most enums have now been moved out of inner classes to the upper level where it makes sense to do so, and some relocated to the com.vonage.client.common package if they are used by multiple APIs. Furthermore, the deserialisation has been standardised across the board, relying on the Jsonable.fromString method. If the string representation does not match a known value, it will return null instead of throwing an IllegalArgumentException. This allows the rest of the object data model to be populated, as it would otherwise have been prevented. For consistency with this approach, the UNKNOWN value in most enums has been removed, unless it is a literal valid value that can be returned from the API (as is the case in Number Insight, for example).
Stronger Typing
Elaborating further on breaking changes, this release improves types used in data model objects. Several return types have been changed from strings to enums, or a more appropriate type, such as UUID, URI, Double, etc. Updating your application to work with these changes should hopefully be straightforward and self-explanatory, but are described more fully in the changelog.
Voice API
The most transformative changes are apparent in the Voice API implementation. Every method and class is now fully documented, and many of the inconsistencies are addressed. All setter methods have been removed and replaced with builders instead. Besides new features and bug fixes, there have been a lot of changes to the Voice API. For example, builders will now only accept a single URL for parameters such as eventUrl. Even though this must be wrapped in an array when serialised as JSON, the SDK hides this to avoid confusion. The same is true for endpoints in Call and ConnectAction - only a single endpoint can be used, but previously the SDK gave the impression that multiple destination endpoints can be specified when in fact it is only because the endpoint must be wrapped in a JSON array. Speaking of endpoints, you may have encountered some confusion when using NCCOs to connect a call, since there were two classes: com.vonage.client.voice.Endpoint and com.vonage.client.voice.ncco.Endpoint. The former is used in Call, whilst the latter is used in the ConnectAction NCCO. These have now been renamed CallEndpoint and ConnectEndpoint respectively to avoid clashes and requiring fully-qualified class names, so you can import both. Finally, there has been some standardisation in CallsFilter (which now extends HalFilterRequest), which uses Instant instead of the outdated Date class (pun intended!), and CallInfoPage, which now extends HalPageResponse. Note that the EmbeddedCalls class has been removed, so you can access the list of calls more directly with the getCallInfos() method on CallInfoPage. Finally, as previously mentioned, stronger typing is used where applicable (for example, rate and price in CallInfo are now Doubles instead of Strings), and enums have been moved out of inner classes.
Numbers API
In v8.10.0, the Numbers API implementation was updated not only to add missing properties but also to improve documentation. The setters have been removed in favour of builders for consistency with other APIs. Linking numbers to an application now works as intended, since the missing property for this has been added. The NumbersClient#listNumbers method now returns a List<OwnedNumber> directly instead of ListNumbersResponse, saving you an additional method call since this additional wrapping is unnecessary.
Number Insight API
Users of the Number Insight API will be pleased to read that support for asynchronous Advanced insight has now been implemented properly, with the correct request and response types, as opposed to the hacky solution which set a boolean flag on the synchronous Advanced insight in previous versions. The callback parameter is mandatory for async advanced insights, as this is where the full response will be delivered, which can then be parsed into AdvancedInsightResponse using the Jsonable.fromJson(String, Class) method.
As a side note, you may be wondering what happened to Number Insight v2. Technically this API was in Beta and so it has been removed in this release, having been added in v8.2.0. The API has been renamed to Fraud Detection, but we have bigger plans later for fraud detection & prevention, as well as Number Insight, so stay tuned for further updates.
Messages API Interfaces
If you've ever tried to do multi-channel or multi-media message building using the Messages API in the Java SDK, you may have come across the issue of needing to handle each channel and type combination individually, even if the code for each case is identical. For example, consider the code used to demo all channel and message type combinations in this SpringBoot application. What's the commonality? Well, all text messages (i.e. when the MessageType is TEXT) have a text(String) method on the builder. Similarly, all media messages (i.e. when the MessageType is FILE, IMAGE, AUDIO, VIDEO, or VCARD) have a url(String) method on their builders. There are two ways these could be refactored to be set in one place without repetition. The hacky workaround way is via reflection. A better option would be through an interface. That's exactly what has been implemented since v8.11.0. You can now cast the text message builders to TextMessageRequest.Builder, and MediaMessageRequest for messages with a URL field. Since some channels also support an optional caption property, there is also CaptionMediaMessageRequest, which extends MediaMessageRequest with this property. Consequently, applying a URL, caption or text can now be performed polymorphically across multiple channels.
Application API Webhooks
Whilst developing the Kotlin SDK last year, I noticed that the Java SDK's handling of Capabilities in the Application API left much to be desired, due to its needless verbosity and the fact that it's not correct by construction. The Kotlin SDK implementation corrected this by ensuring that the webhook types (e.g. event_url, status_url, answer_url, etc.) could only be applied to capabilities that support them. The capability builders in the Java SDK have been updated to be correct by construction, which means that the addWebhook and removeWebhook methods have been replaced by type-specific methods. For example, in the com.vonage.client.application.capabilities.Voice.Builder class, there are now methods event, answer, and fallbackAnswer. For the Messages capability, there's status and event. Each of these methods will set the appropriate property in the JSON payload, making the builders more declarative, less verbose, and correct by construction. To remove a webhook, you can simply pass null as the input to these methods.
Kotlin SDK v2.0.0
Since the Kotlin SDK is built on top of the Java SDK, it has been updated to be compatible with the breaking changes introduced in v9.0.0, which includes removing deprecations, features that are no longer supported such as the old Pricing API, and WhatsApp Codeless workflow in Verify API. The Kotlin SDK follows Semantic Versioning as you would expect, hence the 2.0.0 release.
Code Snippets
A quick note on documentation: although you can find inline code documentation straight from your IDE or from a Javadoc renderer (works for both Java SDK and Kotlin SDK), and you can, of course, find code snippets in our Developer Portal for each product, you may want a concise single-page view of code samples demonstrating how to use each API with the SDK. I'm pleased to announce that the generation of such a file has now been automated for both Java and Kotlin, so you can Ctrl-F to your heart's content!
Future Plans
The Java (and by extension, Kotlin) SDK continues to support Java 8 as the minimum required runtime even in this major release. It is wild to think that Java 8, which was released 11 years ago at the time of writing, is still relevant and used in 2025. However, popular frameworks have migrated towards Java 17 as a minimum, and even the main build tools we rely on (Maven, Gradle) have deprecated Java 8 support. Furthermore, the Apache HTTP Client 4 which the Java SDK is based on has ceased active development. Meanwhile, support for asynchronous/reactive calls has long been requested. To facilitate this, and perhaps for security updates alone, it would be prudent to move the baseline to Java 11, which introduced a built-in HTTP client into the JDK. By leveraging this instead of an external dependency, the footprint of the SDK can be further reduced whilst pushing the maintenance and security burden of the underlying HTTP client to the platform itself. Thus, I would encourage you to migrate away from Java 8 both as a general good practice and in preparation for the next major release.
Conclusion
And that's all the changes you should know about in version 9.0.0 of the Java SDK and the accompanying 2.0.0 release of the Kotlin SDK. For a more comprehensive summary of changes, see CHANGELOG.md for Java and Kotlin SDKs respectively. If you do come across any issues or have suggestions for enhancements, feel free to raise an issue on GitHub or drop by our Community Slack. I hope you have a great experience using the Vonage APIs with the latest version of the Java and Kotlin SDKs!
Share:
)
Sina is a Java Developer Advocate at Vonage. He comes from an academic background and is generally curious about anything related to cars, computers, programming, technology and human nature. In his spare time, he can be found walking or playing competitive video games.