--- title: Accepting URLs ending with a slash --- # by Tomaz Lavieri, applied to VRaptor 4 For those who had some trouble to determine urls like: ~~~ #!java @Path("product/{product.id}") public void view(Product product) {...} ~~~ when typing a URI **/product/1/** and the link didn't work, here's two simple ways to fix the problem. **Note**: This is not necessarily a problem, because the URL /abc is different of /abc/, so the behavior to give 404 is expected. The first way is put two kind of URLs (with or without slash) in the `@Path` annotation, like that: ~~~ #!java @Path(value = {"product/{product.id}", "product/{product.id}/"}) public void view(Product product) {...} ~~~ Note this change **only** will work to method with `@Path` annotation. The others methods will *not* be affected by this change. The other way is write the class below. Thus, unlike the first, will cause the two URLs (with or without slash) are equivalent. ~~~ #!java import javax.enterprise.context.RequestScoped; import javax.enterprise.event.Event; import javax.enterprise.inject.Specializes; import javax.inject.Inject; import javax.servlet.FilterChain; import br.com.caelum.vraptor.Result; import br.com.caelum.vraptor.events.ControllerNotFound; import br.com.caelum.vraptor.http.MutableRequest; import br.com.caelum.vraptor.http.MutableResponse; import br.com.caelum.vraptor.http.route.ControllerNotFoundException; import br.com.caelum.vraptor.http.route.Router; import br.com.caelum.vraptor.view.Results; @RequestScoped @Specializes public class Error404 extends DefaultControllerNotFoundHandler { private final Router router; private final Result result; /** * @deprecated CDI eyes only */ protected Error404() { this(null, null, null); } @Inject public Error404(Router router, Result result, Event event) { super(event); this.router = router; this.result = result; } @Override public void couldntFind(FilterChain chain, MutableRequest request, MutableResponse response) { try { String uri = request.getRequestedUri(); if (uri.endsWith("/")) { tryMovePermanentlyTo(request, uri.substring(0, uri.length()-1)); } else { tryMovePermanentlyTo(request, uri + "/"); } } catch (ControllerNotFoundException ex) { super.couldntFind(chain, request, response); } } private void tryMovePermanentlyTo(MutableRequest request, String newUri) { router.parse(newUri, HttpMethod.of(request), request); result.use(Results.status()).movedPermanentlyTo(newUri); } } ~~~