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:
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.event;
|
||||
|
||||
import org.eclipse.hawkbit.HawkbitAutoConfiguration;
|
||||
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* The {@link EventJacksonConfiguration} adds to the {@link tools.jackson.databind.json.JsonMapper} configuration
|
||||
* (already modified by the {@link HawkbitAutoConfiguration}) the event subtypes defined in {@link EventType}
|
||||
*/
|
||||
@Configuration
|
||||
@Import(HawkbitAutoConfiguration.class)
|
||||
public class EventJacksonConfiguration {
|
||||
|
||||
@Bean
|
||||
JsonMapperBuilderCustomizer jsonMapperBuilderCustomizer() {
|
||||
return jsonMapperBuilder -> jsonMapperBuilder.registerSubtypes(EventType.getNamedTypes());
|
||||
}
|
||||
}
|
||||
@@ -9,30 +9,35 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.event;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
|
||||
import org.springframework.messaging.converter.JacksonJsonMessageConverter;
|
||||
import org.springframework.util.MimeType;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
public class EventJacksonMessageConverter extends MappingJackson2MessageConverter {
|
||||
public class EventJacksonMessageConverter extends JacksonJsonMessageConverter {
|
||||
|
||||
public static final MimeType APPLICATION_REMOTE_EVENT_JSON = new MimeType("application", "remote-event-json");
|
||||
|
||||
public EventJacksonMessageConverter() {
|
||||
super(APPLICATION_REMOTE_EVENT_JSON);
|
||||
final ObjectMapper objectMapper = new ObjectMapper();
|
||||
EventType.getNamedTypes().forEach(objectMapper::registerSubtypes);
|
||||
setObjectMapper(objectMapper);
|
||||
public EventJacksonMessageConverter(final JsonMapper mapper) {
|
||||
super(mapper, APPLICATION_REMOTE_EVENT_JSON);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object convertToInternal(final Object payload, final MessageHeaders headers, final Object conversionHint) {
|
||||
@SuppressWarnings("java:S1185") // intentionally override in order to extend visibility
|
||||
@NullMarked
|
||||
@Nullable
|
||||
protected Object convertToInternal(final Object payload, @Nullable final MessageHeaders headers, @Nullable final Object conversionHint) {
|
||||
return super.convertToInternal(payload, headers, conversionHint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object convertFromInternal(final Message<?> message, final Class<?> targetClass, final Object conversionHint) {
|
||||
@SuppressWarnings("java:S1185") // intentionally override in order to extend visibility
|
||||
@NullMarked
|
||||
@Nullable
|
||||
protected Object convertFromInternal(final Message<?> message, final Class<?> targetClass, @Nullable final Object conversionHint) {
|
||||
return super.convertFromInternal(message, targetClass, conversionHint);
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@ import io.protostuff.Schema;
|
||||
import io.protostuff.runtime.RuntimeSchema;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEvent;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.converter.AbstractMessageConverter;
|
||||
@@ -46,18 +48,20 @@ public class EventProtoStuffMessageConverter extends AbstractMessageConverter {
|
||||
public static final MimeType APPLICATION_BINARY_PROTOSTUFF = new MimeType("application", "binary+protostuff");
|
||||
private static final int HEADER_LENGTH_PREFIX_SIZE = 4;
|
||||
|
||||
|
||||
public EventProtoStuffMessageConverter() {
|
||||
super(APPLICATION_BINARY_PROTOSTUFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NullMarked
|
||||
protected boolean supports(final Class<?> aClass) {
|
||||
return AbstractRemoteEvent.class.isAssignableFrom(aClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object convertFromInternal(final Message<?> message, final Class<?> targetClass, final Object conversionHint) {
|
||||
@NullMarked
|
||||
@Nullable
|
||||
protected Object convertFromInternal(final Message<?> message, final Class<?> targetClass, @Nullable final Object conversionHint) {
|
||||
final Object objectPayload = message.getPayload();
|
||||
if (objectPayload instanceof byte[] payload) {
|
||||
final byte[] clazzHeader = extractClazzHeader(payload);
|
||||
@@ -112,7 +116,6 @@ public class EventProtoStuffMessageConverter extends AbstractMessageConverter {
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
private static EventType readClassHeader(final byte[] typeInformation) {
|
||||
final Schema<EventType> schema = RuntimeSchema.getSchema(EventType.class);
|
||||
final EventType deserializedType = schema.newMessage();
|
||||
@@ -134,8 +137,7 @@ public class EventProtoStuffMessageConverter extends AbstractMessageConverter {
|
||||
throw new MessageConversionException("Missing EventType for given class : " + clazz);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final Schema<Object> schema = (Schema<Object>) RuntimeSchema.getSchema((Class<?>) EventType.class);
|
||||
@SuppressWarnings("unchecked") final Schema<Object> schema = (Schema<Object>) RuntimeSchema.getSchema((Class<?>) EventType.class);
|
||||
final LinkedBuffer buffer = LinkedBuffer.allocate();
|
||||
byte[] typeBytes = ProtobufIOUtil.toByteArray(clazzEventType, schema, buffer);
|
||||
|
||||
|
||||
@@ -29,17 +29,20 @@ import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.event.ApplicationEventMulticaster;
|
||||
import org.springframework.context.event.SimpleApplicationEventMulticaster;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.messaging.converter.MessageConverter;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
/**
|
||||
* Autoconfiguration for the events.
|
||||
* Autoconfiguration for the events publishing.
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@Import(EventJacksonConfiguration.class)
|
||||
public class EventPublisherConfiguration {
|
||||
|
||||
/**
|
||||
@@ -108,15 +111,21 @@ public class EventPublisherConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Consumer<AbstractRemoteEvent> serviceEventConsumer(ApplicationEventPublisher publisher) {
|
||||
public Consumer<AbstractRemoteEvent> serviceEventConsumer(final ApplicationEventPublisher publisher) {
|
||||
return publisher::publishEvent;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Consumer<AbstractRemoteEvent> fanoutEventConsumer(ApplicationEventPublisher publisher) {
|
||||
public Consumer<AbstractRemoteEvent> fanoutEventConsumer(final ApplicationEventPublisher publisher) {
|
||||
return publisher::publishEvent;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageConverter eventJacksonMessageConverter(final JsonMapper mapper) {
|
||||
return new EventJacksonMessageConverter(mapper);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Schema.class, ProtostuffIOUtil.class })
|
||||
protected static class EventProtostuffConfiguration {
|
||||
|
||||
@@ -125,9 +134,4 @@ public class EventPublisherConfiguration {
|
||||
return new EventProtoStuffMessageConverter();
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageConverter eventJacksonMessageConverter() {
|
||||
return new EventJacksonMessageConverter();
|
||||
}
|
||||
}
|
||||
@@ -9,12 +9,10 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.event;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.fasterxml.jackson.databind.jsontype.NamedType;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
@@ -72,15 +70,14 @@ import org.eclipse.hawkbit.repository.event.remote.service.TargetCreatedServiceE
|
||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetDeletedServiceEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetPollServiceEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetUpdatedServiceEvent;
|
||||
import tools.jackson.databind.jsontype.NamedType;
|
||||
|
||||
/**
|
||||
* The {@link EventType} class declares the event-type and it's corresponding
|
||||
* encoding value in the payload of an remote header. The event-type is encoded
|
||||
* into the payload of the message which is distributed.
|
||||
*
|
||||
* To encode and decode the event class type we need some conversation mapping
|
||||
* between the actual class and the corresponding integer value which is the
|
||||
* encoded value in the byte-payload.
|
||||
* The {@link EventType} class declares the event-type, and it's corresponding encoding value in the payload of a remote header.
|
||||
* The event-type is encoded into the payload of the message which is distributed.
|
||||
* <p/>
|
||||
* To encode and decode the event class type we need some conversation mapping between the actual class and the corresponding integer value
|
||||
* which is the encoded value in the byte-payload.
|
||||
*/
|
||||
// for marshalling and unmarshalling.
|
||||
@NoArgsConstructor
|
||||
@@ -93,8 +90,7 @@ public class EventType {
|
||||
|
||||
private int value;
|
||||
|
||||
// The associated event-type-value must remain the same as initially
|
||||
// declared. Otherwise, messages cannot correctly de-serialized.
|
||||
// The associated event-type-value must remain the same as initially declared. Otherwise, messages cannot correctly de-serialized.
|
||||
static {
|
||||
// target
|
||||
TYPES.put(1, TargetCreatedEvent.class);
|
||||
@@ -215,9 +211,9 @@ public class EventType {
|
||||
return TYPES.get(value);
|
||||
}
|
||||
|
||||
public static Collection<NamedType> getNamedTypes() {
|
||||
public static NamedType[] getNamedTypes() {
|
||||
return TYPES.entrySet().stream()
|
||||
.map(e -> new NamedType(e.getValue(), String.valueOf(e.getKey())))
|
||||
.toList();
|
||||
.toArray(NamedType[]::new);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user