How to get path template in JAX-RS ContainerRequestFilter? - jax-rs

From within a JAX-RS ContainerRequestFilter, I'd like to obtain the unresolved path URI of the request; i.e. something like "todos/{id}". Via requestContext.getUriInfo().getPath() I only get the path with parameters resolved, e.g. "todos/1". Is there any way for getting the path with parameters instead?

You may need to just build the template. It's not that difficult. You can get access to the resource class and method (from an injected ResourceInfo) and just use the UriBuilder methods. It has path() methods that accept Class and Method and it will build the Uri for you based on the #Path annotations of those objects. Then just get the template with UriBuilder#toTemplate() For example
public class UriTestingFilter implements ContainerRequestFilter {
#Context
private ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext request) throws IOException {
UriInfo uriInfo = request.getUriInfo();
Class<?> resourceClass = resourceInfo.getResourceClass();
Method resourceMethod = resourceInfo.getResourceMethod();
UriBuilder partialUriBuilder = UriBuilder.fromResource(resourceClass)
.path(resourceMethod);
String partialUri = partialUriBuilder.toTemplate();
URI baseUri = uriInfo.getBaseUri();
UriBuilder fullUriBuilder = UriBuilder.fromUri(baseUri)
.path(resourceClass)
.path(resourceMethod);
String fullUri = fullUriBuilder.toTemplate();
}
}

Using ResourceInfo doesn't really work very well with sub-resources.
It's possible to get it in Jersey from the ContainerRequestContext when using using this:
List<UriTemplate> matchedTemplates = new ArrayList<>(ctx.getMatchedTemplates());
Collections.reverse(matchedTemplates);
String path = matchedTemplates.stream()
.map(UriTemplate::getTemplate)
.filter(s -> !s.equals("/"))
.collect(joining());

Related

how to validate header params using Bean Validation and jax-rs

I have jax-rs resources and each have a same header. what is the best way to validate that the header is present using Bean Validation. I know about #HeaderParam but I don't want to change all my methods in all resources to include the header param.
It's as simple as implementing javax.ws.rs.container.ContainerRequestFilter. For example:
#Provider
public class ContentTypeValidatorFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext reqContext) {
String contentType = getHeader(reqContext, "Content-Type");
// Content-type validation, but you can valid as many headers as you want.
if (Objects.isNull(contentType)) {
throw new InvalidRequestException("Content-Type header is missing");
}
}
private String getHeader(ContainerRequestContext requestContext, String header) {
return requestContext.getHeaders().getFirst(header);
}
}
Later, to handle this exception gracefully just implement ExceptionMapper for this InvalidRequestException.
The above filter will be applied globally. But if you want to exclude some endpoints, then make use of #NameBinding to annotate your custom annotation and apply it only to specific endpoints.

ContainerRequestContext not being injected into business logic

I am using jaxrs 2.0 & am trying to populate an object in the ContainerRequestContext & retrive it in the business logic.
I am populating the object in the ContainerRequestContext like :
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
MyObject myObject = new MyObject();
requestContext.setProperty("myObject", myObject);
}
And I am trying to read it in the business logic like :
#GET
#Path("/custom")
public String data(#Context ContainerRequestContext crc) {
Object pco = crc.getProperty("myObject");
}
I am using this approach from the example shared in : How to inject an object into jersey request context?
However I am getting the ContainerRequestContext crc as null. Can someone tell me what I could be doing wrong ?
I have tested the exact code asked in the question which works as it is with following setup:
spring-boot-starter-parent: 2.3.4.RELEASE
spring-boot-starter: inherited from parent
spring-boot-starter-jersey: inherited from parent
which evaluates to Spring 5.2.9.RELEASE, Jersey 2.30.1
Arquillian with Jersey can work.

how to get server.MapPath in asp.net core from inside a helper

having a helper method like this:
public static IHtmlContent Source(this IHtmlHelper html, string s)
{
var path = ServerMapPath() + "Views\\" + s;
I need to get the equivalent of Server.MapPath in asp.net core
You need to inject IHostingEnvironment. Then:
var path = env.ContentRootPath + "Views\\" + s;
in an html helper you can do this:
((IHostingEnvironment)html.ViewContext.HttpContext.RequestServices.GetService(typeof(IHostingEnvironment))).ContentRootPath;
recommended Solution
I recommend Don't use a static class. You can keep something similar to your class, and register it as a singleton.
public class SourceClass
{
private readonly IWebHostEnvironment _webHostEnvironment;
public SourceClass (IWebHostEnvironment webHostEnvironment)
{
_webHostEnvironment= webHostEnvironment;
}
private IHtmlContent Source(this IHtmlHelper html, string s)
{
string contentRootPath = _webHostEnvironment.ContentRootPath;
Path.Combine(contentRootPath,"Views",s)
}
}
Then, in Startup.ConfigureServices:
services.AddSingleton<SourceClass>();
Finally, inject SourceClass where you need it, instead of just statically referencing the class.
Another Solution
(Note :#regnauld provided this solution, but it had some drawbacks, which I thought would be fully answered)
But if you want to use a static method you can do(Note: In .Net Core 3 IHostingEnvironment is absolute and IWebHostEnvironment must be used instead ):
for ServerPath ,use
((IWebHostEnvironment)html.ViewContext.HttpContext.RequestServices.GetService(typeof(IWebHostEnvironment))).ContentRootPath
OR
for WebRootPath (wwwroot) ,use
((IWebHostEnvironment)html.ViewContext.HttpContext.RequestServices.GetService(typeof(IWebHostEnvironment))).WebRootPath
in this answer you can find more details.
I also recommend that you use this code:
var path = Path.Combine(WebRootPath,"Views",s)
instead of
var path = WebRootPath + "Views\\" + s
to run the code on all operating systems.

How can I get root-context url with JAX-RS?

With given Application
#ApplicationPath("/api")
public class MyApplication {
}
UriInfo#getBaseUri gives me an application path.
#Context
private UriInfo uriInfo
uriInfo.getBaseUri(); // http://address/<context-path>/api
How can I get context-path?
How can I get full URL to context-path?
http://address/<context-path>
UPDATE
I currently using code from this answer.
#Context
private HttpServletRequest servletRequest;
final URI contextUri
= URI.create(servletRequest.getRequestURL().toString())
.resolve(servletRequest.getContextPath());
Any other suggestions?
To get application context, you can inject the ServletContext in your REST method and retrieve contextPath from it, for example like this:
#GET
#Path("/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Catalog find(#PathParam("id") Long id, #Context ServletContext servletContext) {
String contextPath = servletContext.getContextPath();
...
}
EDIT
To get the "full URL to context-path" you want. You could also inject the HttpServletRequest with #Context annotation and use getScheme(), getServerName() and getServerPort() methods to build it.
One possible way is using HttpServletRequest.
#Context
private HttpServletRequest servletRequest;
final URI contextUri
= URI.create(servletRequest.getRequestURL().toString())
.resolve(servletRequest.getContextPath());

How can I get the whole sub path with JAX-RS?

With following URL.
http://doma.in/context/resource/some/.../undefined
I want to get the path name after ../resource which is /some/.../undefined
#Path("/resource")
class Response Resource {
final String path; // "/some/.../undefined"
}
Thanks.
UPDATE
There is, as answered, a way to do this.
#Path("/resource")
class class Resource {
#Path("/{paths: .+}")
public String readPaths() {
final String paths
= uriInfo.getPathParameters().getFirst("paths");
}
#Context
private UriInfo uriInfo;
}
When I invoke
http://.../context/resource/paths/a/b/c
I get
a/b/c
.
You can get all the URI information from UriInfo, which you can inject either as a field or method parameter, using the #Context annotation.
public Response getResponse(#Context UriInfo uriInfo) {
}
-- OR --
#Context
private UriInfo uriInfo;
You can get the absolute request path with UriInfo.getAbsoultePath()
http://doma.in/context/resource/some/somthingelse/undefined
You can get the relative path to the base uri from UriInfo.getPath().
/resource/some/somthingelse/undefined
You can get a list of path segments (each section between slashes is a path segment) with UriInfo.getPathSegments(). Here is an example usage.
There's a bunch of methods you can use for reading the URI. Just look at the API linked above.