This is an automated email from the ASF dual-hosted git repository. rcordier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit b36450f394af14a2b97f3dc847778707d9528535 Author: Rene Cordier <[email protected]> AuthorDate: Fri Apr 3 16:40:51 2026 +0700 JAMES-4197 EventSerializer refactoring The goal is to have methods return Optional, so the EventSerializersAggregator stops relying on json (de)serialization failures until finding the right serializer. --- .../org/apache/james/events/EventSerializer.java | 21 ++++---- .../james/events/EventSerializersAggregator.java | 60 +++++----------------- .../apache/james/events/EventBusTestFixture.java | 37 +++++++------ .../james/events/CassandraEventDeadLettersDAO.java | 8 ++- .../org/apache/james/events/EventDispatcher.java | 10 +++- .../apache/james/events/GroupConsumerRetry.java | 3 +- .../org/apache/james/events/GroupRegistration.java | 4 +- .../james/events/GroupRegistrationHandler.java | 4 +- .../james/events/KeyRegistrationHandler.java | 16 +++--- .../apache/james/events/RabbitMQEventBusTest.java | 2 +- .../james/events/PostgresEventDeadLetters.java | 9 +++- .../apache/james/json/JsonGenericSerializer.java | 42 ++++++++++++--- .../james/event/json/MailboxEventSerializer.scala | 28 +++++++--- .../james/event/json/AddedSerializationTest.java | 6 +-- .../event/json/ExpungedSerializationTest.java | 6 +-- .../event/json/FlagsUpdatedSerializationTest.java | 6 +-- .../MailboxACLUpdatedEventSerializationTest.java | 2 +- .../event/json/MailboxAddedSerializationTest.java | 2 +- .../json/MailboxDeletionSerializationTest.java | 4 +- .../json/MailboxRenamedSerializationTest.java | 2 +- .../MessageContentDeletionSerializationTest.java | 6 +-- .../json/MessageMoveEventSerializationTest.java | 8 +-- .../QuotaUsageUpdatedEventSerializationTest.java | 2 +- .../james/jmap/change/JmapEventSerializer.scala | 15 +++--- .../webadmin/routes/EventDeadLettersRoutes.java | 6 ++- 25 files changed, 174 insertions(+), 135 deletions(-) diff --git a/event-bus/api/src/main/java/org/apache/james/events/EventSerializer.java b/event-bus/api/src/main/java/org/apache/james/events/EventSerializer.java index 72360b861a..c3bf6b3869 100644 --- a/event-bus/api/src/main/java/org/apache/james/events/EventSerializer.java +++ b/event-bus/api/src/main/java/org/apache/james/events/EventSerializer.java @@ -22,29 +22,30 @@ package org.apache.james.events; import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.List; +import java.util.Optional; public interface EventSerializer { - String toJson(Event event); + Optional<String> toJson(Event event); - String toJson(Collection<Event> event); + Optional<String> toJson(Collection<Event> event); - default byte[] toJsonBytes(Event event) { - return toJson(event).getBytes(StandardCharsets.UTF_8); + default Optional<byte[]> toJsonBytes(Event event) { + return toJson(event).map(json -> json.getBytes(StandardCharsets.UTF_8)); } - default byte[] toJsonBytes(Collection<Event> event) { - return toJson(event).getBytes(StandardCharsets.UTF_8); + default Optional<byte[]> toJsonBytes(Collection<Event> event) { + return toJson(event).map(json -> json.getBytes(StandardCharsets.UTF_8)); } - Event asEvent(String serialized); + Optional<Event> asEvent(String serialized); - List<Event> asEvents(String serialized); + Optional<List<Event>> asEvents(String serialized); - default Event fromBytes(byte[] serialized) { + default Optional<Event> fromBytes(byte[] serialized) { return asEvent(new String(serialized, StandardCharsets.UTF_8)); } - default List<Event> asEventsFromBytes(byte[] serialized) { + default Optional<List<Event>> asEventsFromBytes(byte[] serialized) { return asEvents(new String(serialized, StandardCharsets.UTF_8)); } } diff --git a/event-bus/api/src/main/java/org/apache/james/events/EventSerializersAggregator.java b/event-bus/api/src/main/java/org/apache/james/events/EventSerializersAggregator.java index 0661de6c00..86b8baf3f0 100644 --- a/event-bus/api/src/main/java/org/apache/james/events/EventSerializersAggregator.java +++ b/event-bus/api/src/main/java/org/apache/james/events/EventSerializersAggregator.java @@ -37,70 +37,34 @@ public class EventSerializersAggregator implements EventSerializer { } @Override - public String toJson(Event event) { + public Optional<String> toJson(Event event) { return allEventSerializers.stream() - .map(eventSerializer -> serialize(event, eventSerializer)) + .map(eventSerializer -> eventSerializer.toJson(event)) .flatMap(Optional::stream) - .findFirst() - .orElseThrow(() -> new RuntimeException("Could not serialize event: " + event)); + .findFirst(); } @Override - public Event asEvent(String serialized) { + public Optional<Event> asEvent(String serialized) { return allEventSerializers.stream() - .map(eventSerializer -> deserialize(serialized, eventSerializer)) + .map(eventSerializer -> eventSerializer.asEvent(serialized)) .flatMap(Optional::stream) - .findFirst() - .orElseThrow(() -> new RuntimeException("Could not deserialize event: " + serialized)); + .findFirst(); } @Override - public String toJson(Collection<Event> events) { + public Optional<String> toJson(Collection<Event> events) { return allEventSerializers.stream() - .map(eventSerializer -> serialize(events, eventSerializer)) + .map(eventSerializer -> eventSerializer.toJson(events)) .flatMap(Optional::stream) - .findFirst() - .orElseThrow(() -> new RuntimeException("Could not serialize event: " + events)); + .findFirst(); } @Override - public List<Event> asEvents(String serialized) { + public Optional<List<Event>> asEvents(String serialized) { return allEventSerializers.stream() - .map(eventSerializer -> deserializeEvents(serialized, eventSerializer)) + .map(eventSerializer -> eventSerializer.asEvents(serialized)) .flatMap(Optional::stream) - .findFirst() - .orElseThrow(() -> new RuntimeException("Could not deserialize event: " + serialized)); - } - - private Optional<String> serialize(Event event, EventSerializer eventSerializer) { - try { - return Optional.of(eventSerializer.toJson(event)); - } catch (Exception ex) { - return Optional.empty(); - } - } - - private Optional<String> serialize(Collection<Event> event, EventSerializer eventSerializer) { - try { - return Optional.of(eventSerializer.toJson(event)); - } catch (Exception ex) { - return Optional.empty(); - } - } - - private Optional<Event> deserialize(String json, EventSerializer eventSerializer) { - try { - return Optional.of(eventSerializer.asEvent(json)); - } catch (Exception ex) { - return Optional.empty(); - } - } - - private Optional<List<Event>> deserializeEvents(String json, EventSerializer eventSerializer) { - try { - return Optional.of(eventSerializer.asEvents(json)); - } catch (Exception ex) { - return Optional.empty(); - } + .findFirst(); } } diff --git a/event-bus/api/src/test/java/org/apache/james/events/EventBusTestFixture.java b/event-bus/api/src/test/java/org/apache/james/events/EventBusTestFixture.java index cf1fb30def..b56985cfc9 100644 --- a/event-bus/api/src/test/java/org/apache/james/events/EventBusTestFixture.java +++ b/event-bus/api/src/test/java/org/apache/james/events/EventBusTestFixture.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.when; import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -34,7 +35,6 @@ import java.util.stream.Collectors; import org.apache.james.core.Username; import com.google.common.base.Joiner; -import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -178,36 +178,43 @@ public interface EventBusTestFixture { static final String ARRAY_SEPARATOR = "^"; @Override - public String toJson(Event event) { - Preconditions.checkArgument(event instanceof TestEvent || event instanceof UnsupportedEvent); - return event.getClass().getCanonicalName() + "&" + event.getEventId().getId().toString() + "&" + event.getUsername().asString(); + public Optional<String> toJson(Event event) { + if (!(event instanceof TestEvent || event instanceof UnsupportedEvent)) { + return Optional.empty(); + } + return Optional.of(event.getClass().getCanonicalName() + "&" + event.getEventId().getId().toString() + "&" + event.getUsername().asString()); } @Override - public Event asEvent(String serialized) { - Preconditions.checkArgument(serialized.contains("&")); - Preconditions.checkArgument(!serialized.contains(ARRAY_SEPARATOR)); + public Optional<Event> asEvent(String serialized) { + if (!serialized.contains("&") || serialized.contains(ARRAY_SEPARATOR)) { + return Optional.empty(); + } List<String> parts = Splitter.on("&").splitToList(serialized); - Preconditions.checkArgument(parts.get(0).equals(TestEvent.class.getCanonicalName())); + if (!parts.get(0).equals(TestEvent.class.getCanonicalName())) { + return Optional.empty(); + } Event.EventId eventId = Event.EventId.of(UUID.fromString(parts.get(1))); Username username = Username.of(Joiner.on("&").join(parts.stream().skip(2).collect(ImmutableList.toImmutableList()))); - return new TestEvent(eventId, username); + return Optional.of(new TestEvent(eventId, username)); } @Override - public String toJson(Collection<Event> event) { - return event.stream() + public Optional<String> toJson(Collection<Event> event) { + return Optional.of(event.stream() .map(this::toJson) - .collect(Collectors.joining(ARRAY_SEPARATOR)); + .map(Optional::get) + .collect(Collectors.joining(ARRAY_SEPARATOR))); } @Override - public List<Event> asEvents(String serialized) { - return Splitter.on(ARRAY_SEPARATOR) + public Optional<List<Event>> asEvents(String serialized) { + return Optional.of(Splitter.on(ARRAY_SEPARATOR) .splitToStream(serialized) .map(this::asEvent) - .collect(ImmutableList.toImmutableList()); + .map(Optional::get) + .collect(ImmutableList.toImmutableList())); } } diff --git a/event-bus/cassandra/src/main/java/org/apache/james/events/CassandraEventDeadLettersDAO.java b/event-bus/cassandra/src/main/java/org/apache/james/events/CassandraEventDeadLettersDAO.java index 4014caa13d..d7a547c643 100644 --- a/event-bus/cassandra/src/main/java/org/apache/james/events/CassandraEventDeadLettersDAO.java +++ b/event-bus/cassandra/src/main/java/org/apache/james/events/CassandraEventDeadLettersDAO.java @@ -104,10 +104,13 @@ public class CassandraEventDeadLettersDAO { } Mono<Void> store(Group group, Event failedEvent, EventDeadLetters.InsertionId insertionId) { + String serializedEvent = eventSerializer.toJson(failedEvent) + .orElseThrow(() -> new RuntimeException("Could not serialize event: " + failedEvent)); + return executor.executeVoid(insertStatement.bind() .setString(GROUP, group.asString()) .setUuid(INSERTION_ID, insertionId.getId()) - .setString(EVENT, eventSerializer.toJson(failedEvent))); + .setString(EVENT, serializedEvent)); } Mono<Void> removeEvent(Group group, EventDeadLetters.InsertionId failedInsertionId) { @@ -139,6 +142,7 @@ public class CassandraEventDeadLettersDAO { } private Event deserializeEvent(String serializedEvent) { - return eventSerializer.asEvent(serializedEvent); + return eventSerializer.asEvent(serializedEvent) + .orElseThrow(() -> new RuntimeException("Could not deserialize event: " + serializedEvent)); } } diff --git a/event-bus/distributed/src/main/java/org/apache/james/events/EventDispatcher.java b/event-bus/distributed/src/main/java/org/apache/james/events/EventDispatcher.java index f0316ea3e2..ef74ebce34 100644 --- a/event-bus/distributed/src/main/java/org/apache/james/events/EventDispatcher.java +++ b/event-bus/distributed/src/main/java/org/apache/james/events/EventDispatcher.java @@ -180,7 +180,7 @@ public class EventDispatcher { .flatMap(event -> event.keys().stream()) .collect(ImmutableSet.toImmutableSet()); - return Mono.fromCallable(() -> eventSerializer.toJsonBytes(underlyingEvents)) + return Mono.fromCallable(() -> serializeEvents(underlyingEvents)) .flatMap(serializedEvent -> Mono.zipDelayError( remoteGroupsDispatch(serializedEvent, underlyingEvents), remoteKeysDispatch(serializedEvent, keys))) @@ -258,6 +258,12 @@ public class EventDispatcher { } private byte[] serializeEvent(Event event) { - return eventSerializer.toJsonBytes(event); + return eventSerializer.toJsonBytes(event) + .orElseThrow(() -> new RuntimeException("Could not serialize event: " + event)); + } + + private byte[] serializeEvents(Collection<Event> event) { + return eventSerializer.toJsonBytes(event) + .orElseThrow(() -> new RuntimeException("Could not serialize events")); } } diff --git a/event-bus/distributed/src/main/java/org/apache/james/events/GroupConsumerRetry.java b/event-bus/distributed/src/main/java/org/apache/james/events/GroupConsumerRetry.java index 545fbe3fe3..9b03c9171d 100644 --- a/event-bus/distributed/src/main/java/org/apache/james/events/GroupConsumerRetry.java +++ b/event-bus/distributed/src/main/java/org/apache/james/events/GroupConsumerRetry.java @@ -100,7 +100,8 @@ class GroupConsumerRetry { } private Mono<Void> sendRetryMessage(Event event, int currentRetryCount) { - byte[] eventAsBytes = eventSerializer.toJsonBytes(event); + byte[] eventAsBytes = eventSerializer.toJsonBytes(event) + .orElseThrow(() -> new RuntimeException("Could not serialize event: " + event)); Mono<OutboundMessage> retryMessage = Mono.just(new OutboundMessage( retryExchangeName.asString(), diff --git a/event-bus/distributed/src/main/java/org/apache/james/events/GroupRegistration.java b/event-bus/distributed/src/main/java/org/apache/james/events/GroupRegistration.java index bd9e72f4a9..a3be6d6eeb 100644 --- a/event-bus/distributed/src/main/java/org/apache/james/events/GroupRegistration.java +++ b/event-bus/distributed/src/main/java/org/apache/james/events/GroupRegistration.java @@ -27,6 +27,7 @@ import static org.apache.james.backends.rabbitmq.Constants.evaluateAutoDelete; import static org.apache.james.backends.rabbitmq.Constants.evaluateDurable; import static org.apache.james.backends.rabbitmq.Constants.evaluateExclusive; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -177,7 +178,8 @@ class GroupRegistration implements Registration { } private Mono<Event> deserializeEvent(byte[] eventAsBytes) { - return Mono.fromCallable(() -> eventSerializer.fromBytes(eventAsBytes)) + return Mono.fromCallable(() -> eventSerializer.fromBytes(eventAsBytes) + .orElseThrow(() -> new RuntimeException("Could not deserialize event: " + new String(eventAsBytes, StandardCharsets.UTF_8)))) .subscribeOn(Schedulers.parallel()); } diff --git a/event-bus/distributed/src/main/java/org/apache/james/events/GroupRegistrationHandler.java b/event-bus/distributed/src/main/java/org/apache/james/events/GroupRegistrationHandler.java index 6f4b540f53..69e1add06a 100644 --- a/event-bus/distributed/src/main/java/org/apache/james/events/GroupRegistrationHandler.java +++ b/event-bus/distributed/src/main/java/org/apache/james/events/GroupRegistrationHandler.java @@ -152,7 +152,9 @@ public class GroupRegistrationHandler { } private Mono<List<Event>> deserializeEvents(byte[] eventAsBytes) { - return Mono.fromCallable(() -> eventSerializer.asEventsFromBytes(eventAsBytes)); + return Mono.fromCallable(() -> + eventSerializer.asEventsFromBytes(eventAsBytes) + .orElseThrow(() -> new RuntimeException("Could not deserialize events"))); } void stop() { diff --git a/event-bus/distributed/src/main/java/org/apache/james/events/KeyRegistrationHandler.java b/event-bus/distributed/src/main/java/org/apache/james/events/KeyRegistrationHandler.java index ab378fbec6..3a9c371678 100644 --- a/event-bus/distributed/src/main/java/org/apache/james/events/KeyRegistrationHandler.java +++ b/event-bus/distributed/src/main/java/org/apache/james/events/KeyRegistrationHandler.java @@ -26,6 +26,7 @@ import static org.apache.james.backends.rabbitmq.Constants.evaluateDurable; import static org.apache.james.backends.rabbitmq.Constants.evaluateExclusive; import static org.apache.james.events.RabbitMQEventBus.EVENT_BUS_ID; +import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.List; import java.util.Optional; @@ -218,14 +219,12 @@ class KeyRegistrationHandler { byte[] bodyAsBytes = deliver.getBody(); // if the json is an array, we have multiple events if (bodyAsBytes != null && bodyAsBytes.length > 0 && bodyAsBytes[0] == '[') { - return eventSerializer.asEventsFromBytes(bodyAsBytes); + return deserializeEvents(bodyAsBytes); } - try { - return List.of(eventSerializer.fromBytes(bodyAsBytes)); - } catch (RuntimeException exception) { - return eventSerializer.asEventsFromBytes(bodyAsBytes); - } + return eventSerializer.fromBytes(bodyAsBytes) + .map(List::of) + .orElse(deserializeEvents(bodyAsBytes)); } private StructuredLogger structuredLogger(List<Event> events, RegistrationKey key) { @@ -241,4 +240,9 @@ class KeyRegistrationHandler { .collect(Collectors.joining(","))) .field(EventBus.StructuredLoggingFields.REGISTRATION_KEY, key.asString()); } + + private List<Event> deserializeEvents(byte[] bodyAsBytes) { + return eventSerializer.asEventsFromBytes(bodyAsBytes) + .orElseThrow(() -> new RuntimeException("Could not deserialize events: " + new String(bodyAsBytes, StandardCharsets.UTF_8))); + } } diff --git a/event-bus/distributed/src/test/java/org/apache/james/events/RabbitMQEventBusTest.java b/event-bus/distributed/src/test/java/org/apache/james/events/RabbitMQEventBusTest.java index e5addb75c6..38eb279be2 100644 --- a/event-bus/distributed/src/test/java/org/apache/james/events/RabbitMQEventBusTest.java +++ b/event-bus/distributed/src/test/java/org/apache/james/events/RabbitMQEventBusTest.java @@ -431,7 +431,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract, .blockFirst() .getBody(); - return eventSerializer.asEvent(new String(eventInBytes, StandardCharsets.UTF_8)); + return eventSerializer.asEvent(new String(eventInBytes, StandardCharsets.UTF_8)).get(); } } } diff --git a/event-bus/postgres/src/main/java/org/apache/james/events/PostgresEventDeadLetters.java b/event-bus/postgres/src/main/java/org/apache/james/events/PostgresEventDeadLetters.java index 39b79145ed..4c4bb07357 100644 --- a/event-bus/postgres/src/main/java/org/apache/james/events/PostgresEventDeadLetters.java +++ b/event-bus/postgres/src/main/java/org/apache/james/events/PostgresEventDeadLetters.java @@ -50,11 +50,14 @@ public class PostgresEventDeadLetters implements EventDeadLetters { Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL); Preconditions.checkArgument(failDeliveredEvent != null, FAIL_DELIVERED_EVENT_CANNOT_BE_NULL); + String serializedEvent = eventSerializer.toJson(failDeliveredEvent) + .orElseThrow(() -> new RuntimeException("Could not serialize event: " + failDeliveredEvent)); + InsertionId insertionId = InsertionId.random(); return postgresExecutor.executeVoid(dslContext -> Mono.from(dslContext.insertInto(TABLE_NAME) .set(INSERTION_ID, insertionId.getId()) .set(GROUP, registeredGroup.asString()) - .set(EVENT, eventSerializer.toJson(failDeliveredEvent)))) + .set(EVENT, serializedEvent))) .thenReturn(insertionId); } @@ -87,7 +90,9 @@ public class PostgresEventDeadLetters implements EventDeadLetters { } private Event deserializeEvent(Record record) { - return eventSerializer.asEvent(record.get(EVENT)); + String serializedEvent = record.get(EVENT); + return eventSerializer.asEvent(serializedEvent) + .orElseThrow(() -> new RuntimeException("Could not deserialize event: " + serializedEvent)); } @Override diff --git a/json/src/main/java/org/apache/james/json/JsonGenericSerializer.java b/json/src/main/java/org/apache/james/json/JsonGenericSerializer.java index 4f4be5f2e9..d863e9bb3e 100644 --- a/json/src/main/java/org/apache/james/json/JsonGenericSerializer.java +++ b/json/src/main/java/org/apache/james/json/JsonGenericSerializer.java @@ -22,6 +22,7 @@ package org.apache.james.json; import java.io.IOException; import java.util.Arrays; import java.util.Collection; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -36,6 +37,7 @@ import com.fasterxml.jackson.databind.jsontype.NamedType; import com.fasterxml.jackson.datatype.guava.GuavaModule; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.github.fge.lambdas.Throwing; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; @@ -122,16 +124,31 @@ public class JsonGenericSerializer<T, U extends DTO> { return objectMapper.writeValueAsString(dto); } - public byte[] serializeToBytes(T domainObject) throws JsonProcessingException { - U dto = dtoConverter.toDTO(domainObject) - .orElseThrow(() -> new UnknownTypeException("unknown type " + domainObject.getClass())); - return objectMapper.writeValueAsBytes(dto); + public Optional<String> maybeSerialize(T domainObject) { + try { + return dtoConverter.toDTO(domainObject) + .map(Throwing.function(objectMapper::writeValueAsString).sneakyThrow()); + } catch (Exception exception) { + return Optional.empty(); + } } - public T deserializeFromBytes(byte[] value) throws IOException { - U dto = jsonToDTO(value); - return dtoConverter.toDomainObject(dto) - .orElseThrow(() -> new UnknownTypeException("unknown type " + dto.getType())); + public Optional<byte[]> maybeSerializeToBytes(T domainObject) { + try { + return dtoConverter.toDTO(domainObject) + .map(Throwing.function(objectMapper::writeValueAsBytes).sneakyThrow()); + } catch (Exception exception) { + return Optional.empty(); + } + } + + public Optional<T> maybeDeserializeFromBytes(byte[] value) { + try { + U dto = jsonToDTO(value); + return dtoConverter.toDomainObject(dto); + } catch (Exception e) { + return Optional.empty(); + } } public T deserialize(String value) throws IOException { @@ -140,6 +157,15 @@ public class JsonGenericSerializer<T, U extends DTO> { .orElseThrow(() -> new UnknownTypeException("unknown type " + dto.getType())); } + public Optional<T> maybeDeserialize(String value) { + try { + U dto = jsonToDTO(value); + return dtoConverter.toDomainObject(dto); + } catch (Exception e) { + return Optional.empty(); + } + } + private U jsonToDTO(String value) throws IOException { try { JsonNode jsonTree = detectDuplicateProperty(value); diff --git a/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala b/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala index 17b3a2008d..b0ddc58daa 100644 --- a/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala +++ b/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala @@ -21,7 +21,7 @@ package org.apache.james.event.json import java.time.Instant import java.util -import java.util.{TreeMap => JavaTreeMap} +import java.util.{Optional, TreeMap => JavaTreeMap} import jakarta.inject.Inject import julienrf.json.derived @@ -456,17 +456,31 @@ class JsonSerialize(mailboxIdFactory: MailboxId.Factory, messageIdFactory: Messa class MailboxEventSerializer @Inject()(mailboxIdFactory: MailboxId.Factory, messageIdFactory: MessageId.Factory, quotaRootDeserializer: QuotaRootDeserializer) extends EventSerializer { private val jsonSerialize = new JsonSerialize(mailboxIdFactory, messageIdFactory, quotaRootDeserializer) - override def toJson(event: JavaEvent): String = jsonSerialize.toJson(event) + override def toJson(event: JavaEvent): Optional[String] = Optional.of(jsonSerialize.toJson(event)) - override def toJsonBytes(event: JavaEvent): Array[Byte] = jsonSerialize.toJsonBytes(event) + override def toJsonBytes(event: JavaEvent): Optional[Array[Byte]] = Optional.of(jsonSerialize.toJsonBytes(event)) - override def toJsonBytes(event: util.Collection[JavaEvent]): Array[Byte] = jsonSerialize.toJsonBytes(event) + override def toJsonBytes(event: util.Collection[JavaEvent]): Optional[Array[Byte]] = Optional.of(jsonSerialize.toJsonBytes(event)) def fromJson(json: String): JsResult[JavaEvent] = jsonSerialize.fromJson(json) - override def toJson(event: util.Collection[JavaEvent]): String = jsonSerialize.toJson(event) + override def toJson(event: util.Collection[JavaEvent]): Optional[String] = Optional.of(jsonSerialize.toJson(event)) - override def asEvents(serialized: String): util.List[JavaEvent] = jsonSerialize.fromJsonAsEvents(serialized).get.asJava + override def asEvents(serialized: String): Optional[util.List[JavaEvent]] = { + val result = jsonSerialize.fromJsonAsEvents(serialized) + if (result.isError) { + Optional.empty() + } else { + Optional.of(result.get.asJava) + } + } - override def asEvent(serialized: String): JavaEvent = fromJson(serialized).get + override def asEvent(serialized: String): Optional[JavaEvent] = { + val result = fromJson(serialized) + if (result.isError) { + Optional.empty() + } else { + Optional.of(result.get) + } + } } diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/AddedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/AddedSerializationTest.java index b82ff1dc12..d5eb72a30a 100644 --- a/mailbox/event/json/src/test/java/org/apache/james/event/json/AddedSerializationTest.java +++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/AddedSerializationTest.java @@ -172,13 +172,13 @@ class AddedSerializationTest { @Test void addedShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(DEFAULT_ADDED_EVENT)) + assertThatJson(EVENT_SERIALIZER.toJson(DEFAULT_ADDED_EVENT).get()) .isEqualTo(DEFAULT_ADDED_EVENT_JSON); } @Test void addedWithDistinctMessageIdAndThreadIdShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(ADDED_WITH_DISTINCT_MESSAGE_ID_AND_THREAD_ID_EVENT)) + assertThatJson(EVENT_SERIALIZER.toJson(ADDED_WITH_DISTINCT_MESSAGE_ID_AND_THREAD_ID_EVENT).get()) .isEqualTo(ADDED_WITH_DISTINCT_MESSAGE_ID_AND_THREAD_ID_EVENT_JSON); } @@ -252,7 +252,7 @@ class AddedSerializationTest { @Test void addedShouldBeWellSerializedWhenMapKeyIsEmpty() { - assertThatJson(EVENT_SERIALIZER.toJson(emptyAddedEvent)) + assertThatJson(EVENT_SERIALIZER.toJson(emptyAddedEvent).get()) .isEqualTo(emptyAddedEventJson); } diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/ExpungedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/ExpungedSerializationTest.java index 8dfb31a1d4..e9f4550322 100644 --- a/mailbox/event/json/src/test/java/org/apache/james/event/json/ExpungedSerializationTest.java +++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/ExpungedSerializationTest.java @@ -166,13 +166,13 @@ class ExpungedSerializationTest { @Test void expungedShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(DEFAULT_EXPUNGED_EVENT)) + assertThatJson(EVENT_SERIALIZER.toJson(DEFAULT_EXPUNGED_EVENT).get()) .isEqualTo(DEFAULT_EXPUNGED_EVENT_JSON); } @Test void expungedWithDistinctMessageIdAndThreadIdShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(EXPUNGED_WITH_DISTINCT_MESSAGE_ID_AND_THREAD_ID_EVENT)) + assertThatJson(EVENT_SERIALIZER.toJson(EXPUNGED_WITH_DISTINCT_MESSAGE_ID_AND_THREAD_ID_EVENT).get()) .isEqualTo(EXPUNGED_WITH_DISTINCT_MESSAGE_ID_AND_THREAD_ID_EVENT_JSON); } @@ -242,7 +242,7 @@ class ExpungedSerializationTest { @Test void expungedShouldBeWellSerializedWhenMapKeyIsEmpty() { - assertThatJson(EVENT_SERIALIZER.toJson(emptyExpungedEvent)) + assertThatJson(EVENT_SERIALIZER.toJson(emptyExpungedEvent).get()) .isEqualTo(emptyExpungedEventJson); } diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/FlagsUpdatedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/FlagsUpdatedSerializationTest.java index 11fc5c184f..3ffa626bf5 100644 --- a/mailbox/event/json/src/test/java/org/apache/james/event/json/FlagsUpdatedSerializationTest.java +++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/FlagsUpdatedSerializationTest.java @@ -129,7 +129,7 @@ class FlagsUpdatedSerializationTest { @Test void flagsUpdatedShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(DEFAULT_EVENT)) + assertThatJson(EVENT_SERIALIZER.toJson(DEFAULT_EVENT).get()) .when(Option.IGNORING_ARRAY_ORDER) .isEqualTo(DEFAULT_EVENT_JSON); } @@ -164,7 +164,7 @@ class FlagsUpdatedSerializationTest { @Test void flagsUpdatedShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(emptyUpdatedFlagsEvent)) + assertThatJson(EVENT_SERIALIZER.toJson(emptyUpdatedFlagsEvent).get()) .when(Option.IGNORING_ARRAY_ORDER) .isEqualTo(EVENT_JSON_WITH_EMPTY_UPDATED_FLAGS); } @@ -272,7 +272,7 @@ class FlagsUpdatedSerializationTest { @Test void flagsUpdatedShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(eventWithMessageIds)) + assertThatJson(EVENT_SERIALIZER.toJson(eventWithMessageIds).get()) .when(Option.IGNORING_ARRAY_ORDER) .isEqualTo(EVENT_WITH_MESSAGE_IDS_JSON); } diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxACLUpdatedEventSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxACLUpdatedEventSerializationTest.java index d1de1dc5b4..405a596f1f 100644 --- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxACLUpdatedEventSerializationTest.java +++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxACLUpdatedEventSerializationTest.java @@ -75,7 +75,7 @@ class MailboxACLUpdatedEventSerializationTest { @Test void mailboxACLUpdatedShouldBeSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(MAILBOX_ACL_UPDATED)) + assertThatJson(EVENT_SERIALIZER.toJson(MAILBOX_ACL_UPDATED).get()) .isEqualTo(MAILBOX_ACL_UPDATED_JSON); } diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxAddedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxAddedSerializationTest.java index 1063d2f021..d80f32b19f 100644 --- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxAddedSerializationTest.java +++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxAddedSerializationTest.java @@ -60,7 +60,7 @@ class MailboxAddedSerializationTest { @Test void mailboxAddedShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(EVENT_1)) + assertThatJson(EVENT_SERIALIZER.toJson(EVENT_1).get()) .isEqualTo(JSON_1); } diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxDeletionSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxDeletionSerializationTest.java index 99f70726d7..264959a83c 100644 --- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxDeletionSerializationTest.java +++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxDeletionSerializationTest.java @@ -139,7 +139,7 @@ class MailboxDeletionSerializationTest { @Test void mailboxDeletionShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(DEFAULT_MAILBOX_DELETION_EVENT)) + assertThatJson(EVENT_SERIALIZER.toJson(DEFAULT_MAILBOX_DELETION_EVENT).get()) .isEqualTo(DEFAULT_EVENT_JSON); } @@ -151,7 +151,7 @@ class MailboxDeletionSerializationTest { @Test void mailboxDeletionWithEmptyACLShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(EMPTY_ACL_MAILBOX_DELETION_EVENT)) + assertThatJson(EVENT_SERIALIZER.toJson(EMPTY_ACL_MAILBOX_DELETION_EVENT).get()) .isEqualTo(EVENT_WITH_EMPTY_ACL_JSON); } diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxRenamedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxRenamedSerializationTest.java index 18e55d41c8..9158755962 100644 --- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxRenamedSerializationTest.java +++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxRenamedSerializationTest.java @@ -76,7 +76,7 @@ class MailboxRenamedSerializationTest { @Test void mailboxRenamedShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(DEFAULT_MAILBOX_RENAMED_EVENT)) + assertThatJson(EVENT_SERIALIZER.toJson(DEFAULT_MAILBOX_RENAMED_EVENT).get()) .isEqualTo(DEFAULT_MAILBOX_RENAMED_EVENT_JSON); } diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageContentDeletionSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageContentDeletionSerializationTest.java index 39b663f8ac..23749b7760 100644 --- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageContentDeletionSerializationTest.java +++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageContentDeletionSerializationTest.java @@ -234,8 +234,8 @@ class MessageContentDeletionSerializationTest { @Test void messageContentDeletionEventShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(EVENT)).isEqualTo(JSON); - assertThatJson(EVENT_SERIALIZER.toJson(EVENT_WITHOUT_HEADER_CONTENT)).isEqualTo(JSON_WITHOUT_HEADER_CONTENT); + assertThatJson(EVENT_SERIALIZER.toJson(EVENT).get()).isEqualTo(JSON); + assertThatJson(EVENT_SERIALIZER.toJson(EVENT_WITHOUT_HEADER_CONTENT).get()).isEqualTo(JSON_WITHOUT_HEADER_CONTENT); } @Test @@ -246,7 +246,7 @@ class MessageContentDeletionSerializationTest { @Test void messageContentDeletionEventWithMailboxPathShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(EVENT_WITH_MAILBOX_PATH)).isEqualTo(JSON_WITH_MAILBOX_PATH); + assertThatJson(EVENT_SERIALIZER.toJson(EVENT_WITH_MAILBOX_PATH).get()).isEqualTo(JSON_WITH_MAILBOX_PATH); } @Test diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageMoveEventSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageMoveEventSerializationTest.java index b24bc93049..9e2067a75f 100644 --- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageMoveEventSerializationTest.java +++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageMoveEventSerializationTest.java @@ -59,7 +59,7 @@ class MessageMoveEventSerializationTest { @Test void messageMoveEventShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(EVENT)) + assertThatJson(EVENT_SERIALIZER.toJson(EVENT).get()) .isEqualTo(JSON); } @@ -94,7 +94,7 @@ class MessageMoveEventSerializationTest { @Test void messageMoveEventShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(event)) + assertThatJson(EVENT_SERIALIZER.toJson(event).get()) .isEqualTo(json); } @@ -128,7 +128,7 @@ class MessageMoveEventSerializationTest { @Test void messageMoveEventShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(event)) + assertThatJson(EVENT_SERIALIZER.toJson(event).get()) .isEqualTo(json); } @@ -162,7 +162,7 @@ class MessageMoveEventSerializationTest { @Test void messageMoveEventShouldBeWellSerialized() { - assertThatJson(EVENT_SERIALIZER.toJson(event)) + assertThatJson(EVENT_SERIALIZER.toJson(event).get()) .isEqualTo(json); } diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java index 7991349789..f1703a787e 100644 --- a/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java +++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java @@ -77,7 +77,7 @@ class QuotaUsageUpdatedEventSerializationTest { @Test void toJsonShouldReturnQuotaEventJson() { - assertThatJson(EVENT_SERIALIZER.toJson(eventWithUserContainsUsername)) + assertThatJson(EVENT_SERIALIZER.toJson(eventWithUserContainsUsername).get()) .isEqualTo(quotaUsageUpdatedEvent); } diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/JmapEventSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/JmapEventSerializer.scala index e614af67ac..08118e10f8 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/JmapEventSerializer.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/JmapEventSerializer.scala @@ -85,20 +85,21 @@ case class JmapEventSerializer @Inject()(stateChangeEventDTOFactory: StateChange .forModules(stateChangeEventDTOFactory.dtoModule.asInstanceOf[EventDTOModule[Event, EventDTO]]) .withoutNestedType() - override def toJson(event: Event): String = genericSerializer.serialize(event) + override def toJson(event: Event): Optional[String] = genericSerializer.maybeSerialize(event) - override def asEvent(serialized: String): Event = genericSerializer.deserialize(serialized) + override def asEvent(serialized: String): Optional[Event] = genericSerializer.maybeDeserialize(serialized) - override def toJsonBytes(event: Event): Array[Byte] = genericSerializer.serializeToBytes(event) + override def toJsonBytes(event: Event): Optional[Array[Byte]] = genericSerializer.maybeSerializeToBytes(event) - override def fromBytes(serialized: Array[Byte]): Event = genericSerializer.deserializeFromBytes(serialized) + override def fromBytes(serialized: Array[Byte]): Optional[Event] = genericSerializer.maybeDeserializeFromBytes(serialized) - override def toJson(event: util.Collection[Event]): String = { + override def toJson(event: util.Collection[Event]): Optional[String] = { if (event.size() != 1) { - throw new IllegalArgumentException("Not supported for multiple events, please serialize separately") + Optional.empty() } toJson(event.iterator().next()) } - override def asEvents(serialized: String): util.List[Event] = ImmutableList.of(asEvent(serialized)) + override def asEvents(serialized: String): Optional[util.List[Event]] = + asEvent(serialized).map(event => ImmutableList.of(event)) } diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/EventDeadLettersRoutes.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/EventDeadLettersRoutes.java index 86e79a2f27..74a7751ca4 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/EventDeadLettersRoutes.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/EventDeadLettersRoutes.java @@ -106,8 +106,10 @@ public class EventDeadLettersRoutes implements Routes { EventDeadLetters.InsertionId insertionId = parseInsertionId(request); return eventDeadLettersService.getEvent(group, insertionId) - .map(eventSerializer::toJson) - .switchIfEmpty(Mono.fromRunnable(() -> response.status(HttpStatus.NOT_FOUND_404))) + .flatMap(event -> eventSerializer.toJson(event) + .map(Mono::just) + .orElseGet(Mono::empty)) + .switchIfEmpty(Mono.fromRunnable(() -> response.status(HttpStatus.NOT_FOUND_404))) .block(); } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
