Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,23 @@

import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.ParamConverter;

import java.util.Optional;

final class JaxrsRestToolKit extends DefaultRestToolKit {

private final BeanArgumentBinder binder;

private final ParamConverterFactory paramConverterFactory;

public JaxrsRestToolKit(FrameworkModel frameworkModel) {
super(frameworkModel);
binder = new BeanArgumentBinder(frameworkModel);
paramConverterFactory = new ParamConverterFactory();
}

@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public Object convert(Object value, ParameterMeta parameter) {
if (MultivaluedMap.class.isAssignableFrom(parameter.getType())) {
Expand All @@ -43,6 +50,19 @@ public Object convert(Object value, ParameterMeta parameter) {
}
return typeConverter.convert(value, MultivaluedHashMap.class);
}

Optional<ParamConverter> optional = paramConverterFactory.getParamConverter(
parameter.getType(), parameter.getGenericType(), parameter.getRealAnnotations());
if (optional.isPresent()) {
ParamConverter paramConverter = optional.get();
Object result = value.getClass() == String.class
? paramConverter.fromString((String) value)
: paramConverter.toString(value);
if (result != null) {
return result;
}
}

return super.convert(value, parameter);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;

import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.Pair;

import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.ServiceLoader;

import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_ERROR_LOAD_EXTENSION;

@SuppressWarnings({"rawtypes"})
public class ParamConverterFactory {

private static final ErrorTypeAwareLogger logger =
LoggerFactory.getErrorTypeAwareLogger(ParamConverterFactory.class);
private final Map<Pair<Pair<Class<?>, Type>, Annotation[]>, Optional<ParamConverter>> cache =
CollectionUtils.newConcurrentHashMap();
private final List<ParamConverterProvider> providers = new ArrayList<>();

ParamConverterFactory() {
ServiceLoader<ParamConverterProvider> serviceLoader = ServiceLoader.load(ParamConverterProvider.class);
Iterator<ParamConverterProvider> iterator = serviceLoader.iterator();
while (iterator.hasNext()) {
try {
ParamConverterProvider paramConverterProvider = iterator.next();
providers.add(paramConverterProvider);
} catch (Throwable e) {
logger.error(COMMON_ERROR_LOAD_EXTENSION, "", "", "Spi Fail to load ParamConverterProvider");
}
}
}

public <T> Optional<ParamConverter> getParamConverter(
Class<T> rawType, Type genericType, Annotation[] annotations) {
Pair<Pair<Class<?>, Type>, Annotation[]> pair = Pair.of(Pair.of(rawType, genericType), annotations);
return cache.computeIfAbsent(pair, k -> {
for (ParamConverterProvider provider : providers) {
ParamConverter converter = provider.getConverter(rawType, genericType, annotations);
if (converter != null) {
return Optional.of(converter);
}
}
return Optional.empty();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.AnotherUserRestServiceImpl;
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.HttpMethodService;
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.HttpMethodServiceImpl;
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.ParamConverterService;
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.ParamConverterServiceImpl;
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.RestDemoForTestException;
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.RestDemoService;
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.RestDemoServiceImpl;
Expand Down Expand Up @@ -562,4 +564,24 @@ private URL registerProvider(URL url, Object impl, Class<?> interfaceClass) {
repository.registerProvider(providerModel);
return url.setServiceModel(providerModel);
}

@Test
void testParamConverter() {
ParamConverterService service = new ParamConverterServiceImpl();
URL exportUrl = URL.valueOf(
"tri://127.0.0.1:" + availablePort + "/rest?interface=" + ParamConverterService.class.getName());

URL nettyUrl = this.registerProvider(exportUrl, service, ParamConverterService.class);

tProtocol.export(proxy.getInvoker(service, ParamConverterService.class, nettyUrl));

ParamConverterService paramConverterService =
this.proxy.getProxy(protocol.refer(ParamConverterService.class, nettyUrl));

User user = paramConverterService.convert(User.getInstance());
User u = new User();
u.setAge(20);
u.setId(1L);
Assertions.assertEquals(u, user);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;

import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.User;

import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

public class ParamConverterProviderImpl implements ParamConverterProvider {

@Override
public <T> ParamConverter<T> getConverter(Class<T> rawType, Type type, Annotation[] annotations) {
if (rawType.isAssignableFrom(User.class)) {
return (ParamConverter<T>) new UserParamConverter();
}
return null;
}

static class UserParamConverter implements ParamConverter<User> {
@Override
public User fromString(String param) {
User user = new User();
user.setId(1L);
user.setAge(20);
return user;
}

@Override
public String toString(User user) {
return "User{" + "id=" + user.getId() + ", name='" + user.getName() + '\'' + ", age=" + user.getAge() + '}';
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;

import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.User;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;

@Path("/ParamConverterService")
public interface ParamConverterService {

@GET()
@Path("/convert")
User convert(@QueryParam("user") User user);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;

import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.User;

public class ParamConverterServiceImpl implements ParamConverterService {
@Override
public User convert(User user) {
return user;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.ParamConverterProviderImpl