Skip to content

Commit

Permalink
Make both javax.jws.WebParam and jakarta.jws.WebParam work at the sam…
Browse files Browse the repository at this point in the history
…e time

Previous class loading solution assumed that there is only one @WebParam class.
Both of these annotation classes may be used in some applications.

This current change tries to load both classes if these are available from classpath.
Then both classes are used in detection of method parameters.


Signed-off-by: cyb3r4nt <[email protected]>
  • Loading branch information
cyb3r4nt committed Jun 13, 2023
1 parent 4b32e36 commit b0c7605
Showing 1 changed file with 34 additions and 29 deletions.
63 changes: 34 additions & 29 deletions src/main/java/com/googlecode/jsonrpc4j/JsonRpcBasicServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,11 @@ public class JsonRpcBasicServer {
public static final String EXCEPTION_TYPE_NAME = "exceptionTypeName";
public static final String VERSION = "2.0";
public static final int CODE_OK = 0;
public static final String WEB_PARAM_ANNOTATION_CLASS_LOADER = "javax.jws.WebParam";
public static final String WEB_PARAM_ANNOTATION_CLASS_LOADER_JAKARTA = "jakarta.jws.WebParam";
public static final String NAME = "name";
public static final String NULL = "null";
private static final Logger logger = LoggerFactory.getLogger(JsonRpcBasicServer.class);
private static final ErrorResolver DEFAULT_ERROR_RESOLVER = new MultipleErrorResolver(AnnotationsErrorResolver.INSTANCE, DefaultErrorResolver.INSTANCE);
private static final Pattern BASE64_PATTERN = Pattern.compile("[A-Za-z0-9_=-]+");
private static Class<? extends Annotation> WEB_PARAM_ANNOTATION_CLASS;
private static Method WEB_PARAM_NAME_METHOD;

static {
loadAnnotationSupportEngine();
}

private final ObjectMapper mapper;
private final Class<?> remoteInterface;
Expand All @@ -79,6 +71,7 @@ public class JsonRpcBasicServer {
private List<JsonRpcInterceptor> interceptorList = new ArrayList<>();
private ExecutorService batchExecutorService = null;
private long parallelBatchProcessingTimeout = Long.MAX_VALUE;
private final Set<Class<? extends Annotation>> webParamAnnotationClasses;

/**
* Creates the server with the given {@link ObjectMapper} delegating
Expand All @@ -104,6 +97,7 @@ public JsonRpcBasicServer(final ObjectMapper mapper, final Object handler, final
this.mapper = mapper;
this.handler = handler;
this.remoteInterface = remoteInterface;
this.webParamAnnotationClasses = loadWebParamAnnotationClasses();
if (handler != null) {
logger.debug("created server for interface {} with handler {}", remoteInterface, handler.getClass());
}
Expand Down Expand Up @@ -131,24 +125,31 @@ public JsonRpcBasicServer(final Object handler) {
this(new ObjectMapper(), handler, null);
}

private static void loadAnnotationSupportEngine() {
private Set<Class<? extends Annotation>> loadWebParamAnnotationClasses() {
final ClassLoader classLoader = JsonRpcBasicServer.class.getClassLoader();
try {
// javax.jws.WebParam class is part of JDK in Java 1.8, and it is always present.
// If Jakarta variant is present in classpath, then needs to be loaded first,
// otherwise it will be overridden with javax.jws.WebParam from JDK 1.8
WEB_PARAM_ANNOTATION_CLASS = classLoader.loadClass(WEB_PARAM_ANNOTATION_CLASS_LOADER_JAKARTA).asSubclass(Annotation.class);
WEB_PARAM_NAME_METHOD = WEB_PARAM_ANNOTATION_CLASS.getMethod(NAME);
} catch (ClassNotFoundException | NoSuchMethodException e) {
logger.debug("Could not find {}.{}", WEB_PARAM_ANNOTATION_CLASS_LOADER_JAKARTA, NAME);
logger.debug("Try to load it from javax package");
try {
WEB_PARAM_ANNOTATION_CLASS = classLoader.loadClass(WEB_PARAM_ANNOTATION_CLASS_LOADER).asSubclass(Annotation.class);
WEB_PARAM_NAME_METHOD = WEB_PARAM_ANNOTATION_CLASS.getMethod(NAME);
} catch (ClassNotFoundException | NoSuchMethodException ex) {
logger.debug("Could not find {}.{}", WEB_PARAM_ANNOTATION_CLASS_LOADER, NAME);
}
Set<Class<? extends Annotation>> webParamClasses = new HashSet<>(2);
for (String className: Arrays.asList("javax.jws.WebParam", "jakarta.jws.WebParam")) {
try {
Class<? extends Annotation> clazz =
classLoader
.loadClass(className)
.asSubclass(Annotation.class);
// check that method with name "name" is present
clazz.getMethod(NAME);
webParamClasses.add(clazz);
} catch (ClassNotFoundException | NoSuchMethodException e) {
logger.debug("Could not find {}.{}", className, NAME);
}
}

if (webParamClasses.isEmpty()) {
logger.debug(
"Could not find any @WebParam classes in classpath." +
" @WebParam support is disabled"
);
}

return Collections.unmodifiableSet(webParamClasses);
}

/**
Expand Down Expand Up @@ -1299,11 +1300,14 @@ private List<JsonRpcParam> getAnnotatedParameterNames(Method method) {
return parameterNames;
}

private List<? extends List<? extends Annotation>> getWebParameterAnnotations(Method method) {
if (WEB_PARAM_ANNOTATION_CLASS == null) {
return new ArrayList<>();
private List<List<? extends Annotation>> getWebParameterAnnotations(Method method) {
List<List<? extends Annotation>> annotations = new ArrayList<>();
for (Class<? extends Annotation> clazz : JsonRpcBasicServer.this.webParamAnnotationClasses) {
annotations.addAll(
ReflectionUtil.getParameterAnnotations(method, clazz)
);
}
return ReflectionUtil.getParameterAnnotations(method, WEB_PARAM_ANNOTATION_CLASS);
return annotations;
}

private JsonRpcParam createNewJsonRcpParamType(final Annotation annotation) {
Expand All @@ -1314,7 +1318,8 @@ public Class<? extends Annotation> annotationType() {

public String value() {
try {
return (String) WEB_PARAM_NAME_METHOD.invoke(annotation);
Method method = annotation.getClass().getMethod(NAME);
return (String) method.invoke(annotation);
} catch (Exception e) {
throw new RuntimeException(e);
}
Expand Down

0 comments on commit b0c7605

Please sign in to comment.