Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better support inheritance in Resource Methods #5310

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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());
}
}