Revision: 9afcdd8a24ee
Author: Sam Berlin <[email protected]>
Date: Mon Oct 31 13:34:04 2011
Log: Prune all the billions of
c.g.i.servlet.Filter{ChainInvocation,Definition}.doFilter elements from the
stack traces.
Revision created by MOE tool push_codebase.
MOE_MIGRATION=3587
http://code.google.com/p/google-guice/source/detail?r=9afcdd8a24ee
Added:
/extensions/servlet/test/com/google/inject/servlet/ServletTestUtils.java
Modified:
/extensions/servlet/src/com/google/inject/servlet/FilterChainInvocation.java
/extensions/servlet/test/com/google/inject/servlet/FilterDispatchIntegrationTest.java
/extensions/servlet/test/com/google/inject/servlet/ServletTest.java
=======================================
--- /dev/null
+++
/extensions/servlet/test/com/google/inject/servlet/ServletTestUtils.java
Mon Oct 31 13:34:04 2011
@@ -0,0 +1,110 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package com.google.inject.servlet;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+/**
+ * Utilities for servlet tests.
+ *
+ * @author [email protected] (Sam Berlin)
+ */
+public class ServletTestUtils {
+
+ private ServletTestUtils() {}
+
+ private static class ThrowingInvocationHandler implements
InvocationHandler {
+ @Override public Object invoke(Object proxy, Method method, Object[]
args) throws Throwable {
+ throw new UnsupportedOperationException("No methods are supported on
this object");
+ }
+ }
+
+ /**
+ * Returns a fake, HttpServletRequest which stores attributes in a
HashMap.
+ */
+ public static HttpServletRequest newFakeHttpServletRequest() {
+ HttpServletRequest delegate = (HttpServletRequest)
Proxy.newProxyInstance(
+ HttpServletRequest.class.getClassLoader(),
+ new Class[] { HttpServletRequest.class }, new
ThrowingInvocationHandler());
+
+ return new HttpServletRequestWrapper(delegate) {
+ final Map<String, Object> attributes = Maps.newHashMap();
+ final HttpSession session = newFakeHttpSession();
+
+ @Override public String getMethod() {
+ return "GET";
+ }
+
+ @Override public Object getAttribute(String name) {
+ return attributes.get(name);
+ }
+
+ @Override public void setAttribute(String name, Object value) {
+ attributes.put(name, value);
+ }
+
+ @Override public Map getParameterMap() {
+ return ImmutableMap.of();
+ }
+
+ @Override public String getRequestURI() {
+ return "/";
+ }
+
+ @Override public String getContextPath() {
+ return "";
+ }
+
+ @Override public HttpSession getSession() {
+ return session;
+ }
+ };
+ }
+
+ /**
+ * Returns a fake, HttpServletResponse which throws an exception if any
of its
+ * methods are called.
+ */
+ public static HttpServletResponse newFakeHttpServletResponse() {
+ return (HttpServletResponse) Proxy.newProxyInstance(
+ HttpServletResponse.class.getClassLoader(),
+ new Class[] { HttpServletResponse.class }, new
ThrowingInvocationHandler());
+ }
+
+ private static class FakeHttpSessionHandler implements
InvocationHandler, Serializable {
+ final Map<String, Object> attributes = Maps.newHashMap();
+
+ public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
+ String name = method.getName();
+ if ("setAttribute".equals(name)) {
+ attributes.put((String) args[0], args[1]);
+ return null;
+ } else if ("getAttribute".equals(name)) {
+ return attributes.get(args[0]);
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+
+ /**
+ * Returns a fake, serializable HttpSession which stores attributes in a
HashMap.
+ */
+ public static HttpSession newFakeHttpSession() {
+ return (HttpSession)
Proxy.newProxyInstance(HttpSession.class.getClassLoader(),
+ new Class[] { HttpSession.class }, new FakeHttpSessionHandler());
+ }
+
+}
=======================================
---
/extensions/servlet/src/com/google/inject/servlet/FilterChainInvocation.java
Tue Sep 27 08:36:19 2011
+++
/extensions/servlet/src/com/google/inject/servlet/FilterChainInvocation.java
Mon Oct 31 13:34:04 2011
@@ -15,7 +15,14 @@
*/
package com.google.inject.servlet;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
import java.io.IOException;
+import java.util.List;
+import java.util.Set;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
@@ -37,12 +44,19 @@
* @since 1.0
*/
class FilterChainInvocation implements FilterChain {
+
+ private static final Set<String> SERVLET_INTERNAL_METHODS =
ImmutableSet.of(
+ FilterDefinition.class.getName() + ".doFilter",
+ FilterChainInvocation.class.getName() + ".doFilter");
+
private final FilterDefinition[] filterDefinitions;
private final FilterChain proceedingChain;
private final ManagedServletPipeline servletPipeline;
//state variable tracks current link in filterchain
private int index = -1;
+ // whether or not we've caught an exception & cleaned up stack traces
+ private boolean cleanedStacks = false;
public FilterChainInvocation(FilterDefinition[] filterDefinitions,
ManagedServletPipeline servletPipeline, FilterChain proceedingChain)
{
@@ -75,8 +89,37 @@
proceedingChain.doFilter(servletRequest, servletResponse);
}
}
+ } catch (Throwable t) {
+ // Only clean on the first pass through -- one exception deep in a
filter
+ // will propogate upward & hit this catch clause multiple times. We
don't
+ // want to iterate through the stack elements for every filter.
+ if (!cleanedStacks) {
+ cleanedStacks = true;
+ pruneStacktrace(t);
+ }
+ Throwables.propagateIfInstanceOf(t, ServletException.class);
+ Throwables.propagateIfInstanceOf(t, IOException.class);
+ throw Throwables.propagate(t);
} finally {
GuiceFilter.localContext.set(previous);
}
}
-}
+
+ /**
+ * Removes stacktrace elements related to AOP internal mechanics from the
+ * throwable's stack trace and any causes it may have.
+ */
+ private void pruneStacktrace(Throwable throwable) {
+ for (Throwable t = throwable; t != null; t = t.getCause()) {
+ StackTraceElement[] stackTrace = t.getStackTrace();
+ List<StackTraceElement> pruned = Lists.newArrayList();
+ for (StackTraceElement element : stackTrace) {
+ String name = element.getClassName() + "." +
element.getMethodName();
+ if (!SERVLET_INTERNAL_METHODS.contains(name)) {
+ pruned.add(element);
+ }
+ }
+ t.setStackTrace(pruned.toArray(new
StackTraceElement[pruned.size()]));
+ }
+ }
+}
=======================================
---
/extensions/servlet/test/com/google/inject/servlet/FilterDispatchIntegrationTest.java
Thu Jul 7 17:34:16 2011
+++
/extensions/servlet/test/com/google/inject/servlet/FilterDispatchIntegrationTest.java
Mon Oct 31 13:34:04 2011
@@ -1,6 +1,7 @@
package com.google.inject.servlet;
import static
com.google.inject.servlet.ManagedServletPipeline.REQUEST_DISPATCHER_REQUEST;
+import static
com.google.inject.servlet.ServletTestUtils.newFakeHttpServletRequest;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
@@ -21,6 +22,8 @@
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@@ -234,4 +237,87 @@
service((HttpServletRequest) servletRequest, (HttpServletResponse)
servletResponse);
}
}
-}
+
+ public final void testFilterExceptionPrunesStack() throws Exception {
+ Injector injector = Guice.createInjector(new ServletModule() {
+ @Override
+ protected void configureServlets() {
+ filter("/").through(TestFilter.class);
+ filter("/nothing").through(TestFilter.class);
+ filter("/").through(ThrowingFilter.class);
+ }
+ });
+
+ HttpServletRequest request = newFakeHttpServletRequest();
+ FilterPipeline pipeline = injector.getInstance(FilterPipeline.class);
+ pipeline.initPipeline(null);
+ try {
+ pipeline.dispatch(request, null, null);
+ fail("expected exception");
+ } catch(ServletException ex) {
+ for (StackTraceElement element : ex.getStackTrace()) {
+ String className = element.getClassName();
+ assertTrue("was: " + element,
+ !className.equals(FilterChainInvocation.class.getName())
+ && !className.equals(FilterDefinition.class.getName()));
+ }
+ }
+ }
+
+ public final void testServletExceptionPrunesStack() throws Exception {
+ Injector injector = Guice.createInjector(new ServletModule() {
+ @Override
+ protected void configureServlets() {
+ filter("/").through(TestFilter.class);
+ filter("/nothing").through(TestFilter.class);
+ serve("/").with(ThrowingServlet.class);
+ }
+ });
+
+ HttpServletRequest request = newFakeHttpServletRequest();
+ FilterPipeline pipeline = injector.getInstance(FilterPipeline.class);
+ pipeline.initPipeline(null);
+ try {
+ pipeline.dispatch(request, null, null);
+ fail("expected exception");
+ } catch(ServletException ex) {
+ for (StackTraceElement element : ex.getStackTrace()) {
+ String className = element.getClassName();
+ assertTrue("was: " + element,
+ !className.equals(FilterChainInvocation.class.getName())
+ && !className.equals(FilterDefinition.class.getName()));
+ }
+ }
+ }
+
+ @Singleton
+ private static class ThrowingServlet extends HttpServlet {
+
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse
resp)
+ throws ServletException, IOException {
+ throw new ServletException("failure!");
+ }
+
+ }
+
+
+ @Singleton
+ private static class ThrowingFilter implements Filter {
+ @Override
+ public void destroy() {
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
+ throws ServletException {
+ throw new ServletException("we failed!");
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) {
+
+ }
+
+ }
+}
=======================================
--- /extensions/servlet/test/com/google/inject/servlet/ServletTest.java Sun
Oct 16 15:35:11 2011
+++ /extensions/servlet/test/com/google/inject/servlet/ServletTest.java Mon
Oct 31 13:34:04 2011
@@ -17,7 +17,8 @@
package com.google.inject.servlet;
import static com.google.inject.Asserts.reserialize;
-import static com.google.inject.servlet.ServletScopes.NullObject;
+import static
com.google.inject.servlet.ServletTestUtils.newFakeHttpServletRequest;
+import static
com.google.inject.servlet.ServletTestUtils.newFakeHttpServletResponse;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
@@ -25,7 +26,6 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
import com.google.inject.AbstractModule;
import com.google.inject.BindingAnnotation;
import com.google.inject.CreationException;
@@ -35,6 +35,7 @@
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
+import com.google.inject.servlet.ServletScopes.NullObject;
import com.google.inject.util.Providers;
import junit.framework.TestCase;
@@ -43,9 +44,6 @@
import java.io.Serializable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
import java.util.Map;
import javax.servlet.Filter;
@@ -411,88 +409,6 @@
assertSame(chainException, e);
}
}
-
- private static class ThrowingInvocationHandler implements
InvocationHandler {
- @Override public Object invoke(Object proxy, Method method, Object[]
args) throws Throwable {
- throw new UnsupportedOperationException("No methods are supported on
this object");
- }
- }
-
- /**
- * Returns a fake, HttpServletRequest which stores attributes in a
HashMap.
- */
- private HttpServletRequest newFakeHttpServletRequest() {
- HttpServletRequest delegate = (HttpServletRequest)
Proxy.newProxyInstance(
- HttpServletRequest.class.getClassLoader(),
- new Class[] { HttpServletRequest.class }, new
ThrowingInvocationHandler());
-
- return new HttpServletRequestWrapper(delegate) {
- final Map<String, Object> attributes = Maps.newHashMap();
- final HttpSession session = newFakeHttpSession();
-
- @Override public String getMethod() {
- return "GET";
- }
-
- @Override public Object getAttribute(String name) {
- return attributes.get(name);
- }
-
- @Override public void setAttribute(String name, Object value) {
- attributes.put(name, value);
- }
-
- @Override public Map getParameterMap() {
- return ImmutableMap.of();
- }
-
- @Override public String getRequestURI() {
- return "/";
- }
-
- @Override public String getContextPath() {
- return "";
- }
-
- @Override public HttpSession getSession() {
- return session;
- }
- };
- }
-
- /**
- * Returns a fake, HttpServletResponse which throws an exception if any
of its
- * methods are called.
- */
- private HttpServletResponse newFakeHttpServletResponse() {
- return (HttpServletResponse) Proxy.newProxyInstance(
- HttpServletResponse.class.getClassLoader(),
- new Class[] { HttpServletResponse.class }, new
ThrowingInvocationHandler());
- }
-
- private static class FakeHttpSessionHandler implements
InvocationHandler, Serializable {
- final Map<String, Object> attributes = Maps.newHashMap();
-
- public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
- String name = method.getName();
- if ("setAttribute".equals(name)) {
- attributes.put((String) args[0], args[1]);
- return null;
- } else if ("getAttribute".equals(name)) {
- return attributes.get(args[0]);
- } else {
- throw new UnsupportedOperationException();
- }
- }
- }
-
- /**
- * Returns a fake, serializable HttpSession which stores attributes in a
HashMap.
- */
- private HttpSession newFakeHttpSession() {
- return (HttpSession)
Proxy.newProxyInstance(HttpSession.class.getClassLoader(),
- new Class[] { HttpSession.class }, new FakeHttpSessionHandler());
- }
private Injector createInjector(Module... modules) throws
CreationException {
return Guice.createInjector(Lists.<Module>asList(new AbstractModule() {
--
You received this message because you are subscribed to the Google Groups
"google-guice-dev" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-guice-dev?hl=en.