diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock
index b37b1ab6..2f1ad2fd 100755
--- a/.speakeasy/gen.lock
+++ b/.speakeasy/gen.lock
@@ -1,19 +1,19 @@
lockVersion: 2.0.0
id: 1732900d-e173-47c1-a90d-d45182eb35d9
management:
- docChecksum: 184db864cffee563d43aae06915b9671
+ docChecksum: fa4c9c5c23680ad02fdbe831ad9d2403
docVersion: 0.0.3
- speakeasyVersion: 1.529.1
- generationVersion: 2.566.5
- releaseVersion: 0.14.2
- configChecksum: bad4d944912dc794f8497b0cfca8b8b2
+ speakeasyVersion: 1.531.4
+ generationVersion: 2.570.4
+ releaseVersion: 0.15.0
+ configChecksum: 8a775baa0e7c2ba4c10a7c8bb26dbcd3
repoURL: https://github.com/LukeHagar/plexjava.git
published: true
features:
java:
additionalDependencies: 0.1.0
constsAndDefaults: 0.1.1
- core: 3.36.2
+ core: 3.37.1
deprecations: 2.81.1
downloadStreams: 0.1.1
enums: 2.81.2
diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml
index 17697f2e..c497de37 100644
--- a/.speakeasy/gen.yaml
+++ b/.speakeasy/gen.yaml
@@ -15,7 +15,7 @@ generation:
oAuth2ClientCredentialsEnabled: true
oAuth2PasswordEnabled: false
java:
- version: 0.14.2
+ version: 0.15.0
additionalDependencies: []
additionalPlugins: []
artifactID: plexapi
diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock
index 4aafd451..8eba3ea2 100644
--- a/.speakeasy/workflow.lock
+++ b/.speakeasy/workflow.lock
@@ -1,4 +1,4 @@
-speakeasyVersion: 1.529.1
+speakeasyVersion: 1.531.4
sources:
my-source:
sourceNamespace: my-source
@@ -8,19 +8,19 @@ sources:
- latest
plexapi:
sourceNamespace: plexapi
- sourceRevisionDigest: sha256:ea508e3da23b283f47aeb4384d6b3ab374a27bdffb8d8d8376cedbad3ad77a06
- sourceBlobDigest: sha256:c210adbd02b0213b9e6f95ffc27f60ec38f8f9040137d55ccf2b650d92ab0ff5
+ sourceRevisionDigest: sha256:db75a06885b897418dcb580679b5f744348573ad317155172346d32442420e5e
+ sourceBlobDigest: sha256:ac0a3c3a6df002378b3522325c2330ba4309fbbbfa503a04b8267398f20033f5
tags:
- latest
- - speakeasy-sdk-regen-1743899436
+ - speakeasy-sdk-regen-1744590653
targets:
plexjava:
source: plexapi
sourceNamespace: plexapi
- sourceRevisionDigest: sha256:ea508e3da23b283f47aeb4384d6b3ab374a27bdffb8d8d8376cedbad3ad77a06
- sourceBlobDigest: sha256:c210adbd02b0213b9e6f95ffc27f60ec38f8f9040137d55ccf2b650d92ab0ff5
+ sourceRevisionDigest: sha256:db75a06885b897418dcb580679b5f744348573ad317155172346d32442420e5e
+ sourceBlobDigest: sha256:ac0a3c3a6df002378b3522325c2330ba4309fbbbfa503a04b8267398f20033f5
codeSamplesNamespace: code-samples-java-plexjava
- codeSamplesRevisionDigest: sha256:c7bc64aee5441f09dae1f6b15a89c94f6b6065f2e25f5528e849e5ddf2f50d8c
+ codeSamplesRevisionDigest: sha256:da1aba30a925f7fffb273f3f1f7d25920debd20e62c974ad4a6904a98697c8db
workflow:
workflowVersion: 1.0.0
speakeasyVersion: latest
diff --git a/README.md b/README.md
index a226adc8..c25c6095 100644
--- a/README.md
+++ b/README.md
@@ -69,7 +69,7 @@ The samples below show how a published SDK artifact is used:
Gradle:
```groovy
-implementation 'dev.plexapi:plexapi:0.14.2'
+implementation 'dev.plexapi:plexapi:0.15.0'
```
Maven:
@@ -77,7 +77,7 @@ Maven:
dev.plexapi
plexapi
- 0.14.2
+ 0.15.0
```
@@ -94,6 +94,29 @@ On Windows:
```bash
gradlew.bat publishToMavenLocal -Pskip.signing
```
+
+### Logging
+A logging framework/facade has not yet been adopted but is under consideration.
+
+For request and response logging (especially json bodies) use:
+```java
+SpeakeasyHTTPClient.setDebugLogging(true); // experimental API only (may change without warning)
+```
+Example output:
+```
+Sending request: http://localhost:35123/bearer#global GET
+Request headers: {Accept=[application/json], Authorization=[******], Client-Level-Header=[added by client], Idempotency-Key=[some-key], x-speakeasy-user-agent=[speakeasy-sdk/java 0.0.1 internal 0.1.0 org.openapis.openapi]}
+Received response: (GET http://localhost:35123/bearer#global) 200
+Response headers: {access-control-allow-credentials=[true], access-control-allow-origin=[*], connection=[keep-alive], content-length=[50], content-type=[application/json], date=[Wed, 09 Apr 2025 01:43:29 GMT], server=[gunicorn/19.9.0]}
+Response body:
+{
+ "authenticated": true,
+ "token": "global"
+}
+```
+WARNING: This should only used for temporary debugging purposes. Leaving this option on in a production system could expose credentials/secrets in logs. Authorization headers are redacted by default and there is the ability to specify redacted header names via `SpeakeasyHTTPClient.setRedactedHeaders`.
+
+Another option is to set the System property `-Djdk.httpclient.HttpClient.log=all`. However, this second option does not log bodies.
diff --git a/RELEASES.md b/RELEASES.md
index d2d2bacf..657c2738 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -308,4 +308,14 @@ Based on:
### Generated
- [java v0.14.2] .
### Releases
-- [Maven Central v0.14.2] https://central.sonatype.com/artifact/dev.plexapi/plexapi/0.14.2 - .
\ No newline at end of file
+- [Maven Central v0.14.2] https://central.sonatype.com/artifact/dev.plexapi/plexapi/0.14.2 - .
+
+## 2025-04-14 00:30:37
+### Changes
+Based on:
+- OpenAPI Doc
+- Speakeasy CLI 1.531.4 (2.570.4) https://github.com/speakeasy-api/speakeasy
+### Generated
+- [java v0.15.0] .
+### Releases
+- [Maven Central v0.15.0] https://central.sonatype.com/artifact/dev.plexapi/plexapi/0.15.0 - .
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 19ec528e..b20aea75 100644
--- a/build.gradle
+++ b/build.gradle
@@ -103,7 +103,7 @@ publishing {
// https://github.com/gradle/gradle/issues/18619
groupId = "dev.plexapi"
artifactId = "plexapi"
- version = "0.14.2"
+ version = "0.15.0"
from components.java
diff --git a/docs/models/operations/GetAllLibrariesDirectory.md b/docs/models/operations/GetAllLibrariesDirectory.md
index 87b26cc8..d97fbb7f 100644
--- a/docs/models/operations/GetAllLibrariesDirectory.md
+++ b/docs/models/operations/GetAllLibrariesDirectory.md
@@ -3,26 +3,26 @@
## Fields
-| Field | Type | Required | Description | Example |
-| ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
-| `allowSync` | *boolean* | :heavy_check_mark: | Indicates whether syncing is allowed. | false |
-| `art` | *String* | :heavy_check_mark: | URL for the background artwork of the media container. | /:/resources/show-fanart.jpg |
-| `composite` | *String* | :heavy_check_mark: | The relative path to the composite media item. | /library/sections/1/composite/1743824484 |
-| `filters` | *boolean* | :heavy_check_mark: | UNKNOWN | true |
-| `refreshing` | *boolean* | :heavy_check_mark: | Indicates whether the library is currently being refreshed or updated | true |
-| `thumb` | *String* | :heavy_check_mark: | URL for the thumbnail image of the media container. | /:/resources/show.png |
-| `key` | *String* | :heavy_check_mark: | The library key representing the unique identifier | 1 |
-| `type` | [GetAllLibrariesType](../../models/operations/GetAllLibrariesType.md) | :heavy_check_mark: | N/A | movie |
-| `title` | *String* | :heavy_check_mark: | The title of the library | Movies |
-| `agent` | *String* | :heavy_check_mark: | The Plex agent used to match and retrieve media metadata. | tv.plex.agents.movie |
-| `scanner` | *String* | :heavy_check_mark: | UNKNOWN | Plex Movie |
-| `language` | *String* | :heavy_check_mark: | The Plex library language that has been set | en-US |
-| `uuid` | *String* | :heavy_check_mark: | The universally unique identifier for the library. | e69655a2-ef48-4aba-bb19-01e7d3cc34d6 |
-| `updatedAt` | *long* | :heavy_check_mark: | Unix epoch datetime in seconds | 1556281940 |
-| `createdAt` | *Optional\* | :heavy_minus_sign: | N/A | 1556281940 |
-| `scannedAt` | *long* | :heavy_check_mark: | Unix epoch datetime in seconds | 1556281940 |
-| `content` | *boolean* | :heavy_check_mark: | UNKNOWN | true |
-| `directory` | *boolean* | :heavy_check_mark: | UNKNOWN | true |
-| `contentChangedAt` | *int* | :heavy_check_mark: | The number of seconds since the content was last changed relative to now. | 9173960 |
-| `hidden` | [Optional\](../../models/operations/Hidden.md) | :heavy_minus_sign: | N/A | 1 |
-| `location` | List\<[GetAllLibrariesLocation](../../models/operations/GetAllLibrariesLocation.md)> | :heavy_check_mark: | N/A | |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `allowSync` | *boolean* | :heavy_check_mark: | Indicates whether syncing is allowed. | false |
+| `art` | *String* | :heavy_check_mark: | URL for the background artwork of the media container. | /:/resources/show-fanart.jpg |
+| `composite` | *String* | :heavy_check_mark: | The relative path to the composite media item. | /library/sections/1/composite/1743824484 |
+| `filters` | *boolean* | :heavy_check_mark: | UNKNOWN | true |
+| `refreshing` | *boolean* | :heavy_check_mark: | Indicates whether the library is currently being refreshed or updated | true |
+| `thumb` | *String* | :heavy_check_mark: | URL for the thumbnail image of the media container. | /:/resources/show.png |
+| `key` | *String* | :heavy_check_mark: | The library key representing the unique identifier | 1 |
+| `type` | [GetAllLibrariesType](../../models/operations/GetAllLibrariesType.md) | :heavy_check_mark: | N/A | movie |
+| `title` | *String* | :heavy_check_mark: | The title of the library | Movies |
+| `agent` | *String* | :heavy_check_mark: | The Plex agent used to match and retrieve media metadata. | tv.plex.agents.movie |
+| `scanner` | *String* | :heavy_check_mark: | UNKNOWN | Plex Movie |
+| `language` | *String* | :heavy_check_mark: | The Plex library language that has been set | en-US |
+| `uuid` | *String* | :heavy_check_mark: | The universally unique identifier for the library. | e69655a2-ef48-4aba-bb19-01e7d3cc34d6 |
+| `updatedAt` | *long* | :heavy_check_mark: | Unix epoch datetime in seconds | 1556281940 |
+| `createdAt` | *Optional\* | :heavy_minus_sign: | N/A | 1556281940 |
+| `scannedAt` | *long* | :heavy_check_mark: | Unix epoch datetime in seconds | 1556281940 |
+| `content` | *boolean* | :heavy_check_mark: | UNKNOWN | true |
+| `directory` | *boolean* | :heavy_check_mark: | UNKNOWN | true |
+| `contentChangedAt` | *long* | :heavy_check_mark: | Timestamp (in seconds) representing the last time the content was modified.
NOTE: Some Plex server have some absurd values for this field, like 8457612157633039800 so it should be int64
| 9173960 |
+| `hidden` | [Optional\](../../models/operations/Hidden.md) | :heavy_minus_sign: | N/A | 1 |
+| `location` | List\<[GetAllLibrariesLocation](../../models/operations/GetAllLibrariesLocation.md)> | :heavy_check_mark: | N/A | |
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 785cbeec..9565c579 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,3 +1,3 @@
groupId=dev.plexapi
artifactId=plexapi
-version=0.14.2
\ No newline at end of file
+version=0.15.0
\ No newline at end of file
diff --git a/src/main/java/dev/plexapi/sdk/PlexAPI.java b/src/main/java/dev/plexapi/sdk/PlexAPI.java
index 131f62b5..f67e2225 100644
--- a/src/main/java/dev/plexapi/sdk/PlexAPI.java
+++ b/src/main/java/dev/plexapi/sdk/PlexAPI.java
@@ -52,7 +52,7 @@ public class PlexAPI {
/**
* The full address of your Plex Server
*/
- "https://10.10.10.47:32400",
+ "{protocol}://{ip}:{port}",
};
/**
diff --git a/src/main/java/dev/plexapi/sdk/SDKConfiguration.java b/src/main/java/dev/plexapi/sdk/SDKConfiguration.java
index af8d5b4a..d88ed5b3 100644
--- a/src/main/java/dev/plexapi/sdk/SDKConfiguration.java
+++ b/src/main/java/dev/plexapi/sdk/SDKConfiguration.java
@@ -42,8 +42,8 @@ class SDKConfiguration {
} };
private static final String LANGUAGE = "java";
public static final String OPENAPI_DOC_VERSION = "0.0.3";
- public static final String SDK_VERSION = "0.14.2";
- public static final String GEN_VERSION = "2.566.5";
+ public static final String SDK_VERSION = "0.15.0";
+ public static final String GEN_VERSION = "2.570.4";
private static final String BASE_PACKAGE = "dev.plexapi.sdk";
public static final String USER_AGENT =
String.format("speakeasy-sdk/%s %s %s %s %s",
diff --git a/src/main/java/dev/plexapi/sdk/models/operations/GetAllLibrariesDirectory.java b/src/main/java/dev/plexapi/sdk/models/operations/GetAllLibrariesDirectory.java
index 9c1e4d6e..478b6fc0 100644
--- a/src/main/java/dev/plexapi/sdk/models/operations/GetAllLibrariesDirectory.java
+++ b/src/main/java/dev/plexapi/sdk/models/operations/GetAllLibrariesDirectory.java
@@ -12,7 +12,6 @@ import com.fasterxml.jackson.core.type.TypeReference;
import dev.plexapi.sdk.utils.LazySingletonValue;
import dev.plexapi.sdk.utils.Utils;
import java.lang.Boolean;
-import java.lang.Integer;
import java.lang.Long;
import java.lang.Override;
import java.lang.String;
@@ -127,10 +126,11 @@ public class GetAllLibrariesDirectory {
private boolean directory;
/**
- * The number of seconds since the content was last changed relative to now.
+ * Timestamp (in seconds) representing the last time the content was modified.
+ * NOTE: Some Plex server have some absurd values for this field, like 8457612157633039800 so it should be int64
*/
@JsonProperty("contentChangedAt")
- private int contentChangedAt;
+ private long contentChangedAt;
@JsonInclude(Include.NON_ABSENT)
@JsonProperty("hidden")
@@ -159,7 +159,7 @@ public class GetAllLibrariesDirectory {
@JsonProperty("scannedAt") long scannedAt,
@JsonProperty("content") boolean content,
@JsonProperty("directory") boolean directory,
- @JsonProperty("contentChangedAt") int contentChangedAt,
+ @JsonProperty("contentChangedAt") long contentChangedAt,
@JsonProperty("hidden") Optional extends Hidden> hidden,
@JsonProperty("Location") List location) {
Utils.checkNotNull(allowSync, "allowSync");
@@ -224,7 +224,7 @@ public class GetAllLibrariesDirectory {
long scannedAt,
boolean content,
boolean directory,
- int contentChangedAt,
+ long contentChangedAt,
List location) {
this(allowSync, art, composite, filters, refreshing, thumb, key, type, title, agent, scanner, language, uuid, updatedAt, Optional.empty(), scannedAt, content, directory, contentChangedAt, Optional.empty(), location);
}
@@ -368,10 +368,11 @@ public class GetAllLibrariesDirectory {
}
/**
- * The number of seconds since the content was last changed relative to now.
+ * Timestamp (in seconds) representing the last time the content was modified.
+ * NOTE: Some Plex server have some absurd values for this field, like 8457612157633039800 so it should be int64
*/
@JsonIgnore
- public int contentChangedAt() {
+ public long contentChangedAt() {
return contentChangedAt;
}
@@ -553,9 +554,10 @@ public class GetAllLibrariesDirectory {
}
/**
- * The number of seconds since the content was last changed relative to now.
+ * Timestamp (in seconds) representing the last time the content was modified.
+ * NOTE: Some Plex server have some absurd values for this field, like 8457612157633039800 so it should be int64
*/
- public GetAllLibrariesDirectory withContentChangedAt(int contentChangedAt) {
+ public GetAllLibrariesDirectory withContentChangedAt(long contentChangedAt) {
Utils.checkNotNull(contentChangedAt, "contentChangedAt");
this.contentChangedAt = contentChangedAt;
return this;
@@ -703,7 +705,7 @@ public class GetAllLibrariesDirectory {
private Boolean directory;
- private Integer contentChangedAt;
+ private Long contentChangedAt;
private Optional extends Hidden> hidden;
@@ -876,9 +878,10 @@ public class GetAllLibrariesDirectory {
}
/**
- * The number of seconds since the content was last changed relative to now.
+ * Timestamp (in seconds) representing the last time the content was modified.
+ * NOTE: Some Plex server have some absurd values for this field, like 8457612157633039800 so it should be int64
*/
- public Builder contentChangedAt(int contentChangedAt) {
+ public Builder contentChangedAt(long contentChangedAt) {
Utils.checkNotNull(contentChangedAt, "contentChangedAt");
this.contentChangedAt = contentChangedAt;
return this;
diff --git a/src/main/java/dev/plexapi/sdk/utils/SpeakeasyHTTPClient.java b/src/main/java/dev/plexapi/sdk/utils/SpeakeasyHTTPClient.java
index afc46023..7b4631ff 100644
--- a/src/main/java/dev/plexapi/sdk/utils/SpeakeasyHTTPClient.java
+++ b/src/main/java/dev/plexapi/sdk/utils/SpeakeasyHTTPClient.java
@@ -4,18 +4,139 @@
package dev.plexapi.sdk.utils;
import java.io.IOException;
+import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
+import java.net.http.HttpHeaders;
import java.net.http.HttpRequest;
+import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
-import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.Locale;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
public class SpeakeasyHTTPClient implements HTTPClient {
+ private static boolean debugEnabled = false;
+
+ // uppercase
+ private static Set redactedHeaders = Set.of("AUTHORIZATION", "X-API-KEY");
+
+ private static Consumer super String> logger = System.out::println;
+
+ /**
+ * Experimental, may be changed anytime. Sets debug logging on or off for
+ * requests and responses including bodies for JSON content. WARNING: this
+ * setting may expose sensitive information in logs (like Authorization
+ * headers), and should only be enabled temporarily for local debugging
+ * purposes. By default, Authorization headers are redacted in the logs
+ * ( printed with a value of {@code [*******]}). Header suppression is controlled
+ * with the {@link #setRedactedHeaders(Collection)} method.
+ *
+ * @param enabled true to enable debug logging, false to disable it
+ */
+ public static void setDebugLogging(boolean enabled) {
+ debugEnabled = enabled;
+ }
+
+ /**
+ * Experimental, may be changed anytime. When debug logging is enabled this
+ * method controls the suppression of header values in the logs. By default,
+ * Authorization headers are redacted in the logs (printed with a value
+ * of {@code [*******]}). Header suppression is controlled with the
+ * {@link #setRedactedHeaders(Collection)} method.
+ *
+ * @param headerNames the names (case-insensitive) of the headers whose values
+ * will be redacted in the logs
+ */
+ public static void setRedactedHeaders(Collection headerNames) {
+ redactedHeaders = headerNames.stream() //
+ .map(x -> x.toUpperCase(Locale.ENGLISH)) //
+ .collect(Collectors.toSet());
+ }
+
+ public static void setLogger(Consumer super String> logger) {
+ SpeakeasyHTTPClient.logger = logger;
+ }
+
@Override
public HttpResponse send(HttpRequest request)
throws IOException, InterruptedException, URISyntaxException {
HttpClient client = HttpClient.newHttpClient();
- return client.send(request, HttpResponse.BodyHandlers.ofInputStream());
+ if (debugEnabled) {
+ request = logRequest(request);
+ }
+ var response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
+ if (debugEnabled) {
+ response = logResponse(response);
+ }
+ return response;
+ }
+
+ private HttpRequest logRequest(HttpRequest request) {
+ log("Sending request: " + request);
+ log("Request headers: " + redactHeaders(request.headers()));
+ // only log the body if it is present and the content type is JSON
+ if (request.bodyPublisher().isPresent() && request.headers() //
+ .firstValue("Content-Type") //
+ .filter(x -> x.equals("application/json") || x.equals("text/plain")).isPresent()) {
+ // we read the body and ensure that the BodyPublisher is rebuilt to pass to the
+ // http client
+ byte[] body = Helpers.bodyBytes(request);
+ request = Helpers //
+ .copy(request) //
+ .method(request.method(), BodyPublishers.ofByteArray(body)) //
+ .build();
+ // note that in the case of text/plain a different encoding from UTF-8
+ // may be in use but we just log the bytes as UTF-8. Unexpected encodings
+ // do not throw (substitution happens).
+ log("Request body:\n" + new String(body, StandardCharsets.UTF_8));
+ }
+ return request;
+ }
+
+ private static HttpResponse logResponse(HttpResponse response) throws IOException {
+ // make the response re-readable by loading the response body into a byte array
+ // and allowing the InputStream to be read many times
+ response = Utils.cache(response);
+ log("Received response: " + response);
+ log("Response headers: " + redactHeaders(response.headers()));
+ // only log the response body if it is present and the content type is JSON or plain text
+ if (response.headers() //
+ .firstValue("Content-Type") //
+ .filter(x -> x.equals("application/json") || x.equals("text/plain")) //
+ .isPresent()) {
+ // the response is re-readable so we can read and close it without
+ // affecting later processing of the response.
+
+ // note that in the case of text/plain a different encoding from UTF-8
+ // may be in use but we just log the bytes as UTF-8. Unexpected encodings
+ // do not throw (substitution happens).
+ log("Response body:\n" + Utils.toUtf8AndClose(response.body()));
+ }
+ return response;
+ }
+
+ private static String redactHeaders(HttpHeaders headers) {
+ return "{" + headers.map() //
+ .entrySet() //
+ .stream() //
+ .map(entry -> {
+ final String value;
+ if (redactedHeaders.contains(entry.getKey().toUpperCase(Locale.ENGLISH))) {
+ value = "[******]";
+ } else {
+ value = String.valueOf(entry.getValue());
+ }
+ return entry.getKey() + "=" + value;
+ }) //
+ .collect(Collectors.joining(", ")) + "}";
+ }
+
+ private static void log(String message) {
+ logger.accept(message);
}
}
diff --git a/src/main/java/dev/plexapi/sdk/utils/Utils.java b/src/main/java/dev/plexapi/sdk/utils/Utils.java
index e6d36db1..2884f96a 100644
--- a/src/main/java/dev/plexapi/sdk/utils/Utils.java
+++ b/src/main/java/dev/plexapi/sdk/utils/Utils.java
@@ -1368,20 +1368,32 @@ public final class Utils {
}
return list;
}
-
- public static T valueOrNull(T value) {
- return value;
+
+ public static T valueOrElse(T value, T valueIfNotPresent) {
+ return value != null ? value : valueIfNotPresent;
+ }
+
+ public static T valueOrElse(Optional value, T valueIfNotPresent) {
+ return value.orElse(valueIfNotPresent);
}
- public static T valueOrNull(Optional value) {
- return value.orElse(null);
- }
-
- public static T valueOrNull(JsonNullable value) {
+ public static T valueOrElse(JsonNullable value, T valueIfNotPresent) {
if (value.isPresent()) {
return value.get();
} else {
- return null;
+ return valueIfNotPresent;
}
}
+
+ public static T valueOrNull(T value) {
+ return valueOrElse(value, null);
+ }
+
+ public static T valueOrNull(Optional value) {
+ return valueOrElse(value, null);
+ }
+
+ public static T valueOrNull(JsonNullable value) {
+ return valueOrElse(value, null);
+ }
}