Skip to content

Commit

Permalink
Better support inheritance in Resource Methods
Browse files Browse the repository at this point in the history
Signed-off-by: jansupol <jan.supol@oracle.com>
  • Loading branch information
jansupol committed May 16, 2023
1 parent f6e849b commit 2445c46
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -23,6 +23,7 @@
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Member;
Expand Down Expand Up @@ -444,7 +445,7 @@ public Object run() {
* @see AccessController#doPrivileged(java.security.PrivilegedAction)
*/
public static PrivilegedAction setAccessibleMethodPA(final Method m) {
if (Modifier.isPublic(m.getModifiers())) {
if (isPublic(m)) {
return NoOpPrivilegedACTION;
}

Expand All @@ -460,6 +461,24 @@ public Object run() {
};
}

/**
* Return {@code true} iff the method is public.
* @param clazz The method in question
* @return {@code true} if mod includes the public modifier; {@code false} otherwise.
*/
public static boolean isPublic(Class<?> clazz) {
return Modifier.isPublic(clazz.getModifiers());
}

/**
* Return {@code true} iff the executable is public.
* @param executable The executable in question
* @return {@code true} if the executable includes the public modifier; {@code false} otherwise.
*/
public static boolean isPublic(Executable executable) {
return Modifier.isPublic(executable.getModifiers());
}

/**
* Get the list of classes that represent the type arguments of a
* {@link ParameterizedType parameterized} input type.
Expand Down Expand Up @@ -879,8 +898,7 @@ public static Collection<Class<? extends Annotation>> getAnnotationTypes(final A
* @return {@code true} if the method is {@code getter}, {@code false} otherwise.
*/
public static boolean isGetter(final Method method) {
if (method.getParameterTypes().length == 0
&& Modifier.isPublic(method.getModifiers())) {
if (method.getParameterTypes().length == 0 && isPublic(method)) {
final String methodName = method.getName();

if (methodName.startsWith("get") && methodName.length() > 3) {
Expand Down Expand Up @@ -921,7 +939,7 @@ public static GenericType genericTypeFor(final Object instance) {
* @return {@code true} if the method is {@code setter}, {@code false} otherwise.
*/
public static boolean isSetter(final Method method) {
return Modifier.isPublic(method.getModifiers())
return isPublic(method)
&& void.class.equals(method.getReturnType())
&& method.getParameterTypes().length == 1
&& method.getName().startsWith("set");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -32,6 +32,7 @@
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;

import org.glassfish.jersey.internal.util.ReflectionHelper;
import org.glassfish.jersey.message.internal.OutboundJaxrsResponse;
import org.glassfish.jersey.message.internal.OutboundMessageContext;
import org.glassfish.jersey.message.internal.TracingLogger;
Expand Down Expand Up @@ -68,12 +69,23 @@ abstract class AbstractJavaResourceMethodDispatcher implements ResourceMethodDis
AbstractJavaResourceMethodDispatcher(final Invocable resourceMethod,
final InvocationHandler methodHandler,
final ConfiguredValidator validator) {
this.method = resourceMethod.getDefinitionMethod();
this.method = getPublic(resourceMethod.getHandlingMethod(), resourceMethod.getDefinitionMethod());
this.methodHandler = methodHandler;
this.resourceMethod = resourceMethod;
this.validator = validator;
}

private Method getPublic(Method handlingMethod, Method definitionMethod) {
if (handlingMethod == definitionMethod) {
return handlingMethod;
}

boolean publicHandling = ReflectionHelper.isPublic(handlingMethod)
&& ReflectionHelper.isPublic(handlingMethod.getDeclaringClass());

return publicHandling ? handlingMethod : definitionMethod;
}

@Override
public final Response dispatch(Object resource, ContainerRequest request) throws ProcessingException {
Response response = null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package org.glassfish.jersey.server.model;

import org.glassfish.jersey.server.ApplicationHandler;
import org.glassfish.jersey.server.ContainerResponse;
import org.glassfish.jersey.server.RequestContextBuilder;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.util.concurrent.ExecutionException;

public class ResourceMethodDispatcherInheritanceTest {
public interface ResourceIfc1 {
@GET
public void get();
}

@Path("/")
static class ResourceClass1 implements ResourceIfc1 {
public void get() {

}
}

interface ResourceIfc2 {
@GET
public void get();
}

@Path("/")
public static class ResourceClass2 implements ResourceIfc2 {
public void get() {

}
}

@Test
public void testInheritedMethodPublicClass() throws ExecutionException, InterruptedException {
ApplicationHandler app = new ApplicationHandler(new ResourceConfig(ResourceClass2.class));
ContainerResponse response;
response = app.apply(RequestContextBuilder.from("/", "GET").accept("text/plain").build()).get();
Assertions.assertEquals(204, response.getStatus());
}

@Test
public void testInheritedMethodPublicIface() throws ExecutionException, InterruptedException {
ApplicationHandler app = new ApplicationHandler(new ResourceConfig(ResourceClass1.class));
ContainerResponse response;
response = app.apply(RequestContextBuilder.from("/", "GET").accept("text/plain").build()).get();
Assertions.assertEquals(204, response.getStatus());
}
}

0 comments on commit 2445c46

Please sign in to comment.