Configure Jersey MVC to serve Viewable without web.xml - java

The important part is: without web.xml.
I already have a working JAX-RS app running on Glassfish 3.1.2.2 without a web.xml, configured purely by annotations.
The question is, how can I maintain the web.xml-less nirvana and still use Jersey MVC to serve static resources from the resources or webapp directory of my Maven .war project?
I see in many answers how can I do this with web.xml configuration, but nobody mentions how to map resources without the web.xml file.
Currently I have a ui.html file under the resources directory, a JAX-RS Application subclass and a resource class. No web.xml in the project and the following is working well:
#Path("/ui")
#GET
public Response ui() {
String content = "Hello StackOverflow";
return Response.ok(content).build();
}
While this one is failing with the IOException from the resolver:
#Path("/ui")
#GET
public Response ui() {
Viewable viewable = new Viewable("/ui.html");
return Response.ok(viewable).build();
}
java.io.IOException: The template name, /ui.html, could not be resolved to a fully qualified template name
I also tried to specify it with a relative path, but that didn't work either.
The dependencies I'm using for Jersey are as follows:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.18</version>
</dependency>
I understand that a proper example project would be the best and willing to provide that if people are having a hard time figuring out what I'm talking about, just let me know.

Peter Metz, I believe this is possible by using the #WebFilter annotation on a class that extends org.glassfish.jersey.servlet.ServletContainer (Jersey 2.26):-
package com.myorg.myapp.config;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import org.glassfish.jersey.servlet.ServletContainer;
#WebFilter(value = "/*", initParams = #WebInitParam(name = "javax.ws.rs.Application", value = "com.myorg.myapp.config.JerseyConfig"))
public class JerseyFilter extends ServletContainer {
private static final long serialVersionUID = 1L;
}

Related

Spring Boot 2 index.html not loaded automatically from subdirectory mapped as static resource

I have a Maven module containing my Angular 6 application, and at build it is packaged in a jar at META-INF/resources/admin/ui.
My Spring Boot 2 application has a dependency to the frontend Maven module and when building it includes the frontend library as well. However, if I access http://localhost:8080/admin/ui/ it downloads an empty ui file, but if I access http://localhost:8080/admin/ui/index.html then it displays the Angular application.
If I package the frontend application at META-INF/resources/ then http://localhost:8080/ will display the Angular application correctly, but I want the context of the frontend application to start from /admin/ui. The Spring Boot application does not have any custom mappings, it is just annotated with
#Configuration
#EnableAutoConfiguration
#EnableScheduling
#ComponentScan(basePackageClasses = {...})
#Import({...})
Is there a configuration property that I am missing?
I appreciate the help.
You don't need all those annotations to make it working... I would recommend please remove those which are not added purposely by you..!!
To serve your static page on different path than the main context, here is a work-around..!!
Create another simple controller class like below..
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class Home {
#RequestMapping(path = "/")
public String getHome(){
return "redirect:/admin/ui/";
// make sure no space between colon (:) and endpoint name (/admin/ui)
}
#RequestMapping(path = "/admin/ui/" )
public String getAdminUi(){
return "/index.html";
// your index.html built by angular should be in resources/static folder
// if it is in resources/static/dist/index.html,
// change the return statement to "/dist/index.html"
}
}
And, notice here, I have marked the class as #Controller not the #RestController so if you mark it to #RestController or try to do the same in any existing #RestController you would not achieve it easily. So, it's no harm to create another class like above.
Benefit of this way is, it don't destroy your existing mappings.. also the context path is not changes, so no need to bother about your other endpoint paths. They all shall work as before.
Hope this helped!!

#RolesAllowed etc. without web.xml

I am currently working on a quite modular application where we have many jars that will be packaged and glued together in a war file.
Some of these jar files have REST resources that want to be secured. Common way is the #RolesAllowed annotation etc.
From my current knowledge this implies an existing web.xml in the WAR. This way we would have to implement jar-specific information (e.g. context roots) inside the WAR, not in the place where it belongs.
Like the most things nowadays - is there a way to programmatically set up security contexts etc. without a web.xml?
You can restrict access to your REST resources by registering RolesAllowedDynamicFeature in your REST configuration class that extends from ResourceConfig
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
super(ApplicationConfig.class);
register(RolesAllowedDynamicFeature.class);
}
}
So you can use your application roles on your resources methods like this
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;
#Path("secured")
#PermitAll
public class SecuredResource {
#GET
#Path("user")
#RolesAllowed("user")
public String user(#Context SecurityContext sc) {
boolean test = sc.isUserInRole("user");
return (test) ? "true": "false";
}
#GET
#Path("admin")
#RolesAllowed("admin")
public String admin(#Context SecurityContext sc) {
boolean test = sc.isUserInRole("admin");
return (test) ? "true": "false";
}
}
Jersey documentation has more details on securing REST resources using annotations here
https://jersey.github.io/documentation/latest/security.html#d0e12428
I've not worked with JAX-RS for a while, but the last time I checked, when using annotation-based security, web.xml is not optional.
See my answer for details.
https://stackoverflow.com/a/20023018/839733

what is that I'm missing to run jersey 2 web service?

I created a dynamic java project and added this dependency:
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.containers/jersey-container-servlet-core -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>2.23.1</version>
</dependency>
Then i created the App class like this:
#ApplicationPath("/test")
public class App extends ResourceConfig {
public App() {
this.packages("com.test.ul");
}
}
and in the same package as the App class is in, i created this:
#Path("restaurantAPI")
public class RestaurantAPI {
#Path("/get")
#GET
public Response getRequest(#PathParam("id") String id) {
return Response.ok(id).build();
}
}
I run my server, and I call this URL:
http://localhost:8080/ULTestServer/test/restaurantAPI/get?id=3
but I get error 404
What Am I missing please ? (I always do that and it used to work)
Change
jersey-container-servlet-core
to
jersey-container-servlet
The reason is that the latter has the required component1 that allows for discovering your application without web.xml, in replace for #ApplicationPath. This is part of the servlet 3 pluggability mechanism.
The first dependency is use for non servlet 3.0 containers, where the use would have to use a web.xml to register the Jersey servlet.
1 - Here is the implementation

JAX-RS Resource not found in GlassFish Server

I've been trying to create a simple Restful WebService, using NetBeans Ide.
My Java EE Version is: Java EE 7 Web.
I created a new Java Web Application, setting this ContexPath: /DukesAgeService.
Now, running my application, browser display my Index.html page at:
http://localhost:8080/DukesAgeService/
so, everything works fine.
Then, I tried to create a simple restful resource using the RESTful Web Service Wizard.
So, I created this class:
package firstcup.webservice;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PUT;
/**
* REST Web Service
*
* #author nolanof
*/
#Path("dukesAge")
public class DukesAgeResource {
#Context
private UriInfo context;
/**
* Creates a new instance of DukesAgeResource
*/
public DukesAgeResource() {
}
/**
* Retrieves representation of an instance of firstcup.webservice.DukesAgeResource
* #return an instance of java.lang.String
*/
#GET
#Produces("text/plain")
public String getText() {
return "hello world";
}
}
But running my application, at url:
http://localhost:8080/DukesAgeService/dukesAge
I get a 404-not found page.
I exptected that any incoming get request that has the url of "/dukesAge" was handled by DukesAgeResource class getText method. Whats' wrong?
Thanks
You're probably missing the JAX-RS application servlet. You can either define it in the web.xml or if you want to go xml-less, you can use an Application subclass. The easiest way IMO is just to use the Application subclass annotated with #ApplicationPath. A servlet will be created and the servlet path will be set to the value in the annotation. Something like
#ApplicationPath("/rest")
public class RestApplication extends Application {
// All request scoped resources and providers
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(DukesAgeResource.class);
return classes;
}
// all singleton resources and providers
#Override
public Set<Object> getSingletons() {
Set<Object> singletons = new HashSet<>();
return singletons;
}
}
Then the resource should be accessed via
http://localhost:8080/DukesAgeService/rest/dukesAge.
There are other ways, but this is the portable way. Glassfish uses Jersey, but creating a Java EE web application from scratch in Netbeans will only import compile time Java EE standard classes (no Jersey dependencies). So the above is really your best bet to start off with.
You can see other deployment options at the Jersey Documentation. For some of the options, you may need to add some Jersey compile-time dependencies. That's why I just mentioned the above. No other jars needed.
Another thing that would cause a 404, is if you specify the JAX-RS servlet path as /*. This will conflict with the default servlet that serves the static resources like your html pages. That's why I set it to /rest.
UPDATE
It is also stated in the JAX-RS spec that if there are empty sets returned in the getClasses() and getSingletons(), implicit classpath scanning should occur. (provider) Classes annotated withe #Provider will by default be added as singletons and resource classes annotated with #Path will be per-request objects (meaning a new object is created each request). So you could alternatively just have
#ApplicationPath("/rest")
public class RestApplication extends Application {
// Left empty
}
and it should work just the same.
You may have initialized some path in your web.xml, probably that is why you are getting a 404 error while you call the service. Do check your web.xml and in case it is set to anything rather then * then please append that to your service call to get it working.

how to share a jsf error page between multiple wars

I'm trying to share an error page (error.xhtml) between multiple wars. They are all in a big ear application, and all use a common jar library, where I'd like to put this.
The error page should use web.xml, or better web-fragment.xml, and would be declared as a standard java ee error page.
Actual EAR structure:
EAR
EJB1
EJB2
WAR1 (using CommonWeb.jar)
WAR2 (using CommonWeb.jar)
WAR3 (using CommonWeb.jar)
Just putting the error page under META-INF/resources won't work, as it's not a resource.
I'd like to have as little as possible to configure in each war file.
I'm using Glassfish 3.1, but would like to use Java EE 6 standards as much as possible.
You need to create a custom ResourceResolver which resolves resources from classpath, put it in the common JAR file and then declare it in web-fragment.xml of the JAR (or in web.xml of the WARs).
Kickoff example:
package com.example;
import java.net.URL;
import javax.faces.view.facelets.ResourceResolver;
public class FaceletsResourceResolver extends ResourceResolver {
private ResourceResolver parent;
private String basePath;
public FaceletsResourceResolver(ResourceResolver parent) {
this.parent = parent;
this.basePath = "/META-INF/resources"; // TODO: Make configureable?
}
#Override
public URL resolveUrl(String path) {
URL url = parent.resolveUrl(path); // Resolves from WAR.
if (url == null) {
url = getClass().getResource(basePath + path); // Resolves from JAR.
}
return url;
}
}
with in web-fragment.xml or web.xml
<context-param>
<param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name>
<param-value>com.example.FaceletsResourceResolver</param-value>
</context-param>

Categories

Resources