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.
| Dependency | Earlier SDK 1.x | SDK 2.0 |
|---|---|---|
Jackson (jackson-annotations, jackson-core, jackson-databind) | 2.18.11 | 2.21.7 |
| Apache HttpClient and HttpMime | 4.5.14 | 4.5.14 |
| Apache HttpCore | 4.4.15 | 4.4.16 |
| Commons Codec | 1.11 | 1.23.0 |
| Commons Logging | 1.2 | 1.4.0 |
| SLF4J API | 1.7.x, through Log4j | 2.0.20 |
| Log4j | 2.19.0 | none |
JNA (jna) | none | 5.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 raiseServerErrorExceptionfor 5xx statuses,AuthenticationExceptionfor 403 andInvalidResponseExceptionfor other 4xx statuses. The SDK no longer throwsServerErrorExceptionorInvalidResponseException, and both are deprecated. - An error type that the SDK does not recognize, or a missing one, raises
ApiErrorExceptionwith the response's details and headers, instead of aNullPointerExceptionor 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 successfulsave()orupdate(), 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 newreset()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.
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:
FilesClientis nowfinal, so it can no longer be subclassed. In 1.x it wasabstract, and a class could extend it.FilesHttpClientno longer has itsprotectedhttpClientfield, 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.x | SDK 2.0 | |
|---|---|---|
| Attempts of a request | 5, retrying 429 and 502 or above | 4 (3 retries), retrying 429, 502 or above, and 500 in answer to a GET |
| Wait before the first retry | 500 ms, doubling | 100 ms, doubling, up to 10 seconds |
| Retried failures | any I/O failure | failures 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 resend | additional to the SDK's | off: each resend is one of the SDK's retries |
| Connect / read time limit | 10 / 30 seconds | 30 / 80 seconds; the read limit also covers a response body |
| Region mismatch | always an error | followed 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 fromFile.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.