Added SPEL evaluation against spring boot @Topic attributes (#556)

* [WIP] Added SPEL evaluation against spring boot @Topic name and pubsubname attributes

* [WIP] Updated SubscriberController to use SPEL in @Topic

* 554 - SPEL for @Topic attributes: Updated documentation and examples

* Updated documentation as discussed

* Update README.md

* Update SubscriberController.java

Co-authored-by: Artur Souza <artursouza.ms@outlook.com>
This commit is contained in:
Justin Rovang 2021-06-18 00:48:45 -05:00 committed by GitHub
parent 5c05f3d9c7
commit 0e5e3112de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 22 additions and 9 deletions

View File

@ -51,13 +51,18 @@ public class Subscriber {
```
`DaprApplication.start()` Method will run an Spring Boot application that registers the `SubscriberController`, which exposes the message retrieval as a POST request. The Dapr's sidecar is the one that performs the actual call to the controller, based on the pubsub features.
This Spring Controller handles the message endpoint, Printing the message which is received as the POST body. The topic subscription in Dapr is handled automatically via the `@Topic` annotation. See the code snippet below:
This Spring Controller handles the message endpoint, printing the message which is received as the POST body.
The subscription's topic in Dapr is handled automatically via the `@Topic` annotation - which also supports the same expressions in
[Spring's @Value annotations](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-value-annotations).
The code snippet below shows how to create a subscription using the `@Topic` annotation showcasing expression support. In this case, `myAppProperty` is a Java property that does not exist, so the expression resolves to the default value (`messagebus`).
```java
@RestController
public class SubscriberController {
///...
@Topic(name = "testingtopic", pubsubName = "messagebus")
@Topic(name = "testingtopic", pubsubName = "${myAppProperty:messagebus}")
@PostMapping(path = "/testingtopic")
public Mono<Void> handleMessage(@RequestBody(required = false) byte[] body,
@RequestHeader Map<String, String> headers) {

View File

@ -26,7 +26,7 @@ public class SubscriberController {
* @param cloudEvent The cloud event received.
* @return A message containing the time.
*/
@Topic(name = "testingtopic", pubsubName = "messagebus")
@Topic(name = "testingtopic", pubsubName = "${myAppProperty:messagebus}")
@PostMapping(path = "/testingtopic")
public Mono<Void> handleMessage(@RequestBody(required = false) CloudEvent cloudEvent) {
return Mono.fromRunnable(() -> {

View File

@ -11,6 +11,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import io.dapr.Topic;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.EmbeddedValueResolver;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
@ -26,6 +28,12 @@ public class DaprBeanPostProcessor implements BeanPostProcessor {
private static final ObjectMapper MAPPER = new ObjectMapper();
private final EmbeddedValueResolver embeddedValueResolver;
DaprBeanPostProcessor(ConfigurableBeanFactory beanFactory) {
embeddedValueResolver = new EmbeddedValueResolver(beanFactory);
}
/**
* {@inheritDoc}
*/
@ -35,7 +43,7 @@ public class DaprBeanPostProcessor implements BeanPostProcessor {
return null;
}
subscribeToTopics(bean.getClass());
subscribeToTopics(bean.getClass(), embeddedValueResolver);
return bean;
}
@ -52,12 +60,12 @@ public class DaprBeanPostProcessor implements BeanPostProcessor {
* Subscribe to topics based on {@link Topic} annotations on the given class and any of ancestor classes.
* @param clazz Controller class where {@link Topic} is expected.
*/
private static void subscribeToTopics(Class clazz) {
private static void subscribeToTopics(Class clazz, EmbeddedValueResolver embeddedValueResolver) {
if (clazz == null) {
return;
}
subscribeToTopics(clazz.getSuperclass());
subscribeToTopics(clazz.getSuperclass(), embeddedValueResolver);
for (Method method : clazz.getDeclaredMethods()) {
Topic topic = method.getAnnotation(Topic.class);
if (topic == null) {
@ -71,8 +79,8 @@ public class DaprBeanPostProcessor implements BeanPostProcessor {
route = mapping.path()[0];
}
String topicName = topic.name();
String pubSubName = topic.pubsubName();
String topicName = embeddedValueResolver.resolveStringValue(topic.name());
String pubSubName = embeddedValueResolver.resolveStringValue(topic.pubsubName());
if ((topicName != null) && (topicName.length() > 0) && pubSubName != null && pubSubName.length() > 0) {
try {
TypeReference<HashMap<String, String>> typeRef

View File

@ -77,7 +77,7 @@ public class SubscriberController {
});
}
@Topic(name = "anothertopic", pubsubName = "messagebus")
@Topic(name = "#{'another'.concat('topic')}", pubsubName = "${pubsubName:messagebus}")
@PostMapping(path = "/route3")
public Mono<Void> handleMessageAnotherTopic(@RequestBody(required = false) CloudEvent envelope) {
return Mono.fromRunnable(() -> {