Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
with:
distribution: 'zulu'
java-version: '17'

- name: SonarCloud Scan
if: ${{ (github.event_name == 'pull_request' || github.ref_type == 'branch') && matrix.java == 11 && !github.event.pull_request.head.repo.fork }}
env:
Expand Down Expand Up @@ -94,7 +94,7 @@ jobs:
- name: Create GitHub Release
uses: sendgrid/dx-automator/actions/release@main
with:
footer: '**[Maven](https://mvnrepository.com/artifact/com.twilio.sdk/twilio/${version})**'
footer: '**[Maven](https://central.sonatype.com/artifact/com.twilio.sdk/twilio/${version})**'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Expand Down
50 changes: 50 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,56 @@
twilio-java changelog
=====================

[2025-07-24] Version 11.0.0-rc.3
--------------------------------
**Events**
- Remove `SinkSid` parameter when updating subscriptions. **(breaking change)**

**Twiml**
- Remove Duplicates.
- Add Polly Generative voices.
- Add Latest Google (Chirp3-HD) voices.


[2025-07-10] Version 11.0.0-rc.2
--------------------------------
**Flex**
- update team name for web_channel, webchat_init_token, webchat_refresh_token


[2025-07-03] Version 11.0.0-rc.1
--------------------------------
**Library - Chore**
- [PR #875](https://github.com/twilio/twilio-java/pull/875): prepare for RC release. Thanks to [@tiwarishubham635](https://github.com/tiwarishubham635)!
- [PR #874](https://github.com/twilio/twilio-java/pull/874): Handle List<Object> serialization. Thanks to [@tiwarishubham635](https://github.com/tiwarishubham635)!
- [PR #873](https://github.com/twilio/twilio-java/pull/873): use Object for anyType. Thanks to [@tiwarishubham635](https://github.com/tiwarishubham635)!

**Bulkexports**
- Changed the type of 'details' field to be a list of objects instead of a single object

**Conversations**
- Updates to `method` casing for ConfgurationAddress, ConversationScopedWebhook, and ServiceConversationScopedWebhook for RestProxy compatibility

**Proxy**
- remove shortcodes resource as its no longer used

**Serverless**
- Change log field level from type `ienum` to `string` in Logs api

**Taskrouter**
- Remove `URL-encoded` from attributes param definition in tasks

**Trunking**
- Added `symmetric_rtp_enabled` property on Trunks.

**Twiml**
- Add support for `<WhatsApp>` noun under `<Dial>` verb


[2025-07-03] Version 11.0.0-rc.0
--------------------------------
- Release Candidate prep

[2025-06-12] Version 10.9.2
---------------------------
**Library - Chore**
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ Use the following dependency in your project to grab via Maven:
<dependency>
<groupId>com.twilio.sdk</groupId>
<artifactId>twilio</artifactId>
<version>10.X.X</version>
<version>11.X.X-rc.x</version>
<scope>compile</scope>
</dependency>
```

or Gradle:

```groovy
implementation "com.twilio.sdk:twilio:10.X.X"
implementation "com.twilio.sdk:twilio:11.X.X-rc.x"
```

If you want to compile it yourself, here's how:
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<artifactId>twilio</artifactId>
<packaging>jar</packaging>
<name>twilio</name>
<version>10.9.2</version>
<version>11.0.0-rc.3</version>
<description>Twilio Java Helper Library</description>
<url>https://www.twilio.com</url>
<licenses>
Expand All @@ -19,7 +19,7 @@
<url>git@github.com:twilio/twilio-java.git</url>
<connection>scm:git:git@github.com:twilio/twilio-java.git</connection>
<developerConnection>scm:git:git@github.com:twilio/twilio-java.git</developerConnection>
<tag>10.9.2</tag>
<tag>11.0.0-rc.3</tag>
</scm>
<developers>
<developer>
Expand Down
2 changes: 0 additions & 2 deletions src/main/java/com/twilio/Domains.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,9 @@ public enum Domains {
INSIGHTS("insights"),
INTELLIGENCE("intelligence"),
IPMESSAGING("ip-messaging"),
KNOWLEDGE("knowledge"),
LOOKUPS("lookups"),
MARKETPLACE("marketplace"),
MESSAGING("messaging"),
MICROVISOR("microvisor"),
MONITOR("monitor"),
NOTIFY("notify"),
NUMBERS("numbers"),
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/twilio/Twilio.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
*/
public class Twilio {

public static final String VERSION = "10.9.2";
public static final String VERSION = "11.0.0-rc.3";
public static final String JAVA_VERSION = System.getProperty("java.version");
public static final String OS_NAME = System.getProperty("os.name");
public static final String OS_ARCH = System.getProperty("os.arch");
Expand All @@ -37,7 +37,7 @@ public class Twilio {
private static String edge = System.getenv("TWILIO_EDGE");
private static volatile TwilioRestClient restClient;
private static volatile ExecutorService executorService;

private static CredentialProvider credentialProvider;

private Twilio() {
Expand Down Expand Up @@ -85,7 +85,7 @@ private static void setCredentialProvider(final CredentialProvider credentialPro
if (credentialProvider == null) {
throw new AuthenticationException("Credential Provider can not be null");
}

if (!credentialProvider.equals(Twilio.credentialProvider)) {
Twilio.invalidate();
}
Expand Down Expand Up @@ -315,7 +315,7 @@ private static void invalidate() {
private static void invalidateOAuthCreds() {
Twilio.credentialProvider = null;
}

private static void invalidateBasicCreds() {
Twilio.username = null;
Twilio.password = null;
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/com/twilio/base/ResourceSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class ResourceSet<E extends Resource> implements Iterable<E> {

private final Reader<E> reader;
private final TwilioRestClient client;
private final Page<E> firstPage; // Store reference to first page to enable multiple iterations

private boolean autoPaging;
private long pages = 1;
Expand All @@ -32,6 +33,7 @@ public class ResourceSet<E extends Resource> implements Iterable<E> {
public ResourceSet(final Reader<E> reader, final TwilioRestClient client, final Page<E> page) {
this.reader = reader;
this.client = client;
this.firstPage = page; // Save first page to allow resetting iterator state
this.page = page;
this.iterator = page.getRecords().iterator();
this.autoPaging = true;
Expand Down Expand Up @@ -74,6 +76,12 @@ public long getPageLimit() {

@Override
public Iterator<E> iterator() {
// Reset state to allow multiple iterations
this.processed = 0;
this.pages = 1;
this.page = this.firstPage; // Reset to first page for new iteration
this.iterator = this.firstPage.getRecords().iterator(); // Reset iterator to start of first page

return new ResourceSetIterator<>(this);
}

Expand Down
8 changes: 8 additions & 0 deletions src/main/java/com/twilio/base/bearertoken/ResourceSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class ResourceSet<E extends Resource> implements Iterable<E> {

private final Reader<E> reader;
private final BearerTokenTwilioRestClient client;
private final Page<E> firstPage; // Store reference to first page to enable multiple iterations

private boolean autoPaging;
private long pages = 1;
Expand All @@ -32,6 +33,7 @@ public class ResourceSet<E extends Resource> implements Iterable<E> {
public ResourceSet(final Reader<E> reader, final BearerTokenTwilioRestClient client, final Page<E> page) {
this.reader = reader;
this.client = client;
this.firstPage = page; // Save first page to allow resetting iterator state
this.page = page;
this.iterator = page.getRecords().iterator();
this.autoPaging = true;
Expand Down Expand Up @@ -74,6 +76,12 @@ public long getPageLimit() {

@Override
public Iterator<E> iterator() {
// Reset state to allow multiple iterations
this.processed = 0;
this.pages = 1;
this.page = this.firstPage; // Reset to first page for new iteration
this.iterator = this.firstPage.getRecords().iterator(); // Reset iterator to start of first page

return new ResourceSetIterator<>(this);
}

Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/twilio/constant/EnumConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,15 @@ public enum AuthType {

private final String value;
}

@Getter
@RequiredArgsConstructor
public enum ParameterType {
QUERY("Query"),
HEADER("Header"),
URLENCODED("Urlencoded"),
JSON("Json");

private final String value;
}
}
100 changes: 100 additions & 0 deletions src/main/java/com/twilio/converter/Serializer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package com.twilio.converter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.twilio.constant.EnumConstants.ParameterType;
import com.twilio.exception.ApiConnectionException;
import com.twilio.exception.ApiException;
import com.twilio.http.Request;
import java.io.IOException;

import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Objects;

public class Serializer {

public static <T> void toString(Request request, String key, T value, ParameterType parameterType) {
if (value == null) return;

String stringValue = convertToString(value);
addParamToRequest(request, key, stringValue, parameterType);
}

public static <T> void toString(Request request, ObjectMapper mapper, T value) {
if (value == null) return;

if (mapper == null) {
throw new IllegalArgumentException("ObjectMapper is required for JSON serialization");
}

String stringValue = toJson(value, mapper);
request.setBody(stringValue);
}

public static String toJson(Object object, ObjectMapper mapper) {
try {
return mapper.writeValueAsString(object);
} catch (final JsonMappingException e) {
throw new ApiException(e.getMessage(), e);
} catch (JsonProcessingException e) {
throw new ApiException(e.getMessage(), e);
} catch (final IOException e) {
throw new ApiConnectionException(e.getMessage(), e);
}
}

private static <T> String convertToString(T value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The objectToJson() can be used here instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean using mapper to convert to string ?
We can not use it, because \n (new line) is treated as actual new line for toString method, whereas mapper keep /n as it as.

if (value instanceof Map) {
return Converter.mapToJson((Map<String, ? extends Object>) value);
Copy link
Preview

Copilot AI Sep 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cast to (Map<String, ? extends Object>) is unsafe and may cause ClassCastException at runtime. Consider using a type-safe approach with instanceof checks or generic bounds to ensure the cast is valid.

Suggested change
return Converter.mapToJson((Map<String, ? extends Object>) value);
Map<?, ?> map = (Map<?, ?>) value;
boolean allStringKeys = true;
for (Object key : map.keySet()) {
if (!(key instanceof String)) {
allStringKeys = false;
break;
}
}
if (allStringKeys) {
@SuppressWarnings("unchecked")
Map<String, ? extends Object> stringKeyMap = (Map<String, ? extends Object>) map;
return Converter.mapToJson(stringKeyMap);
} else {
// Fallback: not a Map<String, ?>, use toString
return String.valueOf(value);
}

Copilot uses AI. Check for mistakes.

} else {
return String.valueOf(value);
}
}

private static void addParamToRequest(Request request, String key, String value, ParameterType parameterType) {
Objects.requireNonNull(parameterType, "ParameterType cannot be null");
switch (parameterType) {
case HEADER:
request.addHeaderParam(key, value);
break;
case QUERY:
request.addQueryParam(key, value);
break;
case URLENCODED:
request.addPostParam(key, value);
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How will body params be added?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed json content type serialization.

case JSON:
request.setBody(value);
default:
throw new IllegalArgumentException("Unsupported ParameterType: " + parameterType);
}
}

/*
Inequality fields are only supported in Query parameters.
dateBefore is upperBound and dateAfter is lowerBound
*/
public static void toString(final Request request, final String key, LocalDate date, LocalDate dateBefore, LocalDate dateAfter) {
if (date != null) {
request.addQueryParam(key, date.format(DateTimeFormatter.ofPattern(Request.QUERY_STRING_DATE_FORMAT)));
} else if (dateAfter != null || dateBefore != null) {
request.addQueryDateRange(key, dateAfter, dateBefore);
}
}

/*
Inequality fields are only supported in Query parameters.
dateBefore is upperBound and dateAfter is lowerBound
*/
public static void toString(final Request request, final String key, ZonedDateTime date, ZonedDateTime dateBefore, ZonedDateTime dateAfter) {
if (date != null) {
request.addQueryParam(key, date.format(DateTimeFormatter.ofPattern(Request.QUERY_STRING_DATE_TIME_FORMAT)));
} else if (dateAfter != null || dateBefore != null) {
request.addQueryDateTimeRange(key, dateAfter, dateBefore);
}
}
}
4 changes: 1 addition & 3 deletions src/main/java/com/twilio/rest/accounts/v1/BulkConsents.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ public class BulkConsents extends Resource {

private static final long serialVersionUID = 126137950684284L;

public static BulkConsentsCreator creator(
final List<Map<String, Object>> items
) {
public static BulkConsentsCreator creator(final List<Object> items) {
return new BulkConsentsCreator(items);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,21 @@
import com.twilio.rest.Domains;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;

public class BulkConsentsCreator extends Creator<BulkConsents> {

private List<Map<String, Object>> items;
private List<Object> items;

public BulkConsentsCreator(final List<Map<String, Object>> items) {
public BulkConsentsCreator(final List<Object> items) {
this.items = items;
}

public BulkConsentsCreator setItems(final List<Map<String, Object>> items) {
public BulkConsentsCreator setItems(final List<Object> items) {
this.items = items;
return this;
}

public BulkConsentsCreator setItems(final Map<String, Object> items) {
public BulkConsentsCreator setItems(final Object items) {
return setItems(Promoter.listOfOne(items));
}

Expand Down Expand Up @@ -89,8 +87,8 @@ public BulkConsents create(final TwilioRestClient client) {

private void addPostParams(final Request request) {
if (items != null) {
for (Map<String, Object> prop : items) {
request.addPostParam("Items", Converter.mapToJson(prop));
for (Object prop : items) {
request.addPostParam("Items", Converter.objectToJson(prop));
}
}
}
Expand Down
4 changes: 1 addition & 3 deletions src/main/java/com/twilio/rest/accounts/v1/BulkContacts.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ public class BulkContacts extends Resource {

private static final long serialVersionUID = 126137950684284L;

public static BulkContactsCreator creator(
final List<Map<String, Object>> items
) {
public static BulkContactsCreator creator(final List<Object> items) {
return new BulkContactsCreator(items);
}

Expand Down
Loading