- Migration guide from
box-java-sdk
tobox-java-sdk-gen
The new box-java-sdk-gen
SDK library, which helps Java developers to conveniently integrate with Box API.
In the contrary to the previous library (box-java-sdk
), it is not manually maintained, but auto-generated
based on Open API Specification. This means you can leverage the most up-to-date Box API features in your
applications without delay. More information and benefits of using the new can be found in the
README file.
To install a new Box Java SDK GENERATED library, you can use Maven or Gradle. The library is available in the Maven Central Repository.
The new Box Java SDK GENERATED library could be used in the same project along with the legacy one. If you want to use a feature available only in the new SDK, you don't need to necessarily migrate all your code to use Box Java SDK GENERATED at once. You can use a new feature from the new library, while keeping the rest of your code unchanged. Note that it may be required to use fully qualified class names from the new SDK to avoid conflicts with the old one. However, we recommend to fully migrate to the new SDK eventually.
To add a dependency to your Maven project, add the following to your pom.xml
file:
<dependency>
<groupId>com.box</groupId>
<artifactId>box-java-sdk-gen</artifactId>
<version>VERSION</version>
</dependency>
To add a dependency to your Gradle project, add the following to your build.gradle
file:
implementation 'com.box:box-java-sdk-gen:VERSION'
The main difference between the old SDK and the new one is the way how API methods are aggregated into objects.
Old (box-java-sdk
)
Firstly, in the old SDK to be able to perform any action on an API object, e.g. User
, you first had to create its class.
To do it is required to call:
BoxUser user = new BoxUser(api, "12345");
to create a class representing an already existing User with id '12345', or create a new one with a call:
BoxUser.Info createdUserInfo = BoxUser.createAppUser(api, "A User");
BoxUser user = new BoxUser(api, createdUserInfo.getID());
Then, you could perform any action on created class, which will affect the user, e.g.
BoxUser.Info info = user.new Info();
info.setName(name);
user.updateInfo(info);
New (box-java-sdk-gen
)
In the new SDK the API methods are grouped into dedicated manager classes, e.g. User
object
has dedicated UserManager
class. Each manager class instance is available in BoxClient
object.
The fields storing references to the managers are named in the plural form of the resource that the
manager handles - client.users
for UsersManager
. If you want to perform any operation
connected with a User
you need to call a respective method of UserManager
.
For example, to get info about existing user you need to call:
UserFull user = client.users.getUsersById("12345");
or to create a new user:
CreateUserRequestBody requestBody =
new CreateUserRequestBody.CreateUserRequestBodyBuilder("John Doe").build();
UserFull user = client.users.createUser(requestBody);
The UserFull
object returned by both of these methods is a data class - it does not contain any methods to call.
To perform any action on User
object, you need to still use a UserManager
method for that.
Usually these methods have a first argument, which accepts id of the object you want to access,
e.g. to update a user name, call method:
UpdateUserByIdRequestBody requestBody =
new UpdateUserByIdRequestBody.UpdateUserByIdRequestBodyBuilder().name("Marry").build();
UserFull updatedUser = client.users.updateUserById(user.getId(), requestBody);
The new SDK is designed to be mostly immutable. This means that methods,
which used to modify the existing object in old SDK now return a new instance of the class with the modified state.
This design pattern is used to avoid side effects and make the code more predictable and easier to reason about.
Methods, which returns a new modified instance of an object, will always have a prefix with
in their names, e.g.
New (box-java-sdk-gen
)
BoxClient client = new BoxClient(auth);
BoxClient asUserClient = client.withAsUserHeader("USER_ID");
To facilitate easier work with the new SDK, we have changed the API method signatures to be consistent and unified.
Old (box-java-sdk
)
In the old SDK, API methods had numerous parameters, which were not grouped into any objects and were passed as separate arguments, e.g. the method for creating a sign request looked like this:
public static BoxSignRequest.Info createSignRequest(BoxAPIConnection api, List<BoxSignRequestFile> sourceFiles,
List<BoxSignRequestSigner> signers, String parentFolderId,
BoxSignRequestCreateParams optionalParams)
New (box-java-sdk-gen
)
In the new SDK, we have adopted an approach of aggregating parameters into types based on their nature (path, body, query, headers). This can be seen in the example corresponding to the above:
public SignRequest createSignRequest(
SignRequestCreateRequest requestBody, CreateSignRequestHeaders headers)
According to the convention, if an API endpoint requires a parameter placed in the URL path, it will appear at the beginning of our method, such as fileId
in this case. When a request allows for a body, as in POST
or PUT
, the method includes a parameter named requestBody
. Following that, the method signature may include the queryParams
parameter, followed by headers
.
The types of parameters requestBody
, queryParams
, and headers
are specific to each endpoint and, in their definition, encompass all fields allowed by the API.
It's worth noting here that when all fields of a particular type are optional, the entire parameter becomes optional as well. This allows us to pass only the parameters we actually want to provide when calling a given method, without the risk of not providing a sufficient number of parameters.
The Box Java SDK Gen library offers the same authentication methods as the legacy one. Let's see the differences of their usage:
Old (box-java-sdk
)
BoxAPIConnection api = new BoxAPIConnection("YOUR-DEVELOPER-TOKEN");
The new SDK provides a convenient BoxDeveloperTokenAuth
, which allows authenticating
using developer token without necessity to provide a Client ID and Client Secret
New (box-java-sdk-gen
)
BoxDeveloperTokenAuth auth = new BoxDeveloperTokenAuth("YOUR-DEVELOPER-TOKEN");
BoxClient client = new BoxClient(auth);
Old (box-java-sdk
)
The static method, which reads the JWT configuration file has been changed:
Reader reader = new FileReader("src/example/config/config.json");
BoxConfig boxConfig = BoxConfig.readFrom(reader);
IAccessTokenCache tokenCache = new InMemoryLRUAccessTokenCache(100);
BoxDeveloperEditionAPIConnection api = BoxDeveloperEditionAPIConnection.getAppEnterpriseConnection(boxConfig, tokenCache);
New (box-java-sdk-gen
)
TokenStorage tokenStorage = new InMemoryTokenStorage(); // or any other implementation of TokenStorage
JWTConfig config = JWTConfig.fromConfigFile("src/example/config/config.json", tokenStorage);
BoxJWTAuth auth = new BoxJWTAuth(config);
BoxClient client = new BoxClient(auth);
Some params in JWTConfig
constructor have slightly different names than one in old JWTAuth
class.
Old (box-java-sdk
)
JWTEncryptionPreferences jwtPreferences = new JWTEncryptionPreferences();
jwtPreferences.setPublicKeyID("PUBLIC-KEY-ID");
jwtPreferences.setPrivateKeyPassword("PRIVATE-KEY-PASSWORD");
jwtPreferences.setPrivateKey("PRIVATE-KEY");
jwtPreferences.setEncryptionAlgorithm(EncryptionAlgorithm.RSA_SHA_256);
IAccessTokenCache accessTokenCache = new InMemoryLRUAccessTokenCache(100);
BoxDeveloperEditionAPIConnection api = BoxDeveloperEditionAPIConnection
.getUserConnection("USER-ID", "CLIENT-ID","CLIENT-SECRET", jwtPreferences, accessTokenCache);
BoxUser.Info userInfo = BoxUser.getCurrentUser(api).getInfo();
New (box-java-sdk-gen
)
TokenStorage tokenStorage = new InMemoryTokenStorage();
JWTConfig config = new JWTConfig.JWTConfigBuilder("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET", "JWT_KEY_ID", "PRIVATE_KEY", "PRIVATE_KEY_PASSWORD")
.enterpriseId("123456")
.tokenStorage(tokenStorage)
.build();
BoxJWTAuth auth = new BoxJWTAuth(config);
BoxClient client = new BoxClient(auth);
In old SDK method for user authentication was named BoxDeveloperEditionAPIConnection getUserConnection(String userId, BoxConfig boxConfig, IAccessTokenCache accessTokenCache)
and was accepting user id. The method was returning a new instance of BoxDeveloperEditionAPIConnection
class, which was exchanging the existing token with the one with the user access.
Old (box-java-sdk
)
BoxDeveloperEditionAPIConnection api = BoxDeveloperEditionAPIConnection.getUserConnection("USER_ID", boxConfig, tokenCache);
New (box-java-sdk-gen
)
In new SDK, to authenticate as user you need to call
public BoxJWTAuth withUserSubject(String userId, TokenStorage tokenStorage)
method with id of the user
to authenticate. The method returns a new instance of BoxJWTAuth
class, which will perform authentication call
in scope of the user on the first API call. The tokenStorage
parameter is optional and allows to provide a custom
token storage for the new instance of BoxJWTAuth
class. The new auth instance can be used to create a new user client
instance.
BoxJWTAuth userAuth = auth.withUserSubject("USER_ID");
BoxClient userClient = new BoxClient(userAuth);
To authenticate as enterprise, the only difference between the old and the new SDK,
is using the CCGConfig
as a middle step.
Old (box-java-sdk
)
BoxCCGAPIConnection api = BoxCCGAPIConnection.applicationServiceAccountConnection(
"client_id",
"client_secret",
"enterprise_id"
);
New (box-java-sdk-gen
)
CCGConfig config = new CCGConfig.CCGConfigBuilder("YOUR_CLIENT", "YOUR_CLIENT_SECRET")
.enterpriseId("ENTERPRISE_ID")
.build();
BoxCCGAuth auth = new BoxCCGAuth(config);
BoxClient client = new BoxClient(auth);
To authenticate as user, the only difference between the old and the new SDK, is using the CCGConfig
as a middle step.
Old (box-java-sdk
)
BoxCCGAPIConnection api = BoxCCGAPIConnection.userConnection(
"client_id",
"client_secret",
"user_id"
);
New (box-java-sdk-gen
)
CCGConfig config = new CCGConfig.CCGConfigBuilder("YOUR_CLIENT", "YOUR_CLIENT_SECRET")
.userId("USER_ID")
.build();
BoxCCGAuth auth = new BoxCCGAuth(config);
BoxClient client = new BoxClient(auth);
In old SDK, if you want to switch between the Service Account and User, you need to create another API connection.
In the new SDK, to keep the immutability design, the methods switching authenticated subject were replaced with methods
returning a new instance of BoxCCGAuth
class. The new instance will fetch a new token on the next API call.
The new auth instance can be used to create a new client instance. You can also specify tokenStorage
parameter
to provide a custom token storage for the new instance.
The old instance of BoxCCGAuth
class will remain unchanged and will still use the old token.
New (box-java-sdk-gen
)
BoxCCGAuth userAuth = auth.withUserSubject("USER_ID");
BoxClient userClient = new BoxClient(userAuth);
BoxCCGAuth entAuth = auth.withEnterpriseSubject("ENTERPRISE_ID");
BoxClient entClient = new BoxClient(entAuth);
To get authorization url in the new SDK, you need to first create the BoxOAuth
class using
OAuthConfig
class. Then to get authorization url, call
public String getAuthorizeUrl(GetAuthorizeUrlOptions options)
. Note that this method accepts the instance of GetAuthorizeUrlOptions
class, which allows specifying extra options to API call.
Old (box-java-sdk
)
In the old SDK, we did not have any method to get the authorization URL. Instead, we had to manually create the URL.
String authorizationUrl = "https://account.box.com/api/oauth2/authorize?client_id=[CLIENT_ID]&response_type=code";
New (box-java-sdk-gen
)
BoxOAuth auth = new BoxOAuth(new OAuthConfig.OAuthConfigBuilder("CLIENT_ID", "CLIENT_SECRET").build());
String authorizationUrl = auth.getAuthorizeUrl();
The method for authenticating using the authorization code has been changed. With the old SDK, you had to provide the authorization code to the BoxAPIConnection
class constructor. In the new SDK, you need to call the public AccessToken getTokensAuthorizationCodeGrant(String authorizationCode)
method of the BoxOAuth
class.
The method now returns an AccessToken object with accessToken
and refreshToken
fields,
while the old one was creating a new instance of BoxAPIConnection
class.
Old (box-java-sdk
)
BoxAPIConnection client = new BoxAPIConnection(
"[CLIENT_ID]",
"[CLIENT_SECRET]",
"[CODE]"
);
New (box-java-sdk-gen
)
auth.getTokensAuthorizationCodeGrant("AUTHORIZATION_CODE");
BoxClient client = new BoxClient(auth);
In the new SDK you can define your own class delegated for storing and retrieving a token. It has to inherit from
TokenStorage
and implement all of its abstract methods. Next step would be to pass an instance of this class to the
AuthConfig constructor.
New (box-java-sdk-gen
)
TokenStorage customTokenStorage = new TokenStorage() {
@Override
public void store(AccessToken accessToken) {
// Store the access token
}
@Override
public AccessToken get() {
// Retrieve the access token
return null;
}
@Override
public void clear() {
// Clear the access token
}
};
OAuthConfig config = new OAuthConfig.OAuthConfigBuilder("CLIENT_ID", "CLIENT_SECRET")
.tokenStorage(customTokenStorage)
.build();
BoxOAuth auth = new BoxOAuth(config);
or reuse one of the provided implementations: InMemoryTokenStorage
:
TokenStorage tokenStorage = new InMemoryTokenStorage();
OAuthConfig config = new OAuthConfig.OAuthConfigBuilder("CLIENT_ID", "CLIENT_SECRET")
.tokenStorage(tokenStorage)
.build();
BoxOAuth auth = new BoxOAuth(config);
The process of downscoping token in the new SDK is similar to the old one. The main difference is that in the new SDK
you need to call downscopeToken
method of the BoxOAuth
class instead of getLowerScopedToken
method of the BoxAPIConnection
class.
Old (box-java-sdk
)
BoxAPIConnection api = new BoxAPIConnection("YOUR-ACCESS-TOKEN");
String resource = "https://api.box.com/2.0/files/RESOURCE-ID";
List<String> scopes = new ArrayList<String>();
scopes.add("item_preview");
scopes.add("item_content_upload");
ScopedToken token = api.getLowerScopedToken(scopes, resource);
New (box-java-sdk-gen
)
String resource = "https://api.box.com/2.0/files/123456789";
List<String> scopes = List.of("item_preview");
AccessToken downscopedToken = auth.downscopeToken(scopes, resource, null, null);
BoxDeveloperTokenAuth downscopedAuth = new BoxDeveloperTokenAuth(downscopedToken.getAccessToken());
BoxClient downscopedClient = new BoxClient(downscopedAuth);
To revoke current client's tokens in the new SDK, you need to call revokeToken
method of the auth class instead of
revoke
method.
Old (box-java-sdk
)
BoxAPIConnection api = new BoxAPIConnection("YOUR-ACCESS-TOKEN");
api.revokeToken();
New (box-java-sdk-gen
)
client.auth.revokeToken()
The As-User header is used by enterprise admins to make API calls on behalf of their enterprise's users.
This requires the API request to pass an As-User: USER-ID
header. The following examples assume that the client has
been instantiated with an access token with appropriate privileges to make As-User calls.
In old SDK you could call client asUser(String userID)
method to create a new client to impersonate the provided user.
Old (box-java-sdk
)
BoxAPIConnection api = new BoxAPIConnection("YOUR-ACCESS-TOKEN");
api.asUser("USER-ID");
New (box-java-sdk-gen
)
In the new SDK the method was renamed to withAsUserHeader
in the BoxClient
class,
and returns a new instance of BoxClient
class with the As-User header appended to all API calls made by the client.
The method accepts only user id as a parameter.
BoxClient userClient = client.withAsUserHeader("USER-ID");
Additionally BoxClient
offers a withExtraHeaders(Map<String, String> extraHeaders)
method, which allows you to specify the custom set of headers, which will be included in every API call made by client.
Calling the client.withExtraHeaders()
method creates a new client, leaving the original client unmodified.
BoxClient clientWithExtraHeaders = client.withExtraHeaders(new HashMap<>() {{
put("X-My-Header", "124");
}});
Old (box-java-sdk
)
In old SDK you could specify the custom base URLs, which will be used for API calls made by setting
the new values of static variables of the API
class.
BoxAPIConnection api = new BoxAPIConnection("YOUR-DEVELOPER-TOKEN");
api.setBaseAppUrl("https://example.app.com");
api.setBaseURL("https://example.com");
api.setUploadURL("https://upload.example.com");
api.setTokenURL("https://example.com/token");
New (box-java-sdk-gen
)
In the new SDK this functionality has been implemented as part of the BoxClient
class.
By calling the client.withCustomBaseUrls()
method, you can specify the custom base URLs that will be used for API
calls made by client. Following the immutability pattern, this call creates a new client, leaving the original client unmodified.
BaseUrls baseUrls = new BaseUrls.BaseUrlsBuilder()
.baseUrl("https://new-base-url.com")
.uploadUrl("https://my-company-upload-url.com")
.oauth2Url("https://my-company.com/oauth2")
.build();
BoxClient clientWithCustomBaseUrl = client.withCustomBaseUrls(baseUrls);