Skip to content

Migration Guide: Upgrading to use version 6.0.0 (Jackson 3)

Khalid Qarryzada edited this page Jun 24, 2026 · 3 revisions

Jackson is a common HTTP library responsible for handling JSON processing. In the 6.0.0 release of the UnboundID SCIM SDK, the Jackson dependency was updated from version 2.21.3 to version 3.1.3. The update from Jackson 2 to Jackson 3 contains many backwards-incompatible API changes, design changes, and updated default values. This guide contains an overview of changes specific to applications that use the SCIM SDK.

Preqrequisites

To keep migration efforts minimal, it is encouraged to update your application to use version 5.1.0 first, before trying to upgrade to 6.0.0. After this, migration work that is unrelated to Jackson is expected to be low. For a comprehensive overview of what changed in Jackson 3, see the official Jackson 3 Migration Guide.

Dependency Updates

The only dependency changed within the UnboundID SCIM SDK between 5.1.0 and 6.0.0 was Jackson. Make sure your application is updated to use:

  • At least version 3.1.3 of jackson-databind
  • Version 2.21 of jackson-annotations (Jackson 3 still uses the 2.x annotations package)

With the exception of annotations, it's generally best to avoid having Jackson 2 and Jackson 3 coexisting on the classpath if it can be avoided, though the Jackson migration guide states that this can be okay.

To start, update the SCIM SDK's release version:

Maven:

<dependency>
    <groupId>com.unboundid.product.scim2</groupId>
    <artifactId>scim2-sdk-common</artifactId>
    <version>6.0.0</version>
</dependency>

Gradle:

implementation 'com.unboundid.product.scim2:scim2-sdk-common:6.0.0'

Jackson Namespace Rename

The most noticeable change in Jackson 3 is the Java package rename. With the exception of the jackson-annotations package (explanation here), all imports in your application that reference Jackson APIs directly must be updated. Some examples are shown below:

Before upgrade After upgrade
com.fasterxml.jackson.annotation.* com.fasterxml.jackson.annotation.* (unchanged)
com.fasterxml.jackson.core.* tools.jackson.core.*
com.fasterxml.jackson.databind.* tools.jackson.databind.*
com.fasterxml.jackson.databind.node.* tools.jackson.databind.node.*

 

The import statements in your project can be changed as shown below. Note that TextNode was renamed to StringNode in Jackson 3.

// Before (Jackson 2):
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.TextNode;

// After (Jackson 3):
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.node.StringNode;

Jackson API Changes

TextNode Renamed to StringNode

As stated above, com.fasterxml.jackson.databind.node.TextNode has been renamed to tools.jackson.databind.node.StringNode. Related API methods have also changed:

Jackson 2 Jackson 3
TextNode StringNode
TextNode.valueOf() StringNode.valueOf()
node.isTextual() node.isString()
node.textValue() node.asString()
node.asText() node.asString()

Exceptions Are No Longer Checked

Jackson exception objects are no longer checked exceptions. In Jackson 2.x, exceptions were based on java.io.IOException, but in Jackson 3.x, they are based on java.lang.RuntimeException. The UnboundID SCIM SDK still highlights places where a JacksonException is thrown, but it is no longer mandatory to surround these in a try/catch block. These blocks are likely still useful in cases when a descriptive error message should be returned.

Existing references to JsonProcessingException, which was removed in Jackson 3, can be replaced by JacksonException:

Before (Jackson 2):

try 
{
  UserResource user = JsonUtils.nodeToValue(objectNode, UserResource.class);
}
catch (JsonProcessingException e) 
{
  throw new BadRequestException("Custom message.", e);
}

After (Jackson 3):

// The try/catch block is technically not mandatory anymore, but existing usages
// can keep consistent behavior by catching the runtime exception.
try 
{
  UserResource user = JsonUtils.nodeToValue(objectNode, UserResource.class);
}
catch (JacksonException e) 
{
  throw new BadRequestException("Custom message.", e);
}

ObjectMapper Is Now Read-Only

In Jackson 3, ObjectMapper instances are now immutable after they are built with JsonMapper.Builder.build(), so they cannot be customized directly anymore. Existing object mappers that only modified a few settings (e.g., FAIL_ON_UNKNOWN_PROPERTIES) can be updated to use a builder, or simply use JsonUtils.createJsonMapper().

For SCIM uses, it is always encouraged to obtain an ObjectMapper/JsonMapper with createJsonMapper(), as this will provide a mapper with the appropriate settings for SCIM processing. If your object mapper can use it, existing references to customized object mappers can be replaced with:

JsonMapper mapper = JsonUtils.createJsonMapper();

If you need to customize the SCIM SDK's default object mapper behavior, the MapperFactory class still supports this. Note that MapperFactory was updated in 5.1.0 to obtain configuration updates through the builder, which is detailed in the class-level Javadoc.

The JsonUtils.createObjectMapper() method used in previous releases is equivalent to the new JsonUtils.createJsonMapper() one, and may still be used for old code that already called the legacy method. New calls should prefer createJsonMapper(). Note that the legacy method now returns a JsonMapper, but this is a subclass of ObjectMapper, so the following is still permitted:

ObjectMapper mapper = JsonUtils.createObjectMapper();

Jackson Property Updates

Jackson is known for customizability, and provides many configuration options to change the behavior of JSON processing. Jackson 3 changed the default values for several configuration properties that may affect your application.

Renamed Fields

Several DeserializationFeature and SerializationFeature enum values that existed in Jackson 2 have been reorganized in Jackson 3. For example, SerializationFeature.WRITE_DATES_AS_TIMESTAMPS is now DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS. If your application configured such features, review the official Jackson 3 migration guide for the new property names.

Unknown JSON Fields Are Now Ignored

The most consequential property change is to DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, which has been set to false by default in Jackson 3. Previously, deserializing a JSON object that contained unrecognized fields would throw an exception, completely halting request processing and leaving clients to handle the error. Now, the unknown fields are ignored instead. For an example, see the discussion in the next section.

This behavior is aligned with modern API handling, and provides better resilience for applications interacting with external APIs that may add new fields over time. This is still a good default for applications that use the SCIM standard's REST API, since updates to the standard can result in new fields being added. As an example, RFC 9865 added previousCursor and nextCursor values into ListResponse objects. The legacy behavior can cause problems for applications that are overly strict about JSON fields it does not recognize.

The UnboundID SCIM SDK has been updated to incorporate this new setting and will no longer throw exceptions when extra unknown fields are present in JSON objects.


Changed Default Behaviors

Some existing SCIM SDK properties that are unrelated to Jackson have been updated as of the 6.0.0 release. These are listed for documentation purposes and are not expected to require changes outside of accommodating potential test failures.

 

Unknown Fields Are Now Ignored by Default On BaseScimResource Objects

BaseScimResource.IGNORE_UNKNOWN_FIELDS is now true by default so that unknown JSON fields on BaseScimResources are ignored instead of throwing exceptions. This property provides very similar functionality to the Jackson FAIL_ON_UNKNOWN_PROPERTIES that is referenced above, and lives within the SCIM SDK. Since the default behavior in Jackson has changed, this property was updated for alignment in behavior.

With the new behavior, when the SCIM SDK encounters unknown fields, it will ignore them by default instead of throwing its own exceptions. In the example below, all fields except for unknownField will be parsed, since UserResource is a subclass of BaseScimResource. Note that the processing of schema extension values on a BaseScimResource has always been supported in the SCIM SDK.

{
    "schemas": [ "urn:ietf:params:scim:schemas:core:2.0:User" ],
    "userName": "Alice",
    "unknownField": "NOT_USED",
    "urn:pingidentity:customExtension": {
        "id": "fa1afe1"
    }
}

You may encounter test failures if you have tests that intentionally try to trigger JacksonException errors and validate the response. Instead of using an unknown field, these tests can attempt to set a value to an incorrect data type, e.g.:

{
    "schemas": [ "urn:ietf:params:scim:schemas:core:2.0:User" ],
    "userName": true
}

DateTimeUtils Now Uses UTC by Default

DateTimeUtils.USE_GMT_CALENDARS (added in 5.1.0) is now false by default. This update does not not change the behavior of JSON serialization. It only updates the timezone of some Java Calendar objects that are created from a JSON timestamp value.

In previous releases, when ISO 8601 timestamps were converted from JSON into Calendar objects, the SCIM SDK would set the timezone to GMT+00:00 if it used the default time zone. This behavior originally came from the JAX-B dependency (which is no longer used as of 5.0.0). Most notably, it complicated equivalency checks in unit tests, since Calendar objects would need to be intentionally set for this unique value. Now, the SCIM SDK uses UTC in these cases instead.

You may encounter some failed tests that have mismatched meta.created or meta.lastModified values. This can be resolved by updating your tests to use UTC, which is a better value to use.

Restoring Previous Behavior

In the interest of better default behavior, reverting the properties to their previous behavior is discouraged, as these properties are not guaranteed to stay in the SCIM SDK in the long term. However, the previous behavior of these properties may be restored by directly updating the values:

BaseScimResource.IGNORE_UNKNOWN_FIELDS = false;

An alternative approach is to set the value of the relevant JVM system property before starting the application:

-Dcom.unboundid.scim2.common.BaseScimResource.ignoreUnknownFields=false

Removed Classes and Methods

PATCH Annotation Removed

The com.unboundid.scim2.server.PATCH annotation class has been removed, as it was deprecated in 5.1.0. At the time this class was originally written, JAX-RS did not contain support for a native @PATCH annotation, but this now exists. Thus, any import statements that use the legacy annotation may be updated to use jakarta.ws.rs.PATCH instead:

// import com.unboundid.scim2.server.PATCH;
import jakarta.ws.rs.PATCH;

@PATCH
@Path("{id}")
public Response patchUser(...) 
{
}

MapperFactory Deprecated Methods Removed

The following MapperFactory methods were deprecated in 5.1.0 and have been removed in 6.0.0:

  • setDeserializationCustomFeatures(Map<DeserializationFeature, Boolean>)
  • setJsonParserCustomFeatures(Map<JsonParser.Feature, Boolean>)
  • setJsonGeneratorCustomFeatures(Map<JsonGenerator.Feature, Boolean>)
  • setMapperCustomFeatures(Map<MapperFeature, Boolean>)
  • setSerializationCustomFeatures(Map<SerializationFeature, Boolean>)

If you have existing usages of these methods, see the MapperFactory documentation for an explanation on how to migrate these customizations.

JsonProcessingExceptionMapper Renamed To JacksonExceptionMapper

The JsonProcessingExceptionMapper in scim2-sdk-server has been renamed to JacksonExceptionMapper since JsonProcessingExceptions no longer exist.

If you register this provider explicitly in your JAX-RS application, update the class reference. If you rely on auto-discovery via @Provider, no change is required.


Removed throws ScimException Declarations

Several SCIM SDK methods that previously declared throws ScimException (or a subclass) no longer do so. If you run into compile errors that indicate a certain method no longer throws an exception, remove the try/catch block.

Note that unlike JacksonException, the ScimException class is still a checked exception since it generally represents an error condition that should be handled.


New ScimDeserializeException Class

This section is included for informational purposes, and should not affect migrations.

The SCIM SDK has some custom deserializer classes, such as CalendarDeserializer. In cases where an error is thrown, these have been updated to use a runtime exception in accordance with Jackson expectations. All custom deserializers that throw exceptions in the SCIM SDK will use a ScimDeserializeException object, which is based on a JacksonException.