This file is for agents contributing to this repository. If you are using the SDK in another
project, read docs/ instead — task-oriented pages for agents using the SDK.
Use JDK 8 or 11; CI runs on JDK 8. The Gradle 6.0.1 wrapper fails on JDK 17 and later before any task runs.
./gradlew :cloudinary-core:jar :cloudinary-http5:jar :cloudinary-taglib:jar # build the published modules
./gradlew :cloudinary-core:test # unit tests, no cloud needed
./gradlew createTestSubAccount -PmoduleName=http5 # throwaway cloud -> tools/cloudinary_url.txt
source tools/cloudinary_url.txt # sets CLOUDINARY_URL
./gradlew ciTest -p cloudinary-http5 -DCLOUDINARY_URL="$CLOUDINARY_URL" # integration tests, as CI runs themGradle passes -DCLOUDINARY_URL to the test JVM as the CLOUDINARY_URL environment variable
(java_shared.gradle). tools/cloudinary_url.txt is git-ignored and contains live credentials;
never commit it or paste its contents anywhere.
cloudinary-coretests run offline.cloudinary-http5tests need a live product environment.cloudinary-taglibhas no tests.- Use a fresh sub-account for each integration run. Assets and metadata fields left by earlier runs can fail unrelated tests.
javasnippets indocs/must compile against the built jars, and links indocs/must resolve.
| Path | Published | Purpose |
|---|---|---|
cloudinary-core/ |
Yes | URL/transformation building, parameter serialisation. No HTTP client, no runtime dependencies. |
cloudinary-http5/ |
Yes | Apache HttpClient 5 transport. This is what users depend on. |
cloudinary-taglib/ |
Yes | JSP tags. Targets javax.*, not Jakarta EE 9+. |
cloudinary-test-common/ |
Yes | Shared test helpers. Not for application code. |
docs/ |
No | Task pages for agents using the SDK. |
examples/ |
No | One runnable program per doc page where the task is genuinely runnable. |
samples/ |
No | Legacy sample applications. Not in the build. |
tools/ |
No | Release and test-cloud scripts. |
settings.gradle includes the four modules above.
org.cloudinary.json inside cloudinary-core is a vendored JSON implementation. It exists to
keep the core dependency-free. Do not replace it with Jackson or Gson.
docs/ and examples/ are not packaged into any jar; the published -javadoc.jar is the
documentation attached to each artifact.
Keep examples uniform: one entry point taking no arguments, no CLI parsing, constants at the top, and one error-handling block mapping every failure to a non-zero exit with a readable message.
- The build targets Java 8 (
sourceCompatibility = 1.8injava_shared.gradle). Do not use newer language features insrc/main. - There is no linter, formatter, or static-analysis tool. Match the surrounding code.
- Options are untyped
Maps built withObjectUtils.asMap(k, v, ...); responses areMaps keyed by the raw API field names (public_id,secure_url,asset_id). There are no typed response objects. Cloudinaryis safe to share as a singleton.Urlis a mutable builder and is not thread-safe; callcloudinary.url()per URL.
- Docs describe this SDK. Link Cloudinary documentation in
.mdform (https://cloudinary.com/documentation/<page>.md);README.mdmay link HTML. Do not recommend third-party packages. - Prefer
asset_id(immutable) overpublic_id(changes on rename) when showing how to store a reference. FiveApimethods accept an asset ID; nothing inUploaderdoes. README.mdshows the released version, which the release script updates. Pages indocs/useX.Y.Z, because the release script does not touch them.
- Branch from
master; keep changes focused; one topic per pull request. - Do not edit
CHANGELOG.mdor bump the version. Releases runtools/update_version.sh <version>, which rewritesCloudinary.VERSIONinCloudinary.java,version=ingradle.properties, and the version inREADME.md. It reads theVERSIONline with a regex; do not reformat it. - Keep secrets out of everything — code, tests, fixtures, docs, commit messages. Grep the diff
for
cloudinary://with real values before pushing. - Never commit
tools/cloudinary_url.txt,/out/, or media left behind by running examples.
Always
- Verify claims in
docs/against the source and, where possible, by running them. Do not copy another Cloudinary SDK's docs; behaviour differs between the SDKs. - Keep
docs/andexamples/consistent with the code they document. - Keep API secrets out of examples, docs, tests, and fixtures.
Ask first
- Changing the published artifact list, packaging, or what ships inside a jar.
- Adding a dependency.
cloudinary-corehas no runtime dependencies. - Changing public API signatures or behaviour. Document current behaviour and raise an issue
before changing it. This includes these behaviours, which
docs/describes and callers may depend on:- Error types differ by entry point:
java.lang.RuntimeExceptioncarrying a message for uploads (AbstractUploaderStrategy.processResponse), typedApiExceptionsubclasses for the Admin API, andjava.lang.UnknownError(anError, not anException) when no HTTP adapter is present. EnumMetadataFieldhas a package-private constructor and no factory, unlikeSetMetadataField. Application code usesnew MetadataField<String>(MetadataFieldType.ENUM).ProgressCallbackoverloads compile oncloudinary-http5and throwIllegalArgumentException: Progress callback is not supportedwhen called.Url.resourcType(String)is retained alongsideresourceType(String)for compatibility.
- Error types differ by entry point:
- Touching
publish.gradle,gradle.properties,MAVEN_CENTRAL_PUBLISHING_GUIDE.md, or the release script. - Adding a typed response object, a linter, or a formatter.
- Modifying the legacy sample apps in
samples/.
Never
- Commit credentials or real account identifiers.
- Document a Cloudinary platform capability as an SDK method unless this library implements it
(see
docs/platform-capabilities.md).