Skip to content

Commit d16ecc6

Browse files
Merge pull request #16172 from ueberfuhr/BAEL-7570
BAEL-7570: Testing Quarkus with Citrus
2 parents 670fb4c + abf4d6f commit d16ecc6

35 files changed

+1264
-0
lines changed

quarkus-modules/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
<modules>
1717
<module>quarkus</module>
18+
<module>quarkus-citrus</module>
1819
<module>quarkus-extension</module>
1920
<module>quarkus-jandex</module>
2021
<module>quarkus-vs-springboot</module>
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
<?xml version="1.0"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<groupId>com.baeldung.quarkus</groupId>
7+
<artifactId>quarkus-citrus</artifactId>
8+
<version>1.0-SNAPSHOT</version>
9+
<name>quarkus-citrus</name>
10+
11+
<parent>
12+
<groupId>com.baeldung</groupId>
13+
<artifactId>quarkus-modules</artifactId>
14+
<version>1.0.0-SNAPSHOT</version>
15+
</parent>
16+
17+
<dependencyManagement>
18+
<dependencies>
19+
<dependency>
20+
<groupId>io.quarkus</groupId>
21+
<artifactId>quarkus-bom</artifactId>
22+
<version>${quarkus.version}</version>
23+
<type>pom</type>
24+
<scope>import</scope>
25+
</dependency>
26+
<dependency>
27+
<groupId>org.citrusframework</groupId>
28+
<artifactId>citrus-bom</artifactId>
29+
<version>${citrus.version}</version>
30+
<type>pom</type>
31+
<scope>import</scope>
32+
</dependency>
33+
</dependencies>
34+
</dependencyManagement>
35+
36+
<dependencies>
37+
<dependency>
38+
<groupId>io.quarkus</groupId>
39+
<artifactId>quarkus-resteasy-jackson</artifactId>
40+
<version>${quarkus.version}</version>
41+
</dependency>
42+
<dependency>
43+
<groupId>io.quarkus</groupId>
44+
<artifactId>quarkus-smallrye-openapi</artifactId>
45+
</dependency>
46+
<dependency>
47+
<groupId>io.quarkus</groupId>
48+
<artifactId>quarkus-hibernate-validator</artifactId>
49+
</dependency>
50+
<dependency>
51+
<groupId>io.quarkus</groupId>
52+
<artifactId>quarkus-hibernate-orm-panache</artifactId>
53+
</dependency>
54+
<dependency>
55+
<groupId>io.quarkus</groupId>
56+
<artifactId>quarkus-smallrye-reactive-messaging-kafka</artifactId>
57+
</dependency>
58+
<dependency>
59+
<groupId>io.quarkus</groupId>
60+
<artifactId>quarkus-jdbc-h2</artifactId>
61+
</dependency>
62+
<dependency>
63+
<groupId>io.quarkus</groupId>
64+
<artifactId>quarkus-test-h2</artifactId>
65+
<scope>test</scope>
66+
</dependency>
67+
<dependency>
68+
<groupId>org.projectlombok</groupId>
69+
<artifactId>lombok</artifactId>
70+
<version>${lombok.version}</version>
71+
<scope>provided</scope>
72+
<optional>true</optional>
73+
</dependency>
74+
<dependency>
75+
<groupId>org.mapstruct</groupId>
76+
<artifactId>mapstruct</artifactId>
77+
<version>${mapstruct.version}</version>
78+
<optional>true</optional>
79+
</dependency>
80+
<dependency>
81+
<groupId>io.quarkus</groupId>
82+
<artifactId>quarkus-junit5-mockito</artifactId>
83+
<scope>test</scope>
84+
</dependency>
85+
<dependency>
86+
<groupId>io.rest-assured</groupId>
87+
<artifactId>rest-assured</artifactId>
88+
<scope>test</scope>
89+
</dependency>
90+
<dependency>
91+
<groupId>org.citrusframework</groupId>
92+
<artifactId>citrus-quarkus</artifactId>
93+
<scope>test</scope>
94+
</dependency>
95+
<dependency>
96+
<groupId>org.citrusframework</groupId>
97+
<artifactId>citrus-openapi</artifactId>
98+
<scope>test</scope>
99+
</dependency>
100+
<dependency>
101+
<groupId>org.citrusframework</groupId>
102+
<artifactId>citrus-http</artifactId>
103+
<scope>test</scope>
104+
</dependency>
105+
<dependency>
106+
<groupId>org.citrusframework</groupId>
107+
<artifactId>citrus-validation-json</artifactId>
108+
</dependency>
109+
<dependency>
110+
<groupId>org.citrusframework</groupId>
111+
<artifactId>citrus-validation-hamcrest</artifactId>
112+
<version>${citrus.version}</version>
113+
</dependency>
114+
<dependency>
115+
<groupId>org.citrusframework</groupId>
116+
<artifactId>citrus-sql</artifactId>
117+
<scope>test</scope>
118+
</dependency>
119+
<dependency>
120+
<groupId>org.citrusframework</groupId>
121+
<artifactId>citrus-kafka</artifactId>
122+
<scope>test</scope>
123+
</dependency>
124+
<!-- set system property for test -->
125+
<dependency>
126+
<groupId>org.junit-pioneer</groupId>
127+
<artifactId>junit-pioneer</artifactId>
128+
<version>${junit-pioneer.version}</version>
129+
<scope>test</scope>
130+
</dependency>
131+
</dependencies>
132+
<build>
133+
<pluginManagement>
134+
<plugins>
135+
<plugin>
136+
<groupId>org.apache.maven.plugins</groupId>
137+
<artifactId>maven-surefire-plugin</artifactId>
138+
<version>${maven-surefire-plugin.version}</version>
139+
<configuration>
140+
<forkCount>1</forkCount>
141+
<reuseForks>true</reuseForks>
142+
<systemPropertyVariables>
143+
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
144+
<maven.home>${maven.home}</maven.home>
145+
</systemPropertyVariables>
146+
</configuration>
147+
</plugin>
148+
<plugin>
149+
<groupId>org.apache.maven.plugins</groupId>
150+
<artifactId>maven-compiler-plugin</artifactId>
151+
<version>${maven-compiler-plugin.version}</version>
152+
<configuration>
153+
<annotationProcessorPaths>
154+
<!-- Lombok is pre-configured, but must be explicitely listed in case of further annotation processors (e.g. MapStruct) -->
155+
<path>
156+
<groupId>org.projectlombok</groupId>
157+
<artifactId>lombok</artifactId>
158+
<version>${lombok.version}</version>
159+
</path>
160+
<path>
161+
<groupId>org.mapstruct</groupId>
162+
<artifactId>mapstruct-processor</artifactId>
163+
<version>${mapstruct.version}</version>
164+
</path>
165+
<path>
166+
<groupId>org.projectlombok</groupId>
167+
<artifactId>lombok-mapstruct-binding</artifactId>
168+
<version>${lombok-mapstruct-binding.version}</version>
169+
</path>
170+
</annotationProcessorPaths>
171+
</configuration>
172+
</plugin>
173+
</plugins>
174+
</pluginManagement>
175+
<plugins>
176+
<plugin>
177+
<groupId>io.quarkus</groupId>
178+
<artifactId>quarkus-maven-plugin</artifactId>
179+
<version>${quarkus.version}</version>
180+
<executions>
181+
<execution>
182+
<goals>
183+
<goal>build</goal>
184+
<goal>generate-code</goal>
185+
<goal>generate-code-tests</goal>
186+
</goals>
187+
</execution>
188+
</executions>
189+
</plugin>
190+
</plugins>
191+
</build>
192+
193+
<properties>
194+
<quarkus.version>3.10.2</quarkus.version>
195+
<citrus.version>4.2.1</citrus.version>
196+
<mapstruct.version>1.5.5.Final</mapstruct.version>
197+
<lombok.version>1.18.30</lombok.version>
198+
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
199+
<junit-pioneer.version>2.2.0</junit-pioneer.version>
200+
<maven-surefire-plugin.version>3.2.2</maven-surefire-plugin.version>
201+
<maven-compiler-plugin.version>3.12.1</maven-compiler-plugin.version>
202+
<tutorialsproject.basedir>../../</tutorialsproject.basedir>
203+
</properties>
204+
205+
</project>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.baeldung.quarkus;
2+
3+
import io.quarkus.runtime.Quarkus;
4+
import io.quarkus.runtime.annotations.QuarkusMain;
5+
6+
@QuarkusMain
7+
public class TodosApplication {
8+
9+
public static void main(String[] args) {
10+
Quarkus.run(args);
11+
}
12+
13+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.baeldung.quarkus.shared.interceptors;
2+
3+
import java.lang.annotation.Annotation;
4+
import java.lang.reflect.Method;
5+
import java.util.Optional;
6+
7+
import lombok.experimental.UtilityClass;
8+
9+
@UtilityClass
10+
class AnnotationUtils {
11+
12+
<A extends Annotation> Optional<A> findAnnotation(Method method, Class<A> annotationClass) {
13+
Optional<A> result = Optional.ofNullable(method.getAnnotation(annotationClass));
14+
// since Java 9, we could simply use Optional#or(...)
15+
if (!result.isPresent()) {
16+
result = findAnnotation(method.getDeclaringClass(), annotationClass);
17+
}
18+
return result;
19+
}
20+
21+
<A extends Annotation> Optional<A> findAnnotation(Class<?> clazz, Class<A> annotationClass) {
22+
return Optional.ofNullable(clazz.getAnnotation(annotationClass));
23+
}
24+
25+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.baeldung.quarkus.shared.interceptors;
2+
3+
import java.lang.annotation.Documented;
4+
import java.lang.annotation.ElementType;
5+
import java.lang.annotation.Inherited;
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.RetentionPolicy;
8+
import java.lang.annotation.Target;
9+
10+
import jakarta.enterprise.util.Nonbinding;
11+
import jakarta.interceptor.InterceptorBinding;
12+
13+
import lombok.AccessLevel;
14+
import lombok.Getter;
15+
import lombok.RequiredArgsConstructor;
16+
17+
/**
18+
* Annotate a method to get an event fired after method execution.
19+
*/
20+
@Inherited
21+
@Documented
22+
@InterceptorBinding
23+
@Target({ ElementType.METHOD, ElementType.TYPE })
24+
@Retention(RetentionPolicy.RUNTIME)
25+
public @interface FireEvent {
26+
27+
/**
28+
* The event class. This class needs a constructor with the same parameters as the method.
29+
*
30+
* @return the event class
31+
*/
32+
@Nonbinding Class<?> value();
33+
34+
@Nonbinding FireMode mode() default FireMode.SYNC_AND_ASYNC;
35+
36+
@RequiredArgsConstructor
37+
@Getter(AccessLevel.PACKAGE)
38+
enum FireMode {
39+
40+
ONLY_SYNC(true, false),
41+
ONLY_ASYNC(false, true),
42+
SYNC_AND_ASYNC(true, true);
43+
44+
private final boolean fireSync;
45+
private final boolean fireAsync;
46+
47+
}
48+
49+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.baeldung.quarkus.shared.interceptors;
2+
3+
import java.util.Optional;
4+
5+
import jakarta.annotation.Priority;
6+
import jakarta.enterprise.event.Event;
7+
import jakarta.inject.Inject;
8+
import jakarta.interceptor.AroundInvoke;
9+
import jakarta.interceptor.Interceptor;
10+
import jakarta.interceptor.InvocationContext;
11+
12+
import lombok.SneakyThrows;
13+
14+
@Priority(5) // do this before validation to allow publishing events on exception too
15+
@Interceptor
16+
@FireEvent(Object.class)
17+
public class FireEventInterceptor {
18+
19+
@Inject
20+
Event<Object> eventPublisher;
21+
22+
@SneakyThrows
23+
private static <T> T createEventObject(InvocationContext invocation, Class<T> eventType) {
24+
return eventType.getConstructor(invocation.getMethod()
25+
.getParameterTypes())
26+
.newInstance(invocation.getParameters());
27+
}
28+
29+
@AroundInvoke
30+
public Object fireEvent(InvocationContext invocation) throws Exception {
31+
final Optional<FireEvent> annotation = AnnotationUtils.findAnnotation(invocation.getMethod(), FireEvent.class);
32+
@SuppressWarnings("unchecked") final Optional<Class<Object>> eventType = AnnotationUtils.findAnnotation(invocation.getMethod(), FireEvent.class)
33+
.map((FireEvent publishEvent) -> (Class<Object>) publishEvent.value());
34+
final FireEvent.FireMode mode = annotation.map(FireEvent::mode)
35+
.orElse(FireEvent.FireMode.SYNC_AND_ASYNC);
36+
final Optional<Object> event = eventType.map(clazz -> createEventObject(invocation, clazz));
37+
// if something is wrong until here, we do not invoke the service's create-method
38+
// now, we invoke the service
39+
final Object result = invocation.proceed();
40+
// if an exception occured, the event is not fired
41+
// now, we fire the event
42+
event.ifPresent(e -> eventType.map(eventPublisher::select)
43+
.ifPresent(publisher -> {
44+
// fire synchronous events
45+
if (mode.isFireSync()) {
46+
publisher.fire(e);
47+
}
48+
// if no error occured, fire asynchronous events
49+
if (mode.isFireAsync()) {
50+
publisher.fireAsync(e);
51+
}
52+
}));
53+
// and we need to return the service's result to the invoker (the controller)
54+
return result;
55+
}
56+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.baeldung.quarkus.shared.interceptors;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Inherited;
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.RetentionPolicy;
7+
import java.lang.annotation.Target;
8+
9+
import jakarta.interceptor.InterceptorBinding;
10+
11+
@Inherited
12+
@InterceptorBinding
13+
@Target({ ElementType.METHOD, ElementType.TYPE })
14+
@Retention(RetentionPolicy.RUNTIME)
15+
public @interface Validated {
16+
17+
}

0 commit comments

Comments
 (0)