diff --git a/vraptor-core/src/main/java/br/com/caelum/vraptor/core/DefaultInterceptorHandlerFactory.java b/vraptor-core/src/main/java/br/com/caelum/vraptor/core/DefaultInterceptorHandlerFactory.java index 957df1fda..ea50ef485 100644 --- a/vraptor-core/src/main/java/br/com/caelum/vraptor/core/DefaultInterceptorHandlerFactory.java +++ b/vraptor-core/src/main/java/br/com/caelum/vraptor/core/DefaultInterceptorHandlerFactory.java @@ -28,6 +28,7 @@ import br.com.caelum.vraptor.interceptor.StepInvoker; import br.com.caelum.vraptor.ioc.Container; +import br.com.caelum.vraptor.observer.ExecuteMethodExceptionHandler; import com.google.common.base.Supplier; /** @@ -44,18 +45,20 @@ public class DefaultInterceptorHandlerFactory implements InterceptorHandlerFacto private final InterceptorAcceptsExecutor acceptsExecutor; private final CustomAcceptsExecutor customAcceptsExecutor; private final InterceptorExecutor interceptorExecutor; + private final ExecuteMethodExceptionHandler executeMethodExceptionHandler; /** * @deprecated CDI eyes only */ protected DefaultInterceptorHandlerFactory() { - this(null, null, null, null, null, null); + this(null, null, null, null, null, null, null); } @Inject public DefaultInterceptorHandlerFactory(Container container, StepInvoker stepInvoker, CacheStore, InterceptorHandler> cachedHandlers, InterceptorAcceptsExecutor acceptsExecutor, - CustomAcceptsExecutor customAcceptsExecutor, InterceptorExecutor interceptorExecutor) { + CustomAcceptsExecutor customAcceptsExecutor, InterceptorExecutor interceptorExecutor, + ExecuteMethodExceptionHandler executeMethodExceptionHandler) { this.container = container; this.stepInvoker = stepInvoker; @@ -63,6 +66,7 @@ public DefaultInterceptorHandlerFactory(Container container, StepInvoker stepInv this.acceptsExecutor = acceptsExecutor; this.customAcceptsExecutor = customAcceptsExecutor; this.interceptorExecutor = interceptorExecutor; + this.executeMethodExceptionHandler = executeMethodExceptionHandler; } @Override @@ -74,7 +78,7 @@ public InterceptorHandler get() { return new AspectStyleInterceptorHandler(type, stepInvoker, container, customAcceptsExecutor, acceptsExecutor, interceptorExecutor); } - return new ToInstantiateInterceptorHandler(container, type); + return new ToInstantiateInterceptorHandler(container, type, executeMethodExceptionHandler); } }); } diff --git a/vraptor-core/src/main/java/br/com/caelum/vraptor/core/ToInstantiateInterceptorHandler.java b/vraptor-core/src/main/java/br/com/caelum/vraptor/core/ToInstantiateInterceptorHandler.java index 3eac3dfdd..f90f119bf 100644 --- a/vraptor-core/src/main/java/br/com/caelum/vraptor/core/ToInstantiateInterceptorHandler.java +++ b/vraptor-core/src/main/java/br/com/caelum/vraptor/core/ToInstantiateInterceptorHandler.java @@ -17,15 +17,16 @@ package br.com.caelum.vraptor.core; -import javax.enterprise.inject.Vetoed; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import br.com.caelum.vraptor.InterceptionException; import br.com.caelum.vraptor.controller.ControllerMethod; import br.com.caelum.vraptor.interceptor.Interceptor; import br.com.caelum.vraptor.ioc.Container; +import br.com.caelum.vraptor.observer.ExecuteMethodExceptionHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.enterprise.inject.Vetoed; +import java.util.concurrent.Callable; /** * Instantiates the interceptor on the fly and executes its method. @@ -39,28 +40,43 @@ public class ToInstantiateInterceptorHandler implements InterceptorHandler { private final Container container; private final Class type; + private final ExecuteMethodExceptionHandler executeMethodExceptionHandler; - public ToInstantiateInterceptorHandler(Container container, Class type) { + public ToInstantiateInterceptorHandler(Container container, Class type, ExecuteMethodExceptionHandler executeMethodExceptionHandler) { this.container = container; this.type = type; + this.executeMethodExceptionHandler = executeMethodExceptionHandler; } @Override - public void execute(InterceptorStack stack, ControllerMethod method, Object controllerInstance) + public void execute(final InterceptorStack stack, final ControllerMethod method, final Object controllerInstance) throws InterceptionException { - Interceptor interceptor = (Interceptor) container.instanceFor(type); + final Interceptor interceptor = (Interceptor) container.instanceFor(type); if (interceptor == null) { throw new InterceptionException("Unable to instantiate interceptor for " + type.getName() + ": the container returned null."); } if (interceptor.accepts(method)) { logger.debug("Invoking interceptor {}", interceptor.getClass().getSimpleName()); - interceptor.intercept(stack, method, controllerInstance); + executeSafely(stack, method, controllerInstance, interceptor); } else { stack.next(method, controllerInstance); } } + private void executeSafely(final InterceptorStack stack, final ControllerMethod method, final Object controllerInstance, final Interceptor interceptor) { + Try result = Try.run(new Callable() { + @Override + public Void call() throws Exception { + interceptor.intercept(stack, method, controllerInstance); + return null; + } + }); + if (result.failed()) { + executeMethodExceptionHandler.handle(result.getException()); + } + } + @Override public String toString() { return "ToInstantiateHandler for " + type.getName(); diff --git a/vraptor-core/src/main/java/br/com/caelum/vraptor/core/Try.java b/vraptor-core/src/main/java/br/com/caelum/vraptor/core/Try.java new file mode 100644 index 000000000..1fe8fbc5f --- /dev/null +++ b/vraptor-core/src/main/java/br/com/caelum/vraptor/core/Try.java @@ -0,0 +1,86 @@ +package br.com.caelum.vraptor.core; + +import java.util.concurrent.Callable; + +/** + * A class to wrap code that can possibly throw exceptions. + * + * Use the static method Try#run to instantiate this class, passing down + * the dangerous code and use its methods to retrieve the result or the exception + * of your computation. Example using java 8: + * + * + * Try try = Try.run(() -> someDangerousMethod()); + * if (try.failed()) { + * Exception e = try.getException(); + * handleError(e); + * } + * try.result(); //do something with the result + * + * + * @author Chico Sokol + * @param the type of the result of your computation + */ +public abstract class Try { + public static Try run(Callable callable) { + try { + T call = callable.call(); + return new Success(call); + } catch (Exception e) { + return new Failed(e); + } + } + + public abstract boolean failed(); + + public abstract T result(); + + public abstract Exception getException(); + + public static class Success extends Try { + private final T result; + + private Success(T result) { + this.result = result; + } + + @Override + public boolean failed() { + return false; + } + + @Override + public Object result() { + return result; + } + + @Override + public Exception getException() { + throw new UnsupportedOperationException("A Success doesn't have an exception."); + } + } + + public static class Failed extends Try { + private final Exception e; + + private Failed(Exception e) { + this.e = e; + } + + @Override + public boolean failed() { + return true; + } + + @Override + public Object result() { + throw new UnsupportedOperationException("A Failed doesn't have a result."); + } + + @Override + public Exception getException() { + return e; + } + } + +} \ No newline at end of file diff --git a/vraptor-core/src/main/java/br/com/caelum/vraptor/observer/ExecuteMethod.java b/vraptor-core/src/main/java/br/com/caelum/vraptor/observer/ExecuteMethod.java index d32c3e19e..259c536a4 100644 --- a/vraptor-core/src/main/java/br/com/caelum/vraptor/observer/ExecuteMethod.java +++ b/vraptor-core/src/main/java/br/com/caelum/vraptor/observer/ExecuteMethod.java @@ -17,31 +17,27 @@ package br.com.caelum.vraptor.observer; -import static org.slf4j.LoggerFactory.getLogger; - -import java.lang.reflect.Method; - -import javax.enterprise.context.Dependent; -import javax.enterprise.event.Event; -import javax.enterprise.event.Observes; -import javax.inject.Inject; - -import org.slf4j.Logger; - -import br.com.caelum.vraptor.InterceptionException; import br.com.caelum.vraptor.controller.ControllerMethod; import br.com.caelum.vraptor.core.MethodInfo; import br.com.caelum.vraptor.core.ReflectionProvider; -import br.com.caelum.vraptor.core.ReflectionProviderException; +import br.com.caelum.vraptor.core.Try; import br.com.caelum.vraptor.events.InterceptorsExecuted; import br.com.caelum.vraptor.events.MethodExecuted; import br.com.caelum.vraptor.events.MethodReady; -import br.com.caelum.vraptor.interceptor.ApplicationLogicException; import br.com.caelum.vraptor.validator.Messages; -import br.com.caelum.vraptor.validator.ValidationException; +import org.slf4j.Logger; + +import javax.enterprise.context.Dependent; +import javax.enterprise.event.Event; +import javax.enterprise.event.Observes; +import javax.inject.Inject; +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +import static org.slf4j.LoggerFactory.getLogger; /** - * Interceptor that executes the logic method. + * Observer that executes the logic method. * * @author Guilherme Silveira * @author Rodrigo Turini @@ -58,49 +54,44 @@ public class ExecuteMethod { private final Event methodExecutedEvent; private final Event methodReady; + private final ExecuteMethodExceptionHandler executeMethodExceptionHandler; @Inject - public ExecuteMethod(MethodInfo methodInfo, Messages messages, Event methodExecutedEvent, - Event methodReady, ReflectionProvider reflectionProvider) { + public ExecuteMethod(MethodInfo methodInfo, Messages messages, + Event methodExecutedEvent, Event methodReady, + ExecuteMethodExceptionHandler exceptionHandler, ReflectionProvider reflectionProvider) { this.methodInfo = methodInfo; this.messages = messages; this.methodExecutedEvent = methodExecutedEvent; this.methodReady = methodReady; + this.executeMethodExceptionHandler = exceptionHandler; this.reflectionProvider = reflectionProvider; } - public void execute(@Observes InterceptorsExecuted event) { - try { - ControllerMethod method = event.getControllerMethod(); - methodReady.fire(new MethodReady(method)); - Method reflectionMethod = method .getMethod(); - Object[] parameters = methodInfo.getParametersValues(); - - log.debug("Invoking {}", reflectionMethod); - Object instance = event.getControllerInstance(); - Object result = reflectionProvider.invoke(instance, reflectionMethod, parameters); - - messages.assertAbsenceOfErrors(); - - this.methodInfo.setResult(result); - methodExecutedEvent.fire(new MethodExecuted(method, methodInfo)); - } catch (IllegalArgumentException e) { - throw new InterceptionException(e); - } catch (ReflectionProviderException e) { - throwIfNotValidationException(e, e.getCause()); - } catch (Exception e) { - throwIfNotValidationException(e, e); + public void execute(@Observes final InterceptorsExecuted event) { + Try run = Try.run(new Callable() { + @Override + public Void call() throws Exception { + ControllerMethod method = event.getControllerMethod(); + methodReady.fire(new MethodReady(method)); + Method reflectionMethod = method.getMethod(); + Object[] parameters = methodInfo.getParametersValues(); + + log.debug("Invoking {}", reflectionMethod); + Object instance = event.getControllerInstance(); + Object result = reflectionProvider.invoke(instance, reflectionMethod, parameters); + + messages.assertAbsenceOfErrors(); + + methodInfo.setResult(result); + methodExecutedEvent.fire(new MethodExecuted(method, methodInfo)); + return null; + } + }); + if (run.failed()) { + Exception exception = run.getException(); + executeMethodExceptionHandler.handle(exception); } } - private void throwIfNotValidationException(Throwable original, Throwable alternativeCause) { - Throwable cause = original.getCause(); - - if (original instanceof ValidationException || cause instanceof ValidationException) { - // fine... already parsed - log.trace("swallowing {}", cause); - } else { - throw new ApplicationLogicException(alternativeCause); - } - } } \ No newline at end of file diff --git a/vraptor-core/src/main/java/br/com/caelum/vraptor/observer/ExecuteMethodExceptionHandler.java b/vraptor-core/src/main/java/br/com/caelum/vraptor/observer/ExecuteMethodExceptionHandler.java new file mode 100644 index 000000000..550cfe664 --- /dev/null +++ b/vraptor-core/src/main/java/br/com/caelum/vraptor/observer/ExecuteMethodExceptionHandler.java @@ -0,0 +1,39 @@ +package br.com.caelum.vraptor.observer; + +import br.com.caelum.vraptor.InterceptionException; +import br.com.caelum.vraptor.core.ReflectionProviderException; +import br.com.caelum.vraptor.interceptor.ApplicationLogicException; +import br.com.caelum.vraptor.validator.ValidationException; +import org.slf4j.Logger; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Handles exceptions thrown by a controller method + * + * @author Chico Sokol + */ +public class ExecuteMethodExceptionHandler { + private final static Logger log = getLogger(ExecuteMethodExceptionHandler.class); + + public void handle(Exception exception) { + if (exception instanceof IllegalArgumentException) { + throw new InterceptionException(exception); + } + if (exception instanceof ReflectionProviderException) { + throwIfNotValidationException(exception, exception.getCause()); + } + throwIfNotValidationException(exception, exception); + } + + private void throwIfNotValidationException(Throwable original, Throwable alternativeCause) { + Throwable cause = original.getCause(); + + if (original instanceof ValidationException || cause instanceof ValidationException) { + // fine... already parsed + log.trace("swallowing {}", cause); + } else { + throw new ApplicationLogicException(alternativeCause); + } + } +} diff --git a/vraptor-core/src/test/java/br/com/caelum/vraptor/core/DefaultInterceptorHandlerFactoryTest.java b/vraptor-core/src/test/java/br/com/caelum/vraptor/core/DefaultInterceptorHandlerFactoryTest.java index 56742c550..976e8182d 100644 --- a/vraptor-core/src/test/java/br/com/caelum/vraptor/core/DefaultInterceptorHandlerFactoryTest.java +++ b/vraptor-core/src/test/java/br/com/caelum/vraptor/core/DefaultInterceptorHandlerFactoryTest.java @@ -20,6 +20,7 @@ import static org.hamcrest.Matchers.sameInstance; import static org.junit.Assert.assertThat; +import br.com.caelum.vraptor.observer.ExecuteMethodExceptionHandler; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -55,8 +56,9 @@ public void setUp() throws Exception { MockitoAnnotations.initMocks(this); CacheStore, InterceptorHandler> cachedHandlers = new DefaultCacheStore<>(); + ExecuteMethodExceptionHandler executeMethodExceptionHandler = new ExecuteMethodExceptionHandler(); factory = new DefaultInterceptorHandlerFactory(container, stepInvoker, - cachedHandlers, acceptsExecutor, customAcceptsExecutor, interceptorExecutor); + cachedHandlers, acceptsExecutor, customAcceptsExecutor, interceptorExecutor, executeMethodExceptionHandler); } static interface RegularInterceptor extends Interceptor {} diff --git a/vraptor-core/src/test/java/br/com/caelum/vraptor/core/ToInstantiateInterceptorHandlerTest.java b/vraptor-core/src/test/java/br/com/caelum/vraptor/core/ToInstantiateInterceptorHandlerTest.java index 54d7b4e9c..9198629e9 100644 --- a/vraptor-core/src/test/java/br/com/caelum/vraptor/core/ToInstantiateInterceptorHandlerTest.java +++ b/vraptor-core/src/test/java/br/com/caelum/vraptor/core/ToInstantiateInterceptorHandlerTest.java @@ -16,24 +16,26 @@ */ package br.com.caelum.vraptor.core; -import static org.hamcrest.CoreMatchers.containsString; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.IOException; - +import br.com.caelum.vraptor.InterceptionException; +import br.com.caelum.vraptor.controller.ControllerMethod; +import br.com.caelum.vraptor.interceptor.Interceptor; +import br.com.caelum.vraptor.ioc.Container; +import br.com.caelum.vraptor.observer.ExecuteMethodExceptionHandler; +import br.com.caelum.vraptor.validator.Message; +import br.com.caelum.vraptor.validator.ValidationException; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -import br.com.caelum.vraptor.InterceptionException; -import br.com.caelum.vraptor.controller.ControllerMethod; -import br.com.caelum.vraptor.interceptor.Interceptor; -import br.com.caelum.vraptor.ioc.Container; +import java.io.IOException; +import java.util.ArrayList; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.mockito.Mockito.*; public class ToInstantiateInterceptorHandlerTest { @@ -77,7 +79,7 @@ public void shouldComplainWhenUnableToInstantiateAnInterceptor() throws Intercep when(container.instanceFor(MyWeirdInterceptor.class)).thenReturn(null); ToInstantiateInterceptorHandler handler = new ToInstantiateInterceptorHandler(container, - MyWeirdInterceptor.class); + MyWeirdInterceptor.class, new ExecuteMethodExceptionHandler()); handler.execute(null, null, null); } @@ -88,7 +90,7 @@ public void shouldInvokeInterceptorsMethodIfAbleToInstantiateIt() throws Interce when(container.instanceFor(Interceptor.class)).thenReturn(interceptor); when(interceptor.accepts(method)).thenReturn(true); - ToInstantiateInterceptorHandler handler = new ToInstantiateInterceptorHandler(container, Interceptor.class); + ToInstantiateInterceptorHandler handler = new ToInstantiateInterceptorHandler(container, Interceptor.class, new ExecuteMethodExceptionHandler()); handler.execute(stack, method, instance); verify(interceptor).intercept(stack, method, instance); @@ -99,10 +101,33 @@ public void shouldNotInvokeInterceptorsMethodIfInterceptorDoesntAcceptsResource( when(container.instanceFor(Interceptor.class)).thenReturn(interceptor); when(interceptor.accepts(method)).thenReturn(false); - ToInstantiateInterceptorHandler handler = new ToInstantiateInterceptorHandler(container, Interceptor.class); + ToInstantiateInterceptorHandler handler = new ToInstantiateInterceptorHandler(container, Interceptor.class, new ExecuteMethodExceptionHandler()); handler.execute(stack, method, instance); verify(interceptor, never()).intercept(stack, method, instance); verify(stack).next(method, instance); - } + } + + @Test + public void shouldCatchValidationExceptionOfValidatedInterceptor() { + MyValidatedInterceptor validatedInterceptor = new MyValidatedInterceptor(); + when(container.instanceFor(MyValidatedInterceptor.class)).thenReturn(validatedInterceptor); + ExecuteMethodExceptionHandler exceptionHandler = Mockito.spy(new ExecuteMethodExceptionHandler()); + ToInstantiateInterceptorHandler handler = new ToInstantiateInterceptorHandler(container, MyValidatedInterceptor.class, exceptionHandler); + + handler.execute(stack, method, new Object()); + verify(exceptionHandler).handle(Mockito.any(ValidationException.class)); + } + + private static class MyValidatedInterceptor implements Interceptor { + @Override + public void intercept(InterceptorStack stack, ControllerMethod method, Object controllerInstance) throws InterceptionException { + throw new ValidationException(new ArrayList()); + } + + @Override + public boolean accepts(ControllerMethod method) { + return true; + } + } } diff --git a/vraptor-core/src/test/java/br/com/caelum/vraptor/interceptor/ExceptionHandlerInterceptorTest.java b/vraptor-core/src/test/java/br/com/caelum/vraptor/interceptor/ExecuteMethodExceptionHandlerInterceptorTest.java similarity index 97% rename from vraptor-core/src/test/java/br/com/caelum/vraptor/interceptor/ExceptionHandlerInterceptorTest.java rename to vraptor-core/src/test/java/br/com/caelum/vraptor/interceptor/ExecuteMethodExceptionHandlerInterceptorTest.java index f5ce54492..f14fa2303 100644 --- a/vraptor-core/src/test/java/br/com/caelum/vraptor/interceptor/ExceptionHandlerInterceptorTest.java +++ b/vraptor-core/src/test/java/br/com/caelum/vraptor/interceptor/ExecuteMethodExceptionHandlerInterceptorTest.java @@ -34,7 +34,7 @@ import br.com.caelum.vraptor.core.ExceptionRecorder; import br.com.caelum.vraptor.core.InterceptorStack; -public class ExceptionHandlerInterceptorTest { +public class ExecuteMethodExceptionHandlerInterceptorTest { private Object instance; @Mock private InterceptorStack stack; diff --git a/vraptor-core/src/test/java/br/com/caelum/vraptor/observer/ExecuteMethodTest.java b/vraptor-core/src/test/java/br/com/caelum/vraptor/observer/ExecuteMethodTest.java index e5363c422..deaf8eca4 100644 --- a/vraptor-core/src/test/java/br/com/caelum/vraptor/observer/ExecuteMethodTest.java +++ b/vraptor-core/src/test/java/br/com/caelum/vraptor/observer/ExecuteMethodTest.java @@ -17,26 +17,6 @@ package br.com.caelum.vraptor.observer; -import static br.com.caelum.vraptor.controller.DefaultControllerMethod.instanceFor; -import static br.com.caelum.vraptor.view.Results.nothing; -import static org.hamcrest.Matchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.lang.reflect.Method; -import java.util.Collections; - -import javax.enterprise.event.Event; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - import br.com.caelum.vraptor.InterceptionException; import br.com.caelum.vraptor.controller.ControllerMethod; import br.com.caelum.vraptor.controller.DefaultControllerMethod; @@ -51,6 +31,21 @@ import br.com.caelum.vraptor.validator.Messages; import br.com.caelum.vraptor.validator.ValidationException; import br.com.caelum.vraptor.validator.Validator; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import javax.enterprise.event.Event; +import java.lang.reflect.Method; +import java.util.Collections; + +import static br.com.caelum.vraptor.controller.DefaultControllerMethod.instanceFor; +import static br.com.caelum.vraptor.view.Results.nothing; +import static org.hamcrest.Matchers.any; +import static org.mockito.Mockito.*; public class ExecuteMethodTest { @@ -68,7 +63,8 @@ public class ExecuteMethodTest { @Before public void setup() throws NoSuchMethodException { MockitoAnnotations.initMocks(this); - observer = new ExecuteMethod(methodInfo, messages, methodEvecutedEvent, readyToExecuteMethodEvent, new DefaultReflectionProvider()); + observer = new ExecuteMethod(methodInfo, messages, methodEvecutedEvent, readyToExecuteMethodEvent, + new ExecuteMethodExceptionHandler(), new DefaultReflectionProvider()); } @Test diff --git a/vraptor-site/content/en/docs/components.html b/vraptor-site/content/en/docs/components.html index f2f96d0ba..e0a7b499b 100644 --- a/vraptor-site/content/en/docs/components.html +++ b/vraptor-site/content/en/docs/components.html @@ -478,3 +478,20 @@ ~~~ Thus, when the data of an object are not present in the request, you will receive a `null` parameter instead of an empty instance. + +## Using the Try class + +You can use the class `Try` from the public API of VRaptor to handle exceptions more easily. + +With this class, you can specify the code that might throw exceptions with the `run` method: + +~~~ +Try try = Try.run(() -> aDangerousMethod()); +if (try.failed()) { + Exception e = try.getException(); + handleError(e); +} +handleResult(try.result()); +~~~ + +This class is really useful to compose several computations that can throw exceptions. \ No newline at end of file diff --git a/vraptor-site/content/pt/docs/componentes.html b/vraptor-site/content/pt/docs/componentes.html index e1d275525..c191f3e5b 100644 --- a/vraptor-site/content/pt/docs/componentes.html +++ b/vraptor-site/content/pt/docs/componentes.html @@ -397,3 +397,20 @@ ~~~ Dessa forma, quando os dados de um objeto não estiverem presentes no request, você receberá um parâmetro `null` no lugar de uma instância vazia. + +## Usando a classe Try + +Para facilitar o tratamento de exceções, você pode usar a classe `Try`, da API pública do VRaptor. + +Com essa classe, você pode especificar a código que pode lançar exceptions dentro do método `run`: + +~~~ +Try try = Try.run(() -> umMetodoPerigoso()); +if (try.failed()) { + Exception e = try.getException(); + lidaComErro(e); +} +lidaComResultado(try.result()); +~~~ + +Essa classe é especialmente útil para compor diferentes trechos de código que lançam exceptions. \ No newline at end of file