[#2845] Bump Spring boot to 4.x (#2941)

Notes:
1. (!) Eclipselink shall be migrated to 5.0 (in 4.0.8 there are incompatible classes, e.g EJBQueryImpl doesn't implement some newer methods). In the moment is with beta (5.0.0-B12) - JUST for testing!
2. (!) Ethlo plugin doesn't work with Eclipselink 5.0, it builds with Eclipselink 4.0.8 (could be a problem)
3. Dependencies - new starters, test starters changes, some dependencies refactoring
4. Auto-configs split - package changes, some properties classes changes
5. Spring nullable org.springframework.lang.Nullable/NonNull are depecated and replaced with jspcify -> org.jspecify.annotations.Nullable/NonNull (NullMarked)
6. Lombok config - adding lombok.addNullAnnotations=jspecify - to do not mess annotations
7. Distributed lock table changes - SP_LOCK table db migration
8. Spring Retry replaced with Spring Core Retry - does repace retry in hawkbit
9. Specifications -> added Update/Delete(/Predicate) Specifications and JpaSpecificationExecutor changed
10. HawkbitBaseRepositoryFactoryBean modified to register properly
11. Jackson - 2 -> 3, package migrations, finals are not deserialized by default(enable finals deserialization, consider make non-final), too ‘smart’ tries to set complex objects instead of using non args constructor (-> @JsonIgnore), some other default configs made

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2026-04-14 11:31:41 +03:00
committed by GitHub
parent 23cd368e00
commit 1be473b22c
172 changed files with 1254 additions and 1045 deletions

View File

@@ -184,7 +184,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
protected void sendPingResponseToDmfReceiver(final Message ping, final String tenant, final String virtualHost) {
final Message message = MessageBuilder
.withBody(String.valueOf(java.lang.System.currentTimeMillis()).getBytes())
.withBody(String.valueOf(System.currentTimeMillis()).getBytes())
.setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN)
.setCorrelationId(ping.getMessageProperties().getCorrelationId())
.setHeader(MessageHeaderKey.TYPE, MessageType.PING_RESPONSE)
@@ -457,7 +457,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
// due to the fact that all targets in a batch use the same set of software modules we don't generate target-specific urls
final Target firstTarget = targets.get(0);
final DmfBatchDownloadAndUpdateRequest batchRequest = new DmfBatchDownloadAndUpdateRequest(
java.lang.System.currentTimeMillis(),
System.currentTimeMillis(),
dmfTargets,
Optional.ofNullable(modules)
.map(Map::entrySet)

View File

@@ -10,6 +10,7 @@
package org.eclipse.hawkbit.amqp;
import java.sql.SQLException;
import java.time.Duration;
import java.util.List;
import java.util.regex.Pattern;
@@ -32,9 +33,9 @@ import org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler
import org.springframework.amqp.rabbit.listener.FatalExceptionStrategy;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.JacksonJsonMessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.boot.amqp.autoconfigure.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -42,9 +43,10 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.core.retry.RetryPolicy;
import org.springframework.core.retry.RetryTemplate;
import org.springframework.util.ErrorHandler;
import tools.jackson.databind.json.JsonMapper;
/**
* Spring configuration for AMQP based DMF communication for indirect device integration.
@@ -91,13 +93,16 @@ public class DmfApiConfiguration {
* @return {@link RabbitTemplate} with automatic retry, published confirms and {@link Jackson2JsonMessageConverter}.
*/
@Bean
public RabbitTemplate rabbitTemplate() {
public RabbitTemplate rabbitTemplate(final JsonMapper jsonMapper) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(rabbitConnectionFactory);
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
rabbitTemplate.setMessageConverter(new JacksonJsonMessageConverter(jsonMapper));
final RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.setBackOffPolicy(new ExponentialBackOffPolicy());
rabbitTemplate.setRetryTemplate(retryTemplate);
// the same policy the previously used default ExponentialBackOffPolicy applied
rabbitTemplate.setRetryTemplate(new RetryTemplate(RetryPolicy.builder()
.delay(Duration.ofMillis(100))
.multiplier(2)
.maxDelay(Duration.ofSeconds(30))
.build()));
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
@@ -136,8 +141,8 @@ public class DmfApiConfiguration {
*/
@Bean
@ConditionalOnMissingBean
public AmqpMessageSenderService amqpSenderServiceBean() {
return new DefaultAmqpMessageSenderService(rabbitTemplate());
public AmqpMessageSenderService amqpSenderServiceBean(final RabbitTemplate rabbitTemplate) {
return new DefaultAmqpMessageSenderService(rabbitTemplate);
}
/**
@@ -203,5 +208,4 @@ public class DmfApiConfiguration {
return false;
}
}
}