vaadin shows wrong class - java

I am trying Vaadin. I developed two classes. In both classes, I extended its servlet with the code similar to below:
#VaadinServletConfiguration(productionMode = false, ui = <CurrentClassName>.class)
public static class Servlet extends VaadinServlet {
}
When I run the second class, it always show UI from first one. I tried restarting Tomcat but its still the same.
e.g.
http://localhost:8080/hms/servlet/com.test.ui.TestClass2$Servlet
I tried creating a new class and when I run that, even that shows the UI of first one.
Please help to understand and resolve the issue.
Thank you!

Create class MyUIProvider that extends basic UIProvider and override getUIClass method.
For instance:
public class MyUIProvider extends UIProvider
{
#Override
public Class extends UI> getUIClass(UIClassSelectionEvent event)
{
// imlement UI class choosing logic here
return MyUI.class;
}
Than add init-param to your VaadinServlet in web.xml:
...
<servlet>
<servlet-name>VAADIN</servlet-name>
<servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
<init-param>
<param-name>UIProvider</param-name>
<param-value>your.package.MyUIProvider</param-value>
<description>Your custom UIProvider</description>
</init-param>
</servlet>
...

Related

#Context not injecting ServletContext in RESTEasy JAX-RS application

I am deploying a JAX-RS application to JBoss EAP 6.2.
I am trying to obtain a ServletContext from inside of a JAX-RS resource class so that I can read some context-param values that I have set in the WEB-INF/web.xml file.
I.e., after I've gotten hold of the ServletContext I was planning to call ServletContext#getInitParam to get the value.
I am using injection to get the ServletContext as advised here.
The relevant portion of my web.xml is:
<servlet>
<servlet-name>resteasy-servlet</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>foo.MyApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/jax-rs/*</url-pattern>
</servlet-mapping>
So I am using RESTEasy which is bundled with JBoss.
Class MyApplication is:
public class MyApplication extends Application {
private Set<Object> singletons = new HashSet<>();
public MyApplication() {
singletons.add( new MyResource() );
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
… and finally in class MyResource I have the following:
#Path(...)
public class MyResource {
#Context
ServletContext context;
public MyResource() {
// I understand context is supposed to be null here
}
// ... but it should have been injected by the time we reach the service method.
#Path("/somePath")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response someMethod( ) {
if (context==null) throw new RuntimeException();
...
}
}
The above code always results in the RuntimeException being thrown. I.e. RESTEasy somehow fails to inject the ServletContext. Note that I don't have any other JAX-RS problems. I.e. if I hardcode the context-param values I was hoping to be able to retrieve via `ServletContext#getInitParameter", then the JAX-RS rest functionality works as expected when the WAR is deployed to JBoss.
Experimenting further I discovered that the ServletContextis only injected if I perform the injection at an argument of the service method like this:
#Path("/somePath")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response someMethod(#Context ServletContext servletContext) {
...
}
… however I would prefer not to change the API. Moreover, I would like to perform some costly initialization based on the context-param value once and for all, not on every service method invocation.
My questions are:
why is the injection failing?
I am a little tired of the annotations magic failing at runtime, is there a way to get the ServletContext without using annotations?
Alternatively, is it possible for my MyApplication class to obtain the ServletContext and pass it to the MyResource class as a constructor parameter?
If all else fails I guess I can always read and parse the web.xml file myself using Class#getResourceAsStream ?
Based on the comment by FrAn that links to this answer, this is what I ended up doing:
public class JaxRsApplication extends Application {
private Set<Object> singletons = new HashSet<>();
public JaxRsApplication(#Context ServletContext servletContext) {
Assert.assertNotNull(servletContext);
singletons.add( new UserDatabaseResource(servletContext) );
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
… and then, in the UserDatabaseResource class I have the following:
public UserDatabaseResource(ServletContext servletContext) {
Assert.assertNotNull(servletContext);
...
String jndiNameForDatasource = servletContext.getInitParameter("whatever")) ;
...
}
This works as the UserDatabaseResource class which is my DAL layer is a singleton and I just needed to get the JNDI name of the datasource to use (from the web.xml file). But maybe this approach also works with some minor adjustments for non-singleton classes as well.

Descriptor-less Jersey servlet container run as filter in Servlet 3.x container

Is there a way to run the Jersey servlet container (2.x) descriptor-less as a javax.servlet.Filter in a Servlet 3.x container? I need to serve static resources alongside my services and therefore need to use jersey.config.servlet.filter.forwardOn404 or jersey.config.servlet.filter.staticContentRegex which only work when run as a filter according to Javadoc
The property is only applicable when Jersey servlet container is configured to run as a javax.servlet.Filter, otherwise this property will be ignored.
I'd like to get rid of the web.xml completely
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>My-Webservice</display-name>
<filter>
<filter-name>Jersey Filter</filter-name>
<filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.foo.webservices.MyApplication</param-value>
</init-param>
</filter>
</web-app>
and have everything in my custom Applicationclass
#ApplicationPath(value = "/")
public class MyApplication extends ResourceConfig
{
public MyApplication()
{
packages("com.foo.webservices.services");
property(ServletProperties.FILTER_FORWARD_ON_404, true);
}
}
The official documentation (https://jersey.java.net/documentation/latest/deployment.html#deployment.servlet.3) doesn't state anything about filters unfortunately.
It's possible, but not gonna be as easy as just setting some config property. It would help if you understand a little about how it actually works. With Servlet 3.x, introduced a ServletContainerInitializer that we can implement to load servlets dynamically (this is discussed further here). Jersey has an implementation that it uses. But it follows the JAX-RS which says that the application should be loaded as a servlet. So Jersey doesn't doesn't offer any way around this.
We could write our own ServletContainerInitializer or we can just tap into Jersey's. Jersey has a SerletContainerProvider we can implement. We would need to register the servlet filter ourselves. The implementation would look something like this
#Override
public void preInit(ServletContext context, Set<Class<?>> classes) throws ServletException {
final Class<? extends Application> applicationCls = getApplicationClass(classes);
if (applicationCls != null) {
final ApplicationPath appPath = applicationCls.getAnnotation(ApplicationPath.class);
if (appPath == null) {
LOGGER.warning("Application class is not annotated with ApplicationPath");
return;
}
final String mapping = createMappingPath(appPath);
addFilter(context, applicationCls, classes, mapping);
// to stop Jersey servlet initializer from trying to register another servlet
classes.remove(applicationCls);
}
}
private static void addFilter(ServletContext context, Class<? extends Application> cls,
Set<Class<?>> classes, String mapping) {
final ResourceConfig resourceConfig = ResourceConfig.forApplicationClass(cls, classes);
final ServletContainer filter = new ServletContainer(resourceConfig);
final FilterRegistration.Dynamic registration = context.addFilter(cls.getName(), filter);
registration.addMappingForUrlPatterns(null, true, mapping);
registration.setAsyncSupported(true);
}
Once we have our implementation, we need to create a file
META-INF/services/org.glassfish.jersey.servlet.internal.spi.ServletContainerProvider
Which should be at the root of the class path. The contents of that file should be the fully qualified name of our implementation.
You can see a complete example in this GitHub Repo

Swagger JAX-RS with Jersey 1.19 gives 'Conflicting URI templates' error

I am trying to add Swagger to an existing application that uses Jersey 1.19. For adding Swagger to the application, I have been following this guide: https://github.com/swagger-api/swagger-core/wiki/Swagger-Core-Jersey-1.X-Project-Setup-1.5.
When I deploy the application on Apache Tomcat, I get the following error:
SEVERE: Conflicting URI templates. The URI template / for root resource class io.swagger.jaxrs.listing.ApiListingResource and the URI template / transform to the same regular expression (/.*)?
The odd thing is that my Jersey servlet is not deployed at the root context, but at the /api/* context as shown in the web.xml file:
<servlet>
<servlet-name>MyApp Service</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>app.MyApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>MyApp Service</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
My MyApplication class is defined below:
public class MyApplication extends Application {
private final Set<Object> singletons = new HashSet<Object>();
private final Set<Class<?>> classes = new HashSet<Class<?>>();
public MyApplication() {
MyResource resource= new MyResource();
singletons.addAll(Arrays.asList(resource));
BeanConfig beanConfig = new BeanConfig();
beanConfig.setBasePath("/api");
beanConfig.setResourcePackage(getClass().getPackage().getName());
beanConfig.setTitle("REST API");
beanConfig.setVersion("1.0.0");
beanConfig.setScan(true);
classes.add(io.swagger.jaxrs.listing.ApiListingResource.class);
classes.add(io.swagger.jaxrs.listing.SwaggerSerializers.class);
}
#Override
public Set<Class<?>> getClasses() {
return classes;
}
#Override
public Set<Object> getSingletons() {
return singletons;
}}
I have tried other configurations, such as defining the Swagger servlet in the web.xml file instead of using the BeanConfig, but the same error still occurs. I have gotten Swagger to work this way on a different project that uses Jersey 2, but unfortunately the current project has to remain on Jersey 1.19. Here is the Swagger dependency defined in the pom.xml file:
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jersey-jaxrs</artifactId>
<version>1.5.0</version>
</dependency>
Any help would be appreciated.
Update 2: Looks like version 1.5.8 of swagger-core fixes that issue. See this commit for details.
Update: Instead of adding Swagger resource as sub-resource it much easier to just override #Path mapping. See Solution 2 for details.
I was facing exactly the same problem. The cause of that is Swagger resource being mapped to root #Path("/") public class ApiListingResource.
Solution 1 - No concurring mappings
One simple and inflexible way around it, is not to define any resource mapping to root path #Path("/").
Solution 2 - Override #Path mapping
2.1 Override Swagger classes
ApiListingResource should get a new #Path mapping
package my.api.package.swagger
import javax.ws.rs.Path;
#Path("swagger")
public class ApiListingResource extends io.swagger.jaxrs.listing.ApiListingResource {}
SwaggerSerializers should get new package
package my.api.package.swagger;
import javax.ws.rs.ext.Provider;
#Provider
public class SwaggerSerializers extends io.swagger.jaxrs.listing.SwaggerSerializers {}
2.2 Configure overriden classes
Add my.api.package.swagger instead of io.swagger.jaxrs.listing in Swagger package config.
Solution 3 - Swagger resource as sub-resource
Other solution is to move Swagger to a different path, allowing your resources to be mapped anywhere you like. To achieve this you need to:
3.1 Remove ApiListingResource from provider classes.
if you subclass Application:
public MyApplication() {
//init BeanConfig
//add your resource classes
//classes.add(io.swagger.jaxrs.listing.ApiListingResource.class);
classes.add(io.swagger.jaxrs.listing.SwaggerSerializers.class);
}
if you configure via web.xml using com.sun.jersey.config.property.packages param:
<servlet>
<servlet-name>your-rest-api</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>
{your_application_packages},
<!--io.swagger.jaxrs.json,-->
<!--io.swagger.jaxrs.listing-->
</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.classnames</param-name>
<param-value>
io.swagger.jaxrs.listing.SwaggerSerializers,
io.swagger.jaxrs.json.JacksonJsonProvider
</param-value>
</init-param>
</servlet>
BTW, I have noticed that GF 3.1.2.2 with Jersey configured using <filter/> in web.xml does not work with Swagger due to Grizzly related bug.
3.2 Add ApiListingResources as a subresource to one of your resources
#Path("/")
class RootResource {
#Context ServletContext context;
#Path("/swagger")
public ApiListingResource swagger() {
return new ApiListingSubResource(context);
}
}
As ApiListingResource is now not managed by Jersey, it does not get ServletContext injected. To overcome this problem you have to pass it as a constructor parameter, and for that subclass ApiListingResource and provide proper constructor:
// context has 'default' visibility
// so we need to stay in the same package
// to be able to access it
package io.swagger.jaxrs.listing;
import javax.servlet.ServletContext;
public class ApiListingSubResource extends ApiListingResource {
public ApiListingSubResource(ServletContext sc) { this.context = sc; }
}
Now your Swagger descriptors will be under http://hostname/app-path/swagger/swagger.json and you will still be able to use the root resource.
It's a little bit longer way , but works! Hope that helps.

JSR 2.0 annotations are not inherited by implementation

I'm trying to generate a rest-api using cxf and I have run into trouble, it seems like the PATH-annotation is not inherited correctly or something, If create a method that does not need #Path it works, but when I use Path I have to annotate the implementating method aswell
I have the following Api for use with cxf
#Path("/web")
public interface WebApi
{
#GET
#Path("/{id}/")
String getStuff(#PathParam("id") String id);
}
with the following implementation
public class WebApiServer implements WebApi
{
private final Logger logger = LoggerFactory.getLogger(getClass());
#GET
//#Path("/{id}/") //if I uncomment this line, it works
public String getStuff(#PathParam("id") String id)
{
logger.info("get called with args {}", id);
return "asdf";
}
}
I'm using CXF version 3.0.1 and javax.ws.rs-api version 3.0.1
my web.xml
<web-app>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>
<init-param>
<param-name>jaxrs.serviceClasses</param-name>
<param-value>com.richo.merlin.web.api.WebApiServer</param-value>
</init-param>
<init-param>
<param-name>jaxrs.address</param-name>
<param-value>/</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</web-app>
I have also put the entirety of my code here: https://github.com/RichoDemus/stackoverflow-cxf-troubleshoot
Keep your contract as is, but:
Move the class level annotations to the concrete implementaions of your WebApi interface.
Remove all method level annotations from the concrete implementation class, that is redundant.
After why would you have an interface and many implementations if those can only registered to the /web URI, and why would you redeclare the annotations if those are already declared in your interface.
If you want to go with other annotations, you would need to overload you methods declared in the interface level because overriding won't do it:
public interface WebApi
{
#GET
#Path("/{id}/")
String getStuff(#PathParam("id") String id);
}
#Path("/web")
public class WebApiServer implements WebApi
{
private final Logger logger = LoggerFactory.getLogger(getClass());
public String getStuff(String id)
{
logger.info("get called with args {}", id);
return "asdf";
}
}
According to the Inherited type class reference, You can't inherit annotations to implementing classes:
Note also that this meta-annotation only causes annotations to be inherited from superclasses; annotations on implemented interfaces have no effect.
A possible solution is to define an abstract class WebApiImpl implements WebApi and inherit from it.

How to cause static block to run?

I've seen many answers on this topic but still can't find a clean solution.
public class ProcessScheduler {
static {
Timer timer=new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
LogProcessorServiceImpl.processPageRequestsLogs();
}
}, 0, 120);
}
}
How do I make this execute and be happy with quality solution? My application is based on Spring (unfortunately) and I know I can reference this class in one of my controllers and it'd probably work. But that's silly. There just must be a better way. I'm on Tomcat with no EJB support, so timer annotation will not work for me. Also, I don't want to do CRON. I want to schedule all my maintenance tasks within this scheduler class.
Servlet classes can be loaded via web.xml (1). Can we do something similar on non-servlet classes?
Instead of writing this in a static block, I would prefer to
write an event listener that extends javax.servlet.ServletContextListener
move that piece of code into the contextInitialized method
define the contextDestroyed method to cancel the timer
configure the class as <listener> in web.xml file for my application.
<listener>
<listener-class>
com.vikdor.webapps.ProcessSchedulerListener
</listener-class>
</listener>

Categories

Resources