From 52ef79d1fda433ce03838ceb15b3aac2dc315b46 Mon Sep 17 00:00:00 2001 From: chanhyeong-cho Date: Tue, 27 Aug 2024 19:21:27 +0900 Subject: [PATCH] Add typealias guides into README --- README.md | 35 +++++++++++++++++++ .../guide/boot/config/MessageConfig.java | 10 ++++-- .../guide/boot/domain/CreatePostService.java | 4 +++ .../guide/boot/domain/PostEventHandler.java | 14 ++++++++ ...erializeOnlyTypeAliasPostCreatedEvent.java | 32 +++++++++++++++++ .../ProgrammaticBindingEventListener.java | 2 ++ .../PostApiControllerIntegrationTest.java | 6 +++- 7 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/domain/SerializeOnlyTypeAliasPostCreatedEvent.java diff --git a/README.md b/README.md index 08be970..158c143 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,41 @@ public class ExampleService { } ``` +## `typealias` extension + +Eventeria provides the `typealias` extension to support following features. + +- multiple data formats for single topic. +- publish the string of message type in fixed string, even if rename of class or relocate package. + +When publishing `Message`, the message will contain `typealias` extension that you registered by `addSerializeTypeAlias` or `addCompatibleTypeAlias`. If not, full class name will be used. + +When consuming `Message`, eventeria try to deserialize the message with `typealias` extension. You should register typealias by `addDeserializeTypeAlias` or `addCompatibleTypeAlias`. +If eventeria failed to find deserialize target type, it try to load class using ClassLoader with provided `typealias` string. If there is no matching class, consuming will be failed. + +### Configuration Example + +```java +@Bean +CloudEventMessageTypeAliasMapper cloudEventMessageTypeAliasMapper() { + CloudEventMessageTypeAliasMapper typeAliasMapper = new CloudEventMessageTypeAliasMapper(); + + // support typealias at both serialization / deserialization times + typeAliasMapper.addCompatibleTypeAlias( + PostCreatedEvent.class, + "com.navercorp.eventeria.guide.boot.domain.PostCreatedEvent" + ); + + // support typealias at serialization time only + typeAliasMapper.addSerializeTypeAlias( + SerializeOnlyTypeAliasPostCreatedEvent.class, + "com.navercorp.eventeria.guide.boot.domain.PostCreatedEventSerializeOnlyVersion" + ); + + return typeAliasMapper; +} +``` + ## License ``` diff --git a/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/config/MessageConfig.java b/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/config/MessageConfig.java index 06a73bb..afa20e2 100644 --- a/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/config/MessageConfig.java +++ b/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/config/MessageConfig.java @@ -15,6 +15,7 @@ import com.navercorp.eventeria.guide.boot.domain.AfterPostCreationCommand.NotifyToSubscribers; import com.navercorp.eventeria.guide.boot.domain.PostCreatedEvent; +import com.navercorp.eventeria.guide.boot.domain.SerializeOnlyTypeAliasPostCreatedEvent; import com.navercorp.eventeria.messaging.contract.Message; import com.navercorp.eventeria.messaging.contract.cloudevents.serializer.CloudEventMessageReaderWriter; import com.navercorp.eventeria.messaging.contract.serializer.MessageSerializerDeserializer; @@ -29,8 +30,6 @@ @RequiredArgsConstructor public class MessageConfig { - private final ObjectMapper objectMapper; - static { EventFormatProvider.getInstance() .registerFormat( @@ -40,6 +39,8 @@ public class MessageConfig { ); } + private final ObjectMapper objectMapper; + @Bean MessageSerializerDeserializer messageSerializerDeserializer() { return new JacksonMessageSerializer(objectMapper); @@ -54,6 +55,11 @@ CloudEventMessageTypeAliasMapper cloudEventMessageTypeAliasMapper() { "com.navercorp.eventeria.guide.boot.domain.PostCreatedEvent" ); + typeAliasMapper.addSerializeTypeAlias( + SerializeOnlyTypeAliasPostCreatedEvent.class, + "com.navercorp.eventeria.guide.boot.domain.PostCreatedEventSerializeOnlyVersion" + ); + typeAliasMapper.addCompatibleTypeAlias( NotifyToSubscribers.class, "com.navercorp.eventeria.guide.boot.domain.AfterPostCreationCommand$NotifyToSubscribers" diff --git a/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/domain/CreatePostService.java b/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/domain/CreatePostService.java index fa35cd0..5c3ab2d 100644 --- a/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/domain/CreatePostService.java +++ b/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/domain/CreatePostService.java @@ -26,6 +26,10 @@ public Post create(Post post) { PostCreatedEvent.from(post) ); + springMessagePublisher.publish( + SerializeOnlyTypeAliasPostCreatedEvent.from(post) + ); + return post; } } diff --git a/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/domain/PostEventHandler.java b/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/domain/PostEventHandler.java index b873d97..67442b1 100644 --- a/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/domain/PostEventHandler.java +++ b/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/domain/PostEventHandler.java @@ -35,4 +35,18 @@ public void publishAfterPostCreatedCommands( ) ); } + + public void publishAfterPostCreatedCommands( + SerializeOnlyTypeAliasPostCreatedEvent event + ) { + log.info("[CONSUME][Programmatic][SerializeOnlyTypeAliasPostCreatedEvent] {}", event); + + springMessagePublisher.publish( + List.of( + UpdateUserStatistic.of(event.getPostId(), event.getWriterId()), + RefreshPostRanking.from(event.getPostId()), + ApplySearchIndex.from(event.getPostId()) + ) + ); + } } diff --git a/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/domain/SerializeOnlyTypeAliasPostCreatedEvent.java b/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/domain/SerializeOnlyTypeAliasPostCreatedEvent.java new file mode 100644 index 0000000..fdd0536 --- /dev/null +++ b/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/domain/SerializeOnlyTypeAliasPostCreatedEvent.java @@ -0,0 +1,32 @@ +package com.navercorp.eventeria.guide.boot.domain; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import com.navercorp.eventeria.messaging.contract.event.AbstractDomainEvent; + +@Getter +@ToString(callSuper = true) +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SerializeOnlyTypeAliasPostCreatedEvent extends AbstractDomainEvent { + + private long postId; + private String writerId; + + public SerializeOnlyTypeAliasPostCreatedEvent(long postId, String writerId) { + super(String.valueOf(postId)); + this.postId = postId; + this.writerId = writerId; + } + + public static SerializeOnlyTypeAliasPostCreatedEvent from(Post post) { + return new SerializeOnlyTypeAliasPostCreatedEvent(post.id(), post.writerId()); + } + + @Override + public String getSourceType() { + return Post.class.getName(); + } +} diff --git a/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/listener/ProgrammaticBindingEventListener.java b/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/listener/ProgrammaticBindingEventListener.java index 767cea8..d1671c4 100644 --- a/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/listener/ProgrammaticBindingEventListener.java +++ b/guide-projects/spring-boot-eventeria-guide/src/main/java/com/navercorp/eventeria/guide/boot/listener/ProgrammaticBindingEventListener.java @@ -14,6 +14,7 @@ import com.navercorp.eventeria.guide.boot.domain.PostCreatedEvent; import com.navercorp.eventeria.guide.boot.domain.PostEventHandler; +import com.navercorp.eventeria.guide.boot.domain.SerializeOnlyTypeAliasPostCreatedEvent; import com.navercorp.eventeria.messaging.contract.cloudevents.converter.CloudEventToMessageConverter; import com.navercorp.eventeria.messaging.spring.cloud.stream.binding.InboundChannelBinder; import com.navercorp.eventeria.messaging.spring.integration.channel.SpringMessageHandler; @@ -98,6 +99,7 @@ MessagePayloadTypeRouter postEventRouter( ) { return MessagePayloadTypeRouter.register(INBOUND_BEAN_NAME) .route(PostCreatedEvent.class, postEventHandler::publishAfterPostCreatedCommands) + .route(SerializeOnlyTypeAliasPostCreatedEvent.class, postEventHandler::publishAfterPostCreatedCommands) .done(); } } diff --git a/guide-projects/spring-boot-eventeria-guide/src/test/java/com/navercorp/eventeria/guide/boot/controller/PostApiControllerIntegrationTest.java b/guide-projects/spring-boot-eventeria-guide/src/test/java/com/navercorp/eventeria/guide/boot/controller/PostApiControllerIntegrationTest.java index 2998cff..5088ecd 100644 --- a/guide-projects/spring-boot-eventeria-guide/src/test/java/com/navercorp/eventeria/guide/boot/controller/PostApiControllerIntegrationTest.java +++ b/guide-projects/spring-boot-eventeria-guide/src/test/java/com/navercorp/eventeria/guide/boot/controller/PostApiControllerIntegrationTest.java @@ -64,7 +64,7 @@ void registerPost() { } private void assertPublishedMessageCount() { - int expectedPostEventCount = 1; + int expectedPostEventCount = 1 + 1; // PostCreatedEvent + SerializeOnlyTypeAliasPostCreatedEvent int expectedAfterPostCommandCount = 3; int expectedNotifyCommandCount = 1; @@ -88,7 +88,11 @@ private void assertPublishedMessageCount() { throw new RuntimeException(e); } + // PostCreatedEvent + SerializeOnlyTypeAliasPostCreatedEvent published then(actualPostEventCounter.get()).isEqualTo(expectedPostEventCount); + + // continuous command published for PostCreatedEvent only. + // Because failed to deserialize SerializeOnlyTypeAliasPostCreatedEvent then(actualAfterPostCommandCounter.get()).isEqualTo(expectedAfterPostCommandCount); then(actualNotifyCommandCounter.get()).isEqualTo(expectedNotifyCommandCount); }