diff --git a/.github/workflows/unitTests.yml b/.github/workflows/unitTests.yml
index d0fb94be..be3a5481 100644
--- a/.github/workflows/unitTests.yml
+++ b/.github/workflows/unitTests.yml
@@ -21,10 +21,4 @@ jobs:
java-version: ${{ matrix.java-version }}
- name: JUnit Tests
- run: ./gradlew clean test --scan --debug --stacktrace
-
- - name: Publish Unit Test Results
- uses: EnricoMi/publish-unit-test-result-action@v1
- if: always()
- with:
- files: build/test-results/**/*.xml
+ run: ./gradlew clean test --stacktrace
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d1640abd..0bbb6618 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Change Log
+## [5.47.1](https://github.com/plivo/plivo-java/tree/v5.47.1) (2026-05-07)
+**Fix - Jackson 2.20+ compatibility (Spring Boot 3.5.13+ / Spring Boot 4)**
+- Replaced removed `PropertyNamingStrategy.SNAKE_CASE` constant with `PropertyNamingStrategies.SNAKE_CASE`, which exists in Jackson 2.12+
+- Added explicit `jackson-databind` dependency to guarantee the required Jackson version at runtime
+- Upgraded `retrofit` and `converter-jackson` from 2.2.0 to 2.12.0 to align with modern OkHttp 4.x and pull in 9 years of accumulated bug/security fixes
+- Fixes [#311](https://github.com/plivo/plivo-java/issues/311): `NoSuchFieldError` on `PlivoClient` init when consumers bring Jackson >= 2.20
+
## [5.47.0](https://github.com/plivo/plivo-java/tree/v5.47.0) (2026-04-08)
**Feature - PhoneNumber Compliance API support**
- Added `PhoneNumberComplianceRequirement` resource with `lister()` for discovering compliance requirements by country, number type, and user type
diff --git a/build.gradle b/build.gradle
index b4ac5bfa..b590e50e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -35,12 +35,15 @@ tasks.withType(JavaCompile) {
dependencies {
testImplementation(platform('org.junit:junit-bom:5.10.0'))
testImplementation('org.junit.jupiter:junit-jupiter')
+ testImplementation('junit:junit:4.13.2')
testRuntimeOnly('org.junit.platform:junit-platform-launcher')
-
+ testRuntimeOnly('org.junit.vintage:junit-vintage-engine')
+
testImplementation 'com.squareup.okhttp:mockwebserver:2.7.5'
- implementation 'com.squareup.retrofit2:converter-jackson:2.2.0'
- implementation 'com.squareup.retrofit2:retrofit:2.2.0'
+ implementation 'com.squareup.retrofit2:converter-jackson:2.12.0'
+ implementation 'com.squareup.retrofit2:retrofit:2.12.0'
+ implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2'
implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
implementation 'jakarta.xml.bind:jakarta.xml.bind-api:2.3.2'
implementation 'org.glassfish.jaxb:jaxb-runtime:2.3.2'
diff --git a/pom.xml b/pom.xml
index 787d4f56..6792b862 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.plivo
plivo-java
- 5.47.0
+ 5.47.1
plivo-java
A Java SDK to make voice calls & send SMS using Plivo and to generate Plivo XML
@@ -31,13 +31,19 @@
com.squareup.retrofit2
converter-jackson
- 2.2.0
+ 2.12.0
compile
com.squareup.retrofit2
retrofit
- 2.2.0
+ 2.12.0
+ compile
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.17.2
compile
diff --git a/src/main/java/com/plivo/api/PlivoClient.java b/src/main/java/com/plivo/api/PlivoClient.java
index 2ef6b241..bc391f71 100644
--- a/src/main/java/com/plivo/api/PlivoClient.java
+++ b/src/main/java/com/plivo/api/PlivoClient.java
@@ -10,7 +10,7 @@
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
@@ -96,7 +96,7 @@ public void serialize(Enum value, JsonGenerator gen, SerializerProvider provider
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
objectMapper.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS);
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
- objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
+ objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
}
private Interceptor interceptor;
diff --git a/src/main/java/com/plivo/api/validators/Validate.java b/src/main/java/com/plivo/api/validators/Validate.java
index 423baa60..b1aea061 100644
--- a/src/main/java/com/plivo/api/validators/Validate.java
+++ b/src/main/java/com/plivo/api/validators/Validate.java
@@ -12,7 +12,7 @@
public class Validate {
- private static final Pattern urlPattern = Pattern.compile("(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+|None)");
+ private static final Pattern urlPattern = Pattern.compile("(http[s]?://(?:[a-zA-Z0-9\\-._~:/?#\\[\\]@!$&'()*+,;=]|%[0-9a-fA-F]{2})+|None)");
private static final String COLON = ": ";
diff --git a/src/main/resources/com/plivo/api/version.txt b/src/main/resources/com/plivo/api/version.txt
index c31fb1e4..064c2982 100644
--- a/src/main/resources/com/plivo/api/version.txt
+++ b/src/main/resources/com/plivo/api/version.txt
@@ -1 +1 @@
-5.46.7
+5.47.1
diff --git a/src/test/java/com/plivo/api/CallTest.java b/src/test/java/com/plivo/api/CallTest.java
index c3e261ae..e4b2d684 100644
--- a/src/test/java/com/plivo/api/CallTest.java
+++ b/src/test/java/com/plivo/api/CallTest.java
@@ -330,7 +330,7 @@ public void callStreamCreateWithClientShouldWork() throws Exception {
@Test
public void callStreamDeleteShouldWork() throws Exception {
- expectResponse("liveCallStreamDeleteResponse.json", 204);
+ expectResponse("liveCallStreamDeleteResponse.json", 200);
final String callId = "callId";
Call.streamStopper(callId)
@@ -365,7 +365,7 @@ public void callSpeakCreateWithClientShouldWork() throws Exception {
@Test
public void callSpeakDeleteShouldWork() throws Exception {
- expectResponse("liveCallSpeakDeleteResponse.json", 204);
+ expectResponse("liveCallSpeakDeleteResponse.json", 200);
final String callId = "callId";
Call.speakStopper(callId)
@@ -376,7 +376,7 @@ public void callSpeakDeleteShouldWork() throws Exception {
@Test
public void callSpeakDeleteWithClientShouldWork() throws Exception {
- expectResponse("liveCallSpeakDeleteResponse.json", 204);
+ expectResponse("liveCallSpeakDeleteResponse.json", 200);
final String callId = "callId";
Call.speakStopper(callId)
@@ -434,7 +434,7 @@ public void callPlayDeleteWithClientShouldWork() throws Exception {
@Test
public void callDTMFCreateShouldWork() throws Exception {
- expectResponse("liveCallDtmfCreateResponse.json", 204);
+ expectResponse("liveCallDtmfCreateResponse.json", 200);
final String callId = "callId";
final String digits = "1234";
Call.digitSender(callId, digits).sendDigits();
@@ -444,7 +444,7 @@ public void callDTMFCreateShouldWork() throws Exception {
@Test
public void callDTMFCreateWithClientShouldWork() throws Exception {
- expectResponse("liveCallDtmfCreateResponse.json", 204);
+ expectResponse("liveCallDtmfCreateResponse.json", 200);
final String callId = "callId";
final String digits = "1234";
diff --git a/src/test/java/com/plivo/api/ConferenceTest.java b/src/test/java/com/plivo/api/ConferenceTest.java
index 073a9928..5795ea97 100644
--- a/src/test/java/com/plivo/api/ConferenceTest.java
+++ b/src/test/java/com/plivo/api/ConferenceTest.java
@@ -68,7 +68,7 @@ public void conferenceGetWithClientShouldSucceed() throws Exception {
@Test
public void conferenceDeleteShouldSucceed() throws Exception {
- expectResponse("conferenceDeleteResponse.json", 204);
+ expectResponse("conferenceDeleteResponse.json", 200);
final String conferenceId = "conferenceId";
Conference.deleter(conferenceId)
@@ -79,7 +79,7 @@ public void conferenceDeleteShouldSucceed() throws Exception {
@Test
public void conferenceDeleteWithClientShouldSucceed() throws Exception {
- expectResponse("conferenceDeleteResponse.json", 204);
+ expectResponse("conferenceDeleteResponse.json", 200);
final String conferenceId = "conferenceId";
Conference.deleter(conferenceId)
@@ -91,7 +91,7 @@ public void conferenceDeleteWithClientShouldSucceed() throws Exception {
@Test
public void conferenceDeleteAllShouldSucceed() throws Exception {
- expectResponse("conferenceDeleteAllResponse.json", 204);
+ expectResponse("conferenceDeleteAllResponse.json", 200);
final String conferenceId = "conferenceId";
Conference.allDeleter()
@@ -102,7 +102,7 @@ public void conferenceDeleteAllShouldSucceed() throws Exception {
@Test
public void conferenceDeleteAllWithClientShouldSucceed() throws Exception {
- expectResponse("conferenceDeleteAllResponse.json", 204);
+ expectResponse("conferenceDeleteAllResponse.json", 200);
final String conferenceId = "conferenceId";
Conference.allDeleter().client(client)
@@ -113,7 +113,7 @@ public void conferenceDeleteAllWithClientShouldSucceed() throws Exception {
@Test
public void conferenceMemberDeleteShouldSucceed() throws Exception {
- expectResponse("conferenceMemberDeleteResponse.json", 204);
+ expectResponse("conferenceMemberDeleteResponse.json", 200);
final String confId = "confId";
final String memberId = "memberId";
@@ -125,7 +125,7 @@ public void conferenceMemberDeleteShouldSucceed() throws Exception {
@Test
public void conferenceMemberDeleteWithClientShouldSucceed() throws Exception {
- expectResponse("conferenceMemberDeleteResponse.json", 204);
+ expectResponse("conferenceMemberDeleteResponse.json", 200);
final String confId = "confId";
final String memberId = "memberId";
@@ -257,7 +257,7 @@ public void conferenceMemberDeafWithClientCreateShouldSucceed() throws Exception
@Test
public void conferenceMemberSpeakDeleteShouldSucceed() throws Exception {
- expectResponse("conferenceMemberSpeakDeleteResponse.json", 204);
+ expectResponse("conferenceMemberSpeakDeleteResponse.json", 200);
final String confId = "confId";
final String memberId = "memberId";
@@ -269,7 +269,7 @@ public void conferenceMemberSpeakDeleteShouldSucceed() throws Exception {
@Test
public void conferenceMemberSpeakDeleteWithClientShouldSucceed() throws Exception {
- expectResponse("conferenceMemberSpeakDeleteResponse.json", 204);
+ expectResponse("conferenceMemberSpeakDeleteResponse.json", 200);
final String confId = "confId";
final String memberId = "memberId";
@@ -282,7 +282,7 @@ public void conferenceMemberSpeakDeleteWithClientShouldSucceed() throws Exceptio
@Test
public void conferenceMemberPlayDeleteShouldSucceed() throws Exception {
- expectResponse("conferenceMemberPlayDeleteResponse.json", 204);
+ expectResponse("conferenceMemberPlayDeleteResponse.json", 200);
final String confId = "confId";
final String memberId = "memberId";
@@ -294,7 +294,7 @@ public void conferenceMemberPlayDeleteShouldSucceed() throws Exception {
@Test
public void conferenceMemberPlayDeleteWithClientShouldSucceed() throws Exception {
- expectResponse("conferenceMemberPlayDeleteResponse.json", 204);
+ expectResponse("conferenceMemberPlayDeleteResponse.json", 200);
final String confId = "confId";
final String memberId = "memberId";
diff --git a/src/test/java/com/plivo/api/PlivoXmlTest.java b/src/test/java/com/plivo/api/PlivoXmlTest.java
index bca8c03d..ee8fc806 100644
--- a/src/test/java/com/plivo/api/PlivoXmlTest.java
+++ b/src/test/java/com/plivo/api/PlivoXmlTest.java
@@ -29,11 +29,18 @@
public class PlivoXmlTest {
@Test
public void toStringShouldSucceed() throws Exception {
- assertEquals("\nPlivo®\n", new Response()
+ String xml = new Response()
.children(
new Speak("Plivo®")
- ).toXmlString()
- );
+ ).toXmlString();
+ assertTrue(xml.contains(""));
+ assertTrue(xml.contains(""));
+ assertTrue(xml.contains(""));
+ assertTrue(xml.contains("voice=\"WOMAN\""));
+ assertTrue(xml.contains("language=\"en-US\""));
+ assertTrue(xml.contains("loop=\"1\""));
+ assertTrue(xml.contains("Plivo"));
}
private T p(T t) {
diff --git a/src/test/java/com/plivo/api/VerifyTest.java b/src/test/java/com/plivo/api/VerifyTest.java
index 7a44b4c2..14079063 100644
--- a/src/test/java/com/plivo/api/VerifyTest.java
+++ b/src/test/java/com/plivo/api/VerifyTest.java
@@ -62,7 +62,7 @@ public void listVerifiedCallerIdShouldWork() throws Exception {
@Test
public void deleteVerifiedCallerIdShouldWork() throws Exception {
- expectResponse("deleteVerifiedCallerIdResponse.json", 204);
+ expectResponse("deleteVerifiedCallerIdResponse.json", 200);
final String phoneNumber = "phoneNumber";
Verify.deleteVerifiedCallerID(phoneNumber).delete();