diff --git a/common/common/src/main/java/io/helidon/common/FeatureCatalog.java b/common/common/src/main/java/io/helidon/common/FeatureCatalog.java
index 4fe82c495d4..151212b903d 100644
--- a/common/common/src/main/java/io/helidon/common/FeatureCatalog.java
+++ b/common/common/src/main/java/io/helidon/common/FeatureCatalog.java
@@ -150,7 +150,8 @@ final class FeatureCatalog {
.name("Websocket")
.description("Jakarta Websocket implementation")
.path("WebServer", "Websocket")
- .nativeSupported(false));
+ .nativeSupported(true)
+ .nativeDescription("Server only"));
/*
* MP Modules
diff --git a/dependencies/pom.xml b/dependencies/pom.xml
index 3bf24685a62..ec925a79591 100644
--- a/dependencies/pom.xml
+++ b/dependencies/pom.xml
@@ -51,7 +51,7 @@
2.3.1
1.30.5
2.3.3
- 20.0.0
+ 20.1.0
1.27.1
28.1-jre
1.4.199
diff --git a/docs/se/aot/01_introduction.adoc b/docs/se/aot/01_introduction.adoc
index aeed3b5eeee..cb1570e6d3e 100644
--- a/docs/se/aot/01_introduction.adoc
+++ b/docs/se/aot/01_introduction.adoc
@@ -102,7 +102,7 @@ for native image.
|✅ |{nbsp} |JSON-P |{nbsp}
|✅ |{nbsp} |Multi-part |{nbsp}
|❓ |{nbsp} |Prometheus |Not yet tested.
-|❓ |{nbsp} |Websocket |Not yet tested.
+|✅ |{nbsp} |Websocket |Server only.
|❓ |gRPC Server |gRPC Server |Not yet tested.
|✅ |{nbsp} |Metrics |{nbsp}
|❓ |gRPC Client |gRPC Client |Not yet tested.
diff --git a/integrations/graal/native-image-extension/src/main/java/io/helidon/integrations/graal/nativeimage/extension/HelidonReflectionFeature.java b/integrations/graal/native-image-extension/src/main/java/io/helidon/integrations/graal/nativeimage/extension/HelidonReflectionFeature.java
index 76cf34842b2..4c5f8cbc3af 100644
--- a/integrations/graal/native-image-extension/src/main/java/io/helidon/integrations/graal/nativeimage/extension/HelidonReflectionFeature.java
+++ b/integrations/graal/native-image-extension/src/main/java/io/helidon/integrations/graal/nativeimage/extension/HelidonReflectionFeature.java
@@ -794,9 +794,8 @@ private void addConstructors() {
}
void addFields(boolean all) {
- Field[] fields = clazz.getFields();
-
try {
+ Field[] fields = clazz.getFields();
// add all public fields
for (Field field : fields) {
add(field);
diff --git a/tests/integration/native-image/se-1/README.md b/tests/integration/native-image/se-1/README.md
index c5bc5827993..b802da71ccd 100644
--- a/tests/integration/native-image/se-1/README.md
+++ b/tests/integration/native-image/se-1/README.md
@@ -40,4 +40,21 @@ curl -i -H "Accept: application/json" http://localhost:7076/metrics
# Should return ALL TESTS PASSED! after passing all webclient tests
curl -i http://localhost:7076/wc/test
+
+# Should return: Upgrade: websocket
+curl \
+ --include \
+ --no-buffer \
+ --header "Connection: Upgrade" \
+ --header "Upgrade: websocket" \
+ --header "Host: localhost:7076" \
+ --header "Origin: http://localhost:7076" \
+ --header "Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==" \
+ --header "Sec-WebSocket-Version: 13" \
+ http://localhost:7076/ws/messages
+
+# Bi-directional test is possible with websocat tool
+# should return 'part1 part2'
+for msg in "part1" "part2" "SEND"; do echo $msg; done \
+| websocat ws://127.0.0.1:7076/ws/messages
```
diff --git a/tests/integration/native-image/se-1/pom.xml b/tests/integration/native-image/se-1/pom.xml
index 10f9549814a..89d31e11fe3 100644
--- a/tests/integration/native-image/se-1/pom.xml
+++ b/tests/integration/native-image/se-1/pom.xml
@@ -35,6 +35,7 @@
JSON-P
Classpath static content
File static content
+ Tyrus(web sockets)
Config (with change support)
File watch
Classpath
@@ -64,6 +65,10 @@
io.helidon.webserver
helidon-webserver
+
+ io.helidon.webserver
+ helidon-webserver-tyrus
+
io.helidon.media
helidon-media-jsonp
diff --git a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/Se1Main.java b/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/Se1Main.java
index b0d76703733..033b7643320 100644
--- a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/Se1Main.java
+++ b/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/Se1Main.java
@@ -32,9 +32,12 @@
import io.helidon.webserver.Routing;
import io.helidon.webserver.StaticContentSupport;
import io.helidon.webserver.WebServer;
+import io.helidon.webserver.tyrus.TyrusSupport;
import org.eclipse.microprofile.health.HealthCheckResponse;
+import javax.websocket.server.ServerEndpointConfig;
+
import static io.helidon.config.ConfigSources.classpath;
import static io.helidon.config.ConfigSources.file;
@@ -42,7 +45,6 @@
* Main class of this integration test.
*/
public final class Se1Main {
-
/**
* Cannot be instantiated.
*/
@@ -143,6 +145,12 @@ private static Routing createRouting(Config config) {
.register("/greet", greetService)
.register("/wc", webClientService)
.register("/zipkin", zipkinService)
+ .register("/ws",
+ TyrusSupport.builder().register(
+ ServerEndpointConfig.Builder.create(
+ WebSocketEndpoint.class, "/messages")
+ .build())
+ .build())
.build();
}
diff --git a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/WebSocketEndpoint.java b/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/WebSocketEndpoint.java
new file mode 100644
index 00000000000..92fe3459805
--- /dev/null
+++ b/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/WebSocketEndpoint.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2020 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package io.helidon.tests.integration.nativeimage.se1;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.websocket.Endpoint;
+import javax.websocket.EndpointConfig;
+import javax.websocket.MessageHandler;
+import javax.websocket.Session;
+
+
+public class WebSocketEndpoint extends Endpoint {
+
+ private static final Logger LOGGER = Logger.getLogger(WebSocketEndpoint.class.getName());
+
+ @Override
+ public void onOpen(Session session, EndpointConfig endpointConfig) {
+
+ StringBuilder sb = new StringBuilder();
+
+ LOGGER.log(Level.INFO, "Session " + session.getId());
+ session.addMessageHandler(new MessageHandler.Whole() {
+ @Override
+ public void onMessage(String message) {
+ LOGGER.log(Level.INFO, "WS Receiving " + message);
+ if (message.contains("SEND")) {
+ sendTextMessage(session, sb.toString());
+ sb.setLength(0);
+ } else {
+ sb.append(message);
+ }
+ }
+ });
+ }
+
+ private void sendTextMessage(Session session, String msg) {
+ try {
+ session.getBasicRemote().sendText(msg);
+ } catch (IOException e) {
+ LOGGER.log(Level.SEVERE, "Message sending failed", e);
+ }
+ }
+}
diff --git a/webserver/tyrus/src/main/resources/META-INF/helidon/native-image/reflection-config.json b/webserver/tyrus/src/main/resources/META-INF/helidon/native-image/reflection-config.json
new file mode 100644
index 00000000000..28ed29528e8
--- /dev/null
+++ b/webserver/tyrus/src/main/resources/META-INF/helidon/native-image/reflection-config.json
@@ -0,0 +1,19 @@
+{
+ "annotated": [],
+ "class-hierarchy": [
+ "javax.websocket.Endpoint",
+ "javax.websocket.Encoder",
+ "javax.websocket.Decoder",
+ "org.glassfish.tyrus.spi.ClientContainer",
+ "io.netty.channel.ChannelInboundHandlerAdapter",
+ "io.netty.channel.ChannelHandlerAdapter",
+ "io.netty.channel.ChannelInboundHandler",
+ "io.netty.channel.ChannelOutboundHandler"
+ ],
+ "classes": [
+ "javax.websocket.CloseReason",
+ "javax.naming.InitialContext"
+ ],
+ "exclude": [
+ ]
+}
\ No newline at end of file