Upgrading

Version 2.0 of com.files:files-sdk still runs on Java 8 or later. Code that calls the SDK's static methods and models generally compiles against it unchanged, but code that extends SDK classes may not; see Clients. Version 2.0 also changes how the SDK logs, raises the versions of its dependencies, and changes how some errors, saves, listings, file parameters, retries and transfers behave.

Logging

SDK 1.x brought Log4j Core, Log4j's SLF4J 1.x binding and a log4j2.xml file that turned the com.files loggers off. SDK 2.0 depends only on the SLF4J 2 API, and your application chooses the logging provider and its configuration. If your application relied on the Log4j that SDK 1.x brought with it, add a provider as described in Logging, under Configuration. The SDK's warnings now appear wherever your configuration sends them; set the com.files level to change that.

Apache HttpClient's own log messages, under org.apache.http, now reach the same SLF4J provider. Keep com.files and org.apache.http at INFO or above in production: at DEBUG, both log credentials.

Dependencies

Later 1.x versions may already use some of these 2.0 versions, so compare with the version you are upgrading from.

DependencyEarlier SDK 1.xSDK 2.0
Jackson (jackson-annotations, jackson-core, jackson-databind)2.18.112.21.7
Apache HttpClient and HttpMime4.5.144.5.14
Apache HttpCore4.4.154.4.16
Commons Codec1.111.23.0
Commons Logging1.21.4.0
SLF4J API1.7.x, through Log4j2.0.20
Log4j2.19.0none
JNA (jna)none5.19.1

If your build manages Jackson itself, keep jackson-annotations, jackson-core and jackson-databind on one release, for example with Jackson's jackson-bom.

JNA, under the Apache License 2.0 or the LGPL 2.1, lets downloads on macOS and Windows keep their unfinished file private; see Uploads and Downloads. It includes its own native library for each platform. On Java 24 and later, its native access prints a warning unless your application allows it: with --enable-native-access=ALL-UNNAMED when JNA is on the class path, --enable-native-access=com.sun.jna when it is on the module path, or the manifest attribute Enable-Native-Access: ALL-UNNAMED in an executable JAR.

Errors

Errors are classified by the error type in the API's response, never by the HTTP status alone:

  • A response without a structured error body raises ApiConnectionException, whatever its status. It used to raise ServerErrorException for 5xx statuses, AuthenticationException for 403 and InvalidResponseException for other 4xx statuses. The SDK no longer throws ServerErrorException or InvalidResponseException, and both are deprecated.
  • An error type that the SDK does not recognize, or a missing one, raises ApiErrorException with the response's details and headers, instead of a NullPointerException or another unchecked exception.

Review catch blocks for ServerErrorException, InvalidResponseException and AuthenticationException; AuthenticationException is now raised only when the SDK has no credentials to send.

The message of a request that failed without a response names the kind of failure and the request's method and path, such as The request failed: the connection could not be made (ConnectException) (response to GET /api/rest/v1/users/1). It no longer repeats the message of the underlying exception, which can include URLs or other details.

Saving and Listing

  • For records the API identifies by id, save() on a record that already has one updates it with a single PATCH request, instead of creating another record. After a successful save() or update(), the object holds the attributes the server returned. A failed request leaves the object unchanged.
  • listAutoPaging() loads pages as you iterate, continues past empty pages, and stops loading when you stop iterating. all() and the new reset() start over from the first page.

File Attachments

Parameters of type file, such as avatar_file, now send their byte[] as the file. SDK 1.x sent it as Base64 text, which the API did not take as a file. They also accept an Attachment for local files and streams; see File Attachments.

Remote Mount Backend Decimals

min_free_cpu and min_free_mem are exact decimals. RemoteMountBackend.create and update take them as a String or a BigDecimal, which are sent as exact text, as well as the Double that SDK 1.x took, which is still sent as a JSON number and keeps a double's precision limits. Make a BigDecimal from text, such as new BigDecimal("0.35"), not from a double. The attributes remain BigDecimal.

HashMap<String, Object> parameters = new HashMap<>();
parameters.put("min_free_cpu", "0.35");
parameters.put("min_free_mem", new BigDecimal("12.5"));
RemoteMountBackend.update(backendId, parameters);

Clients

FilesClient is now also a client you can build, with its own credentials, workspace and connections; see Clients and Connections. The static methods keep working, through FilesClient.defaultClient(), with one difference: objects and listings they return keep the static settings that were in effect when they were requested. Changing FilesClient.apiKey, for example, no longer changes the credentials of a listing you already have.

Two changes stop some 1.x code from compiling:

  • FilesClient is now final, so it can no longer be subclassed. In 1.x it was abstract, and a class could extend it.
  • FilesHttpClient no longer has its protected httpClient field, so a subclass that uses that field no longer compiles.

Request option maps are copied: changing the map you passed no longer changes the object or listing a call returned.

A client you build without a transport of your own, or a transport you build with HttpTransport.builder(), keeps up to 1024 connections to one host and 2048 in all, so that an automatic transfer can send as many parts at once as it targets. The limits apply to every request the client sends, Files.com API requests included: requests that a pool of 20 connections a host, such as the static methods' FilesClient.connectionManager, would have queued now each go out at once on a connection of its own. Connections are opened only as they are needed and closed once idle for 5 seconds. For lower limits, set maxConnectionsPerRoute and maxConnections on the transport builder, or give the client a pool of your own; transfers stay within the limits either way. The static methods keep their pool and its 20 connections a host.

Files.com credentials now go only to the API root a call starts at; in 1.x they went to whatever host a request was first sent to. An API request to an absolute URL elsewhere, such as one passed to FilesClient.apiRequest, carries none: to call another site, pass its root as the api_root request option. Requests sent through FilesHttpClient's executor carry credentials only to the apiRoot property.

Retries and Time Limits

Later 1.x versions may already use some of these 2.0 values, such as the attempts, the wait and the time limits, so compare with the version you are upgrading from.

Earlier SDK 1.xSDK 2.0
Attempts of a request5, retrying 429 and 502 or above4 (3 retries), retrying 429, 502 or above, and 500 in answer to a GET
Wait before the first retry500 ms, doubling100 ms, doubling, up to 10 seconds
Retried failuresany I/O failurefailures that may be temporary; not a URL that cannot be sent, a certificate or host name that does not verify, or redirects that loop or go past the limit
Apache HttpClient's own resendadditional to the SDK'soff: each resend is one of the SDK's retries
Connect / read time limit10 / 30 seconds30 / 80 seconds; the read limit also covers a response body
Region mismatchalways an errorfollowed to Files.com's own servers, as a retry

The upstreamMaxAttempts property still sets the number of attempts; maxNetworkRetries now sets the number of retries. The static methods read them, and the wait, again before each attempt; a client you build keeps the values it was built with. connectTimeoutMillis and readTimeoutMillis keep their meaning: 0 means no limit, and a negative value leaves the limit to the system default. The static methods wait up to 10 seconds for a connection from the pool. A retry is logged when it happens, not after the last attempt. A request made on a thread that is interrupted, or that is interrupted while it waits, now stops and throws OperationCancelledException, and the thread keeps its interrupt status.

Uploads and Downloads

FileUploadPart.putInputStream, putBufferedInputStream and putLocalFile now run on the same engine as client.transfers(): they send the parts Files.com plans with the method and headers it gives, send parts in parallel only when Files.com allows it, retry a failed part with the same bytes only when Files.com allows it, and complete the upload with every part's ETag and the file's size. They no longer close your stream. The Date given to putInputStream and putBufferedInputStream is now recorded as the file's modification time (provided_mtime), and putLocalFile now records the local file's last modification time, to the second, the same way.

File.saveAsLocalFile now writes the download to a new, private file beside the destination and replaces the destination only once every byte has arrived, instead of truncating the destination first. The replaced file's permissions are kept, and a destination owned by another user is not replaced. Because the download replaces the destination's directory entry instead of writing into the existing file:

  • A symbolic link at the destination is replaced by a regular file, so the file it pointed to is no longer updated.
  • Other hard links to the destination keep the old contents.
  • The destination's directory must allow creating files in it, even when the destination itself can be written.
  • A device such as /dev/stdout, a FIFO or another special file is not written to: the download fails, or replaces it with a regular file. To send a download to a stream, read it from File.getInputStream().

A download whose length differs from the size Files.com gives for the file (File.size) now fails instead of being saved. Downloads to a Path with client.transfers() work the same way.

On macOS and Windows, downloads use JNA to keep the unfinished file private, and fail with an IOException, before they create anything, where JNA cannot be loaded. On Windows, unless you set jna.tmpdir or turn JNA's extraction off, the SDK lets JNA write its library only to a directory that only your application's account and administrators can change, and sets jna.tmpdir to it; see Uploads and Downloads. A library found through jna.boot.library.path or jna.nosys=false is loaded as supplied, without being checked by the SDK. On macOS and Windows, a download to a volume that does not enforce file ownership or keep ACLs, such as a FAT drive or a macOS volume set to ignore ownership, now fails, since nothing on it can be kept private.

Files.com Connectors

The Files.com MuleSoft and Boomi connectors package the SDK version they were built with. Updating the SDK in your own application does not change the SDK that a connector uses.