Skip to content

Commit

Permalink
[RESTEASY-2866] Make proxy interface check configurable (#2777)
Browse files Browse the repository at this point in the history
* [RESTEASY-2866] Make proxy intf check configurable

Signed-off-by: Andy McCright <j.andrew.mccright@gmail.com>

* [RESTEASY-2866] Enable switch for integration test

Signed-off-by: Andy McCright <j.andrew.mccright@gmail.com>

* Update ResteasyDeploymentImpl.java

Removing contextProxyToImplementAllInterfaces from ResteasyDeploymentImpl.

Co-authored-by: Ron Sigal <rsigal@redhat.com>
  • Loading branch information
andymc12 and ronsigal committed May 13, 2021
1 parent 3da360d commit d81cd23
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package org.jboss.resteasy.core;

import org.jboss.resteasy.plugins.providers.sse.SseImpl;
import org.jboss.resteasy.plugins.server.servlet.ResteasyContextParameters;
import org.jboss.resteasy.resteasy_jaxrs.i18n.Messages;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.LoggableFailure;
import org.jboss.resteasy.spi.ResteasyDeployment;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.ValueInjector;
import org.jboss.resteasy.spi.util.Types;
Expand Down Expand Up @@ -237,25 +239,27 @@ public ClassLoader run() {

protected Class<?>[] computeInterfaces(Object delegate, Class<?> cls)
{
Set<Class<?>> set = new HashSet<>();
set.add(cls);
if (delegate != null)
ResteasyDeployment deployment = ResteasyContext.getContextData(ResteasyDeployment.class);
if (deployment != null
&& Boolean.TRUE.equals(deployment.getProperty(ResteasyContextParameters.RESTEASY_PROXY_IMPLEMENT_ALL_INTERFACES)))
{
Class<?> delegateClass = delegate.getClass();
while (delegateClass != null)
{
for (Class<?> intf : delegateClass.getInterfaces())
{
set.add(intf);
for (Class<?> superIntf : intf.getInterfaces())
{
set.add(superIntf);
Set<Class<?>> set = new HashSet<>();
set.add(cls);
if (delegate != null) {
Class<?> delegateClass = delegate.getClass();
while (delegateClass != null) {
for (Class<?> intf : delegateClass.getInterfaces()) {
set.add(intf);
for (Class<?> superIntf : intf.getInterfaces()) {
set.add(superIntf);
}
}
delegateClass = delegateClass.getSuperclass();
}
delegateClass = delegateClass.getSuperclass();
}
return set.toArray(new Class<?>[]{});
}
return set.toArray(new Class<?>[]{});
return new Class<?>[]{cls};
}

OutputStream wrapServletOutputStream(OutputStream os)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,19 @@ public ResteasyDeployment createDeployment()
{
deployment.setStatisticsEnabled(Boolean.valueOf(statisticsEnabled));
}

String proxiesImplAllInterfaces = getParameter(ResteasyContextParameters.RESTEASY_PROXY_IMPLEMENT_ALL_INTERFACES);
if (proxiesImplAllInterfaces != null)
{
boolean b = parseBooleanParam(ResteasyContextParameters.RESTEASY_PROXY_IMPLEMENT_ALL_INTERFACES,
proxiesImplAllInterfaces);
deployment.setProperty(ResteasyContextParameters.RESTEASY_PROXY_IMPLEMENT_ALL_INTERFACES, b);
}
else
{
deployment.setProperty(ResteasyContextParameters.RESTEASY_PROXY_IMPLEMENT_ALL_INTERFACES, false);
}

return deployment;
}

Expand All @@ -262,7 +275,6 @@ protected boolean parseBooleanParam(String key, String value) {
return false;
} else {
throw new RuntimeException(Messages.MESSAGES.keyCouldNotBeParsed(key));

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public interface ResteasyContextParameters {
String RESTEASY_TRACING_TYPE_ON_DEMAND = "ON_DEMAND";

/**
* Set level o tracing information.
* Set level of tracing information.
* <p>
* The property allows to set application default level o diagnostic information.
* Tracing level can be changed for each request by specifying request HTTP header {@code X-RESTEasy-Tracing-Threshold}.
Expand Down Expand Up @@ -101,4 +101,8 @@ public interface ResteasyContextParameters {
String RESTEASY_FAIL_FAST_ON_MULTIPLE_RESOURCES_MATCHING = "resteasy.fail.fast.on.multiple.resources.matching";
String RESTEASY_MATCH_CACHE_ENABLED = "resteasy.match.cache.enabled";
String RESTEASY_MATCH_CACHE_SIZE = "resteasy.match.cache.size";

// Added for non-quarkus servers - to enable generated proxies to implement all interfaces of delegate object.
String RESTEASY_PROXY_IMPLEMENT_ALL_INTERFACES = "resteasy.proxy.implement.all.interfaces"; // default is false

}
Original file line number Diff line number Diff line change
@@ -1,41 +1,86 @@
package org.jboss.resteasy.core;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;

import org.jboss.resteasy.plugins.server.servlet.ConfigurationBootstrap;
import org.jboss.resteasy.plugins.server.servlet.ListenerBootstrap;
import org.jboss.resteasy.spi.ResteasyDeployment;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.junit.Test;
import org.junit.AfterClass;
import org.junit.BeforeClass;

public class ContextParameterInjectionTest {
private static final String RESTEASY_PROXY_IMPLEMENT_ALL_INTERFACES = "resteasy.proxy.implement.all.interfaces";
private static final Map<String, String> preTestProps = new HashMap<>();

@BeforeClass
public static void enableConfigForImplementingAllInterfaces() {
if (System.getProperties().containsKey(RESTEASY_PROXY_IMPLEMENT_ALL_INTERFACES)) {
String value = System.getProperty(RESTEASY_PROXY_IMPLEMENT_ALL_INTERFACES);
preTestProps.put(RESTEASY_PROXY_IMPLEMENT_ALL_INTERFACES, value);
}
}

@AfterClass
public static void cleanup() {
if (!preTestProps.containsKey(RESTEASY_PROXY_IMPLEMENT_ALL_INTERFACES)) {
System.clearProperty(RESTEASY_PROXY_IMPLEMENT_ALL_INTERFACES);
} else {
preTestProps.forEach(System::setProperty);
}
ResteasyProviderFactory.setInstance(null);
}

@Test
public void testInjectedProxyImplementsAllInterfaces() {
final Class<ContainerRequestFilter> filterClass = ContainerRequestFilter.class;
final ContainerRequestFilter coolInstance = new CoolFilter();
ResteasyProviderFactory mockFactory = mock(ResteasyProviderFactory.class);
when(mockFactory.getContextData(filterClass, filterClass, null, false)).thenReturn(coolInstance);

ResteasyProviderFactory.setInstance(mockFactory);
public void testInjectedProxyImplementsOnlySpecificInterfaceByDefault() {
System.clearProperty(RESTEASY_PROXY_IMPLEMENT_ALL_INTERFACES);
Object proxy = createProxy();
assertTrue("Proxy does not implemented expected JAXRS interface", proxy instanceof ContainerRequestFilter);
assertFalse("Proxy implements non-JAXRS interfaces", proxy instanceof CoolInterface);
}

ContextParameterInjector cpi = new ContextParameterInjector(null, filterClass, filterClass, null, mockFactory);
Object proxy = cpi.createProxy();
@Test
public void testInjectedProxyImplementsAllInterfaces() {
System.setProperty(RESTEASY_PROXY_IMPLEMENT_ALL_INTERFACES, "true");
Object proxy = createProxy();
assertTrue("Proxy does not implemented expected JAXRS interface", proxy instanceof ContainerRequestFilter);
assertTrue("Proxy does not implement all expected interfaces", proxy instanceof CoolInterface);
assertEquals("cool", ((CoolInterface)proxy).coolMethod());
}

private Object createProxy() {
ServletContext mockServletContext = mock(ServletContext.class);
when(mockServletContext.getAttribute(ResteasyDeployment.class.getName())).thenReturn(null);
ConfigurationBootstrap configBootstrap = new ListenerBootstrap(mockServletContext);
ResteasyContext.pushContext(ResteasyDeployment.class, configBootstrap.createDeployment());
try {
final Class<ContainerRequestFilter> filterClass = ContainerRequestFilter.class;
final ContainerRequestFilter coolInstance = new CoolFilter();
ResteasyProviderFactory mockFactory = mock(ResteasyProviderFactory.class);
when(mockFactory.getContextData(filterClass, filterClass, null, false)).thenReturn(coolInstance);

ResteasyProviderFactory.setInstance(mockFactory);

ContextParameterInjector cpi = new ContextParameterInjector(null, filterClass, filterClass, null, mockFactory);
return cpi.createProxy();
} finally {
ResteasyContext.removeContextDataLevel();
}
}

public interface CoolInterface {
String coolMethod();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.jboss.resteasy.test.contextProxyInterfaces;

import java.util.Collections;
import java.util.Map;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.Invocation.Builder;
import javax.ws.rs.core.Response;
Expand Down Expand Up @@ -36,7 +39,8 @@ public static Archive<?> deploy()
{
WebArchive war = TestUtil.prepareArchive(ContextProxyInterfacesTest.class.getSimpleName());
war.addClasses(TestUtil.class, PortProviderUtil.class);
return TestUtil.finishContainerPrepare(war, null, CastableConfigurationResource.class);
Map<String, String> contextParams = Collections.singletonMap("resteasy.proxy.implement.all.interfaces", "true");
return TestUtil.finishContainerPrepare(war, contextParams, CastableConfigurationResource.class);
}

private String generateURL(String path)
Expand Down

0 comments on commit d81cd23

Please sign in to comment.