Skip to content

Commit

Permalink
Respect endpoint encoders/decoders for path parameters
Browse files Browse the repository at this point in the history
`PathParameters` could only make use of the default encoding factory, which allows primitive and String types.

With this change, custom encoders/decoders are considered, too.

Fixes quarkusioGH-52
  • Loading branch information
micheljung committed Feb 7, 2021
1 parent 8403f58 commit 7c93d8e
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ public InstanceHandle<Object> createInstance() throws InstantiationException {

AnnotatedEndpointFactory annotatedEndpointFactory = null;
if (!Endpoint.class.isAssignableFrom(sec.getEndpointClass())) {
annotatedEndpointFactory = AnnotatedEndpointFactory.create(sec.getEndpointClass(), encodingFactory, pt.getParameterNames());
annotatedEndpointFactory = AnnotatedEndpointFactory.create(sec.getEndpointClass(), encodingFactory, pt.getParameterNames(), config);
}


Expand Down Expand Up @@ -686,24 +686,6 @@ private synchronized void addEndpointInternal(final Class<?> endpoint, boolean r
seenPaths.add(template);
Class<? extends ServerEndpointConfig.Configurator> configuratorClass = serverEndpoint.configurator();

EncodingFactory encodingFactory = EncodingFactory.createFactory(classIntrospecter, serverEndpoint.decoders(), serverEndpoint.encoders());
AnnotatedEndpointFactory annotatedEndpointFactory = AnnotatedEndpointFactory.create(endpoint, encodingFactory, template.getParameterNames());
InstanceFactory<?> instanceFactory = null;
try {
instanceFactory = classIntrospecter.createInstanceFactory(endpoint);
} catch (Exception e) {
//so it is possible that this is still valid if a custom configurator is in use
if (configuratorClass == ServerEndpointConfig.Configurator.class) {
throw JsrWebSocketMessages.MESSAGES.couldNotDeploy(e);
} else {
instanceFactory = new InstanceFactory<Object>() {
@Override
public InstanceHandle<Object> createInstance() throws InstantiationException {
throw JsrWebSocketMessages.MESSAGES.endpointDoesNotHaveAppropriateConstructor(endpoint);
}
};
}
}
ServerEndpointConfig.Configurator configurator;
if (configuratorClass != ServerEndpointConfig.Configurator.class) {
try {
Expand All @@ -719,10 +701,28 @@ public InstanceHandle<Object> createInstance() throws InstantiationException {
.decoders(Arrays.asList(serverEndpoint.decoders()))
.encoders(Arrays.asList(serverEndpoint.encoders()))
.subprotocols(Arrays.asList(serverEndpoint.subprotocols()))
.extensions(Collections.<Extension>emptyList())
.extensions(Collections.emptyList())
.configurator(configurator)
.build();

EncodingFactory encodingFactory = EncodingFactory.createFactory(classIntrospecter, serverEndpoint.decoders(), serverEndpoint.encoders());
AnnotatedEndpointFactory annotatedEndpointFactory = AnnotatedEndpointFactory.create(endpoint, encodingFactory, template.getParameterNames(), config);
InstanceFactory<?> instanceFactory = null;
try {
instanceFactory = classIntrospecter.createInstanceFactory(endpoint);
} catch (Exception e) {
//so it is possible that this is still valid if a custom configurator is in use
if (configuratorClass == ServerEndpointConfig.Configurator.class) {
throw JsrWebSocketMessages.MESSAGES.couldNotDeploy(e);
} else {
instanceFactory = new InstanceFactory<Object>() {
@Override
public InstanceHandle<Object> createInstance() throws InstantiationException {
throw JsrWebSocketMessages.MESSAGES.endpointDoesNotHaveAppropriateConstructor(endpoint);
}
};
}
}

ConfiguredServerEndpoint confguredServerEndpoint = new ConfiguredServerEndpoint(config, instanceFactory, template, encodingFactory, annotatedEndpointFactory, installedExtensions);
configuredServerEndpoints.add(confguredServerEndpoint);
Expand All @@ -749,7 +749,6 @@ public InstanceHandle<Object> createInstance() throws InstantiationException {
}
}
}
AnnotatedEndpointFactory factory = AnnotatedEndpointFactory.create(endpoint, encodingFactory, Collections.<String>emptySet());

ClientEndpointConfig.Configurator configurator = null;
try {
Expand All @@ -764,6 +763,8 @@ public InstanceHandle<Object> createInstance() throws InstantiationException {
.configurator(configurator)
.build();

AnnotatedEndpointFactory factory = AnnotatedEndpointFactory.create(endpoint, encodingFactory, Collections.emptySet(), config);

ConfiguredClientEndpoint configuredClientEndpoint = new ConfiguredClientEndpoint(config, factory, encodingFactory, instanceFactory);
clientEndpoints.put(endpoint, configuredClientEndpoint);
} else {
Expand Down Expand Up @@ -803,7 +804,7 @@ public void addEndpoint(final ServerEndpointConfig endpoint) throws DeploymentEx
AnnotatedEndpointFactory annotatedEndpointFactory = null;
if (!Endpoint.class.isAssignableFrom(endpoint.getEndpointClass())) {
// We may want to check that the path in @ServerEndpoint matches the specified path, and throw if they are not equivalent
annotatedEndpointFactory = AnnotatedEndpointFactory.create(endpoint.getEndpointClass(), encodingFactory, template.getParameterNames());
annotatedEndpointFactory = AnnotatedEndpointFactory.create(endpoint.getEndpointClass(), encodingFactory, template.getParameterNames(), endpoint);
}
ConfiguredServerEndpoint confguredServerEndpoint = new ConfiguredServerEndpoint(endpoint, null, template, encodingFactory, annotatedEndpointFactory, endpoint.getExtensions());
configuredServerEndpoints.add(confguredServerEndpoint);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ private AnnotatedEndpointFactory(final Class<?> endpointClass, final BoundMethod
}


public static AnnotatedEndpointFactory create(final Class<?> endpointClass, final EncodingFactory encodingFactory, final Set<String> paths) throws DeploymentException {
public static AnnotatedEndpointFactory create(final Class<?> endpointClass, final EncodingFactory encodingFactory, final Set<String> paths, final EndpointConfig endpointConfig) throws DeploymentException {
BoundMethod onOpen = null;
BoundMethod onClose = null;
BoundMethod onError = null;
Expand All @@ -95,7 +95,7 @@ public static AnnotatedEndpointFactory create(final Class<?> endpointClass, fina
}
onOpen = new BoundMethod(method, null, false, 0, new BoundSingleParameter(method, Session.class, true),
new BoundSingleParameter(method, EndpointConfig.class, true),
createBoundPathParameters(method, paths, endpointClass));
createBoundPathParameters(method, paths, endpointClass, encodingFactory, endpointConfig));
}
if (method.isAnnotationPresent(OnClose.class)) {
if (onClose != null) {
Expand All @@ -107,7 +107,7 @@ public static AnnotatedEndpointFactory create(final Class<?> endpointClass, fina
}
onClose = new BoundMethod(method, null, false, 0, new BoundSingleParameter(method, Session.class, true),
new BoundSingleParameter(method, CloseReason.class, true),
createBoundPathParameters(method, paths, endpointClass));
createBoundPathParameters(method, paths, endpointClass, encodingFactory, endpointConfig));
}
if (method.isAnnotationPresent(OnError.class)) {
if (onError != null) {
Expand All @@ -119,7 +119,7 @@ public static AnnotatedEndpointFactory create(final Class<?> endpointClass, fina
}
onError = new BoundMethod(method, null, false, 0, new BoundSingleParameter(method, Session.class, true),
new BoundSingleParameter(method, Throwable.class, false),
createBoundPathParameters(method, paths, endpointClass));
createBoundPathParameters(method, paths, endpointClass, encodingFactory, endpointConfig));
}
if (method.isAnnotationPresent(OnMessage.class) && !method.isBridge()) {
if (binaryMessage != null && binaryMessage.overrides(method)) {
Expand Down Expand Up @@ -150,7 +150,7 @@ public static AnnotatedEndpointFactory create(final Class<?> endpointClass, fina
}
textMessage = new BoundMethod(method, param, true, maxMessageSize, new BoundSingleParameter(method, Session.class, true),
new BoundSingleParameter(i, param),
createBoundPathParameters(method, paths, endpointClass));
createBoundPathParameters(method, paths, endpointClass, encodingFactory, endpointConfig));
messageHandled = true;
break;
} else if (encodingFactory.canDecodeBinary(param)) {
Expand All @@ -159,7 +159,7 @@ public static AnnotatedEndpointFactory create(final Class<?> endpointClass, fina
}
binaryMessage = new BoundMethod(method, param, true, maxMessageSize, new BoundSingleParameter(method, Session.class, true),
new BoundSingleParameter(i, param),
createBoundPathParameters(method, paths, endpointClass));
createBoundPathParameters(method, paths, endpointClass, encodingFactory, endpointConfig));
messageHandled = true;
break;
} else if (param.equals(byte[].class)) {
Expand All @@ -169,7 +169,7 @@ public static AnnotatedEndpointFactory create(final Class<?> endpointClass, fina
binaryMessage = new BoundMethod(method, byte[].class, false, maxMessageSize, new BoundSingleParameter(method, Session.class, true),
new BoundSingleParameter(method, boolean.class, true),
new BoundSingleParameter(i, byte[].class),
createBoundPathParameters(method, paths, endpointClass));
createBoundPathParameters(method, paths, endpointClass, encodingFactory, endpointConfig));
messageHandled = true;
break;
} else if (param.equals(ByteBuffer.class)) {
Expand All @@ -180,7 +180,7 @@ public static AnnotatedEndpointFactory create(final Class<?> endpointClass, fina
maxMessageSize, new BoundSingleParameter(method, Session.class, true),
new BoundSingleParameter(method, boolean.class, true),
new BoundSingleParameter(i, ByteBuffer.class),
createBoundPathParameters(method, paths, endpointClass));
createBoundPathParameters(method, paths, endpointClass, encodingFactory, endpointConfig));
messageHandled = true;
break;

Expand All @@ -191,7 +191,7 @@ maxMessageSize, new BoundSingleParameter(method, Session.class, true),
binaryMessage = new BoundMethod(method, InputStream.class, false,
maxMessageSize, new BoundSingleParameter(method, Session.class, true),
new BoundSingleParameter(i, InputStream.class),
createBoundPathParameters(method, paths, endpointClass));
createBoundPathParameters(method, paths, endpointClass, encodingFactory, endpointConfig));
messageHandled = true;
break;

Expand All @@ -202,7 +202,7 @@ maxMessageSize, new BoundSingleParameter(method, Session.class, true),
textMessage = new BoundMethod(method, String.class, false, maxMessageSize, new BoundSingleParameter(method, Session.class, true),
new BoundSingleParameter(method, boolean.class, true),
new BoundSingleParameter(i, String.class),
createBoundPathParameters(method, paths, endpointClass));
createBoundPathParameters(method, paths, endpointClass, encodingFactory, endpointConfig));
messageHandled = true;
break;

Expand All @@ -213,7 +213,7 @@ maxMessageSize, new BoundSingleParameter(method, Session.class, true),
textMessage = new BoundMethod(method, Reader.class, false,
maxMessageSize, new BoundSingleParameter(method, Session.class, true),
new BoundSingleParameter(i, Reader.class),
createBoundPathParameters(method, paths, endpointClass));
createBoundPathParameters(method, paths, endpointClass, encodingFactory, endpointConfig));
messageHandled = true;
break;

Expand All @@ -223,7 +223,7 @@ maxMessageSize, new BoundSingleParameter(method, Session.class, true),
}
pongMessage = new BoundMethod(method, PongMessage.class, false, maxMessageSize, new BoundSingleParameter(method, Session.class, true),
new BoundSingleParameter(i, PongMessage.class),
createBoundPathParameters(method, paths, endpointClass));
createBoundPathParameters(method, paths, endpointClass, encodingFactory, endpointConfig));
messageHandled = true;
break;
}
Expand All @@ -237,7 +237,7 @@ maxMessageSize, new BoundSingleParameter(method, Session.class, true),
textMessage = new BoundMethod(method, boolClass, true, maxMessageSize, new BoundSingleParameter(method, Session.class, true),
new BoundSingleParameter(method, boolean.class, true),
new BoundSingleParameter(booleanLocation, boolClass),
createBoundPathParameters(method, paths, endpointClass));
createBoundPathParameters(method, paths, endpointClass, encodingFactory, endpointConfig));
messageHandled = true;
}
if (!messageHandled) {
Expand All @@ -250,8 +250,8 @@ maxMessageSize, new BoundSingleParameter(method, Session.class, true),
return new AnnotatedEndpointFactory(endpointClass, onOpen, onClose, onError, textMessage, binaryMessage, pongMessage);
}

private static BoundPathParameters createBoundPathParameters(final Method method, Set<String> paths, Class<?> endpointClass) throws DeploymentException {
return new BoundPathParameters(pathParams(method), method, endpointClass, paths);
private static BoundPathParameters createBoundPathParameters(final Method method, Set<String> paths, Class<?> endpointClass, final EncodingFactory encodingFactory, final EndpointConfig endpointConfig) throws DeploymentException {
return new BoundPathParameters(pathParams(method), method, endpointClass, paths, encodingFactory, endpointConfig);
}


Expand Down Expand Up @@ -365,7 +365,7 @@ private static class BoundPathParameters implements BoundParameter {
private final Encoding[] encoders;
private final Class[] types;

BoundPathParameters(final String[] positions, final Method method, Class<?> endpointClass, Set<String> paths) throws DeploymentException {
BoundPathParameters(final String[] positions, final Method method, Class<?> endpointClass, Set<String> paths, final EncodingFactory encodingFactory, final EndpointConfig endpointConfig) throws DeploymentException {
this.positions = positions;
this.encoders = new Encoding[positions.length];
this.types = new Class[positions.length];
Expand All @@ -383,8 +383,8 @@ private static class BoundPathParameters implements BoundParameter {
if (positions[i] == null || type == null || type == String.class) {
continue;
}
if (EncodingFactory.DEFAULT.canEncodeText(type)) {
encoders[i] = EncodingFactory.DEFAULT.createEncoding(EmptyEndpointConfig.INSTANCE);
if (encodingFactory.canEncodeText(type)) {
encoders[i] = encodingFactory.createEncoding(endpointConfig);
types[i] = type;

} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public static void setup() throws Exception {
.addEndpoint(AnnotatedClientEndpoint.class)
.addEndpoint(AnnotatedClientEndpointWithConfigurator.class)
.addEndpoint(IncrementEndpoint.class)
.addEndpoint(UuidEndpoint.class)
.addEndpoint(EncodingEndpoint.class)
.addEndpoint(EncodingGenericsEndpoint.class)
.addEndpoint(TimeoutEndpoint.class)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2014 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* 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.undertow.websockets.jsr.test.annotated;

import javax.websocket.EndpointConfig;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.UUID;

@ServerEndpoint("/uuid/{id}")
public class UuidEndpoint {

UUID id;

@OnOpen
public void open(Session session, EndpointConfig config, @PathParam("id") UUID id) {
this.id = id;
}

@OnMessage
public String handleMessage(String message) {
return message + id;
}

}

0 comments on commit 7c93d8e

Please sign in to comment.