Skip to main content

Migration

From 6.x.x to 7.x.x

Change notes

  • Upgrade to Spring Boot 4 and Jackson 3.

Actions

1. Update Jackson imports

If you have custom code using Jackson, update the imports from com.fasterxml.jackson.* to tools.jackson.*.

Before (Jackson 2):

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.core.type.TypeReference;

After (Jackson 3):

import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.JsonNode;
import tools.jackson.core.type.TypeReference;

2. Remove CloudEvents Jackson dependency

If you were using CloudEvents, remove the cloudevents-json-jackson dependency as it only supports Jackson 2. A built-in module now provides Jackson 3 support for CloudEvents.

// Remove this dependency
implementation 'io.cloudevents:cloudevents-json-jackson:<version>'

From 5.x.x to 6.x.x

New features

  • Connection customization: You can now customize the RabbitMQ connection by defining a ConnectionFactoryCustomizer bean. For more details, see Customizing the connection.
Programmatic configuration

@Bean
public ConnectionFactoryCustomizer connectionFactoryCustomizer() {
return (connectionFactory, asyncProps) -> {
connectionFactory.setExceptionHandler(new MyCustomExceptionHandler()); // Optional custom exception handler
connectionFactory.setCredentialsProvider(new MyCustomCredentialsProvider()); // Optional custom credentials provider
return connectionFactory;
};
}

Change notes

  • The configuration property listenReplies for RabbitMQ now defaults to null. Previously, it was true, causing all applications to subscribe to a reply queue even when not needed.
  • The domain app is now required. If not defined, the application will fail to start.

Actions

1. Configure listenReplies property

If your application uses the ReqReply pattern, you must explicitly set app.async.app.listenReplies to true. Otherwise, it should be false to avoid unnecessary resource usage.

YAML Configuration:

app:
async:
app:
listenReplies: true # set to true if ReqReply is required, false if not

Programmatic Configuration:

@Configuration
public class MyDomainConfig {

@Bean
@Primary
public AsyncRabbitPropsDomainProperties customDomainProperties() {
RabbitProperties propertiesApp = new RabbitProperties();
// Additional connection configuration goes here...
return AsyncRabbitPropsDomainProperties.builder()
.withDomain("app", AsyncProps.builder()
.connectionProperties(propertiesApp)
.listenReplies(Boolean.TRUE) // set to true if ReqReply is required, false if not
.build())
.build();
}
}

2. Define the app domain

The domain app must be defined in your configuration. Otherwise, the application will throw an exception at startup.

YAML Configuration:

app:
async:
app: # Configure the 'app' domain
# domain configuration goes here

Programmatic Configuration:

@Configuration
public class MyDomainConfig {

@Bean
@Primary
public AsyncRabbitPropsDomainProperties customDomainProperties() {
RabbitProperties propertiesApp = new RabbitProperties();
// Additional connection configuration goes here...
return AsyncRabbitPropsDomainProperties.builder()
.withDomain("app", AsyncProps.builder() // Configure the 'app' domain
.connectionProperties(propertiesApp)
.build())
.build();
}
}

From 4.x.x to 5.x.x

New features

  • Support for multiple brokers: It is now possible to configure and connect to up to two brokers simultaneously, using independent domains in the configuration.

Change notes

  • Configuration properties are now defined per domain, allowing each to have its own properties and connection settings.
  • The broker connection is no longer manually defined in the code. It is now automatically managed based on the configuration declared in the application.yaml file or through programmatic configuration.

Actions

1. Update domain configuration structure

The app domain needs to be defined to specify the configuration properties.

Before:

app:
async:
withDLQRetry: true
maxRetries: 1
retryDelay: 1000

After:

app:
async:
app: # this is the name of the default domain
withDLQRetry: true
maxRetries: 1
retryDelay: 1000

2. Migrate connection configuration

Before:

The connection was defined manually in a Java class:

@Log4j2
@Configuration
@RequiredArgsConstructor
public class MyDomainConfig {

private final RabbitMQConnectionProperties properties;
private static final String TLS = "TLSv1.2";
private static final String FAIL_MSG = "Error creating ConnectionFactoryProvider in enroll";

@Primary
@Bean
public ConnectionFactoryProvider getConnectionFactoryProvider() {
final var factory = new ConnectionFactory();
var map = PropertyMapper.get();
map.from(properties::hostname).whenNonNull().to(factory::setHost);
map.from(properties::port).to(factory::setPort);
map.from(properties::username).whenNonNull().to(factory::setUsername);
map.from(properties::password).whenNonNull().to(factory::setPassword);
map.from(properties::ssl).whenTrue().as(isSsl -> factory).to(this::configureSsl);
return () -> factory;
}

private void configureSsl(ConnectionFactory factory) {
try {
var sslContext = SSLContext.getInstance(TLS);
var trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
factory.useSslProtocol(sslContext);
} catch (KeyManagementException | KeyStoreException | NoSuchAlgorithmException e) {
log.error("{}: {}", FAIL_MSG, e);
}
}
}

After:

The connection is configured directly in the application.yaml file per domain:

app:
async:
app: # this is the name of the default domain
connectionProperties: # you can override the connection properties of each domain
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
# Another domain can be configured with same properties structure that app
accounts: # this is a second domain name and can have another independent setup
connectionProperties: # you can override the connection properties of each domain
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /accounts

Alternative - Programmatic Configuration:

Domains can also be configured programmatically:

@Configuration
public class MyDomainConfig {

@Bean
@Primary
public AsyncRabbitPropsDomainProperties customDomainProperties() {
RabbitProperties propertiesApp = new RabbitProperties();
propertiesApp.setHost("localhost");
propertiesApp.setPort(5672);
propertiesApp.setVirtualHost("/");
propertiesApp.setUsername("guest");
propertiesApp.setPassword("guest");

RabbitProperties propertiesAccounts = new RabbitProperties();
propertiesAccounts.setHost("localhost");
propertiesAccounts.setPort(5672);
propertiesAccounts.setVirtualHost("/accounts");
propertiesAccounts.setUsername("guest");
propertiesAccounts.setPassword("guest");

return AsyncRabbitPropsDomainProperties.builder()
.withDomain("app", AsyncProps.builder()
.connectionProperties(propertiesApp)
.build())
.withDomain("accounts", AsyncProps.builder()
.connectionProperties(propertiesAccounts)
.build())
.build();
}
}