Adding a ContainerResponseFilter to jetty server - java

I want to add a ContainerResponseFilter and ContainerRequestFilter to my jetty-server. But when I try to add it, I get an error that the class is not good.
My jetty server-setup:
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.addFilter(CorsFilter.class, //Error here
"/*", EnumSet.of(DispatcherType.REQUEST));
Server jettyServer = new Server(8090);
jettyServer.setHandler(context);
ServletHolder jerseyServlet =
context.addServlet(ServletContainer.class, "/*");
jerseyServlet.setInitOrder(0);
jerseyServlet.setInitParameter("jersey.config.server.provider.classnames",
Login.class.getCanonicalName());
Starter.start(jettyServer);
and my filter:
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
The error is that the method is not resolved.
Thanks!

ContainerRequestFilter and ContainerResponseFilter are not Servlet Filters, those are JAX-RS filters.
Register them with your ResourceConfig implementation.
Example:
#ApplicationPath("/")
public class MyApplication extends ResourceConfig {
public MyApplication() {
// Register resources and providers using package-scanning.
packages("my.package");
// Register my custom provider - not needed if it's in my.package.
register(CorsFilter.class);
// Register an instance of LoggingFilter.
register(new LoggingFilter(LOGGER, true));
...
}
}

Related

Spring Boot is not setting the #Value property in Jersey's ResourceConfig class

why is my port member 0 in my Jersey ResourceConfig class at runtime?
Application.property file:
#web server
server.port=9000
JerseyConfig file:
#Component
#ApplicationPath(Pathes.APPLICATION_PATH)
public class JerseyConfig extends ResourceConfig {
#Value("${server.port}")
private int port;
public JerseyConfig() {
final BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0.0");
beanConfig.setHost("localhost:" + port);
beanConfig.setBasePath(Pathes.APPLICATION_PATH);
beanConfig.setResourcePackage(myPackages);
beanConfig.setScan(true);
register(ApiListingResource.class);
register(SwaggerSerializers.class);
}
}
Thank's for your help!
You are using port in constructor, before it's initialized by Spring container. You can't do this with Spring.
Do constructor injection instead:
#Component
#ApplicationPath(Pathes.APPLICATION_PATH)
public class JerseyConfig extends ResourceConfig {
#Autowired
public JerseyConfig(#Value("${server.port}") int port) {
final BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0.0");
beanConfig.setHost("localhost:" + port);
beanConfig.setBasePath(Pathes.APPLICATION_PATH);
beanConfig.setResourcePackage(myPackages);
beanConfig.setScan(true);
register(ApiListingResource.class);
register(SwaggerSerializers.class);
}
}

Adding SecurityWebApplicationInitializer to existing Spring app

I try to follow answers to this question, but still cannot make it work.
I have following Java config classes:
public class MyWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(WebAppConfiguration.class);
container.addListener(new ContextLoaderListener(rootContext));
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
And for security:
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
super(WebSecurityConfiguration.class);
}
}
The problem is I get exception like that on startup:
java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
Without SecurityWebApplicationInitializer class it starts up and works fine except of the fact that Spring Security doesn't work.
I understand that the problem is that SecurityWebApplicationInitializer injects it's own context. But then what is the right way to make the Spring Security work for my case?
Thank you.

Jersey with embedded Jetty resolving dependency injection in Resource

I'm having troubles to wire Jersey with Jetty while trying to inject dependencies of my resouce. What I'm doing is:
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new MyBinder());
}
}
My binder simplified:
public class MyBinder extends AbstractBinder {
#Override
protected void configure() {
bind(ManagerImpl.class).to(Manager.class);
}
}
And my resource simplified:
#Path("test")
public class MyResource {
#Inject
Manager manager;
...
}
I tried this to wire all that together:
ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
ServletContainer jerseyServletContainer = new ServletContainer(new MyApplication());
ServletHolder jerseyServletHolder = new ServletHolder(jerseyServletContainer);
jerseyServletHolder.setInitParameter("jersey.config.server.provider.classnames", MyResource.class.getCanonicalName());
servletContextHandler.setContextPath("/");
servletContextHandler.addServlet(jerseyServletHolder, "/*");
Server server = new Server(threadPool);
ServerConnector connector = new ServerConnector(server);
connector.setPort(httpPort);
server.setConnectors(new Connector[]{connector});
server.setHandler(servletContextHandler);
server.start();
However I keep receiving HTTP ERROR: 404
Any ideas how I could get it sorted?
Thanks
Ok, I also made it work without dropwizard and guice. For some reasons Jersey implementation doesn't include GuiceComponentProviderFactory since the version 2.XX. Otherwise it would be possible to do something like this:
Injector injector = Guice.createInjector( new ServletModule() { ...} );
IoCComponentProviderFactory ioc = new GuiceComponentProviderFactory( resourceConfig, injector );
Server server = JettyHttpContainerFactory.createHttpServer( BASE_URI + "services/", resourceConfig, ioc );
Since version 2.X they have integrated HK2 IoC framework with a GuiceBirdge, so you would need to mess around with HK2 and Guice:
GuiceBridge.getGuiceBridge().initializeGuiceBridge(aServiceLocator);
So I simply stick to HK2 for the moment having it wired all together in this way:
URI baseUri = UriBuilder.fromUri("http://localhost/").port(8800).build();
Server server = JettyHttpContainerFactory.createServer( baseUri, new MyApplication() );
server.start();
My ResourceConfig:
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new MyBinder());
register(MyResource.class);
}
}
So I simply missed to register my resources on top of registering my binder. So in that way I'm not using web.xml at all having nicely embedded jetty server.

Registering a provider programmatically in jersey which implements exceptionmapper

How do I register my provider programmatically in jersey which implements the Exceptionmapper provided by jersey API? I don't want to use #Provider annotation and want to register the provider using ResourceConfig, how can I do that?
For example:
public class MyProvider implements ExceptionMapper<WebApplicationException> extends ResourceConfig {
public MyProvider() {
final Resource.Builder resourceBuilder = Resource.builder();
resourceBuilder.path("helloworld");
final ResourceMethod.Builder methodBuilder = resourceBuilder.addMethod("GET");
methodBuilder.produces(MediaType.TEXT_PLAIN_TYPE)
.handledBy(new Inflector<ContainerRequestContext, String>() {
#Override
public String apply(ContainerRequestContext containerRequestContext) {
return "Hello World!";
}
});
final Resource resource = resourceBuilder.build();
registerResources(resource);
}
#Override
public Response toResponse(WebApplicationException ex) {
String trace = Exceptions.getStackTraceAsString(ex);
return Response.status(500).entity(trace).type("text/plain").build();
}
}
Is this the correct way to do this?
I'm guessing you don't have a ResourceConfig, since you seem to not be sure how to use it. For one, it is not required. If you do use it, it should be it's own separate class. There you can register the mapper.
public class AppConfig extends ResourceConfig {
public AppConfig() {
register(new MyProvider());
}
}
But you are probably using a web.xml. In which case, you can register the provider, with the following <init-param>
<servlet>
<servlet-name>MyApplication</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
org.foo.providers.MyProvider
</param-value>
</init-param>
</servlet>
Have a look at What exactly is the ResourceConfig class in Jersey 2?
for more information on different deployment models. There are a few different ways to deploy applications. You can even mix and match (web.xml and ResourceConfig).
While #paul-samsotha's answer is correct, still there is implementation trick. I want to share it and hope it will help someone.
a) Implement your mapper:
public class MyExceptionMapper implements ExceptionMapper<Throwable>, ResponseErrorMapper {
...
b) make sure you declare generic type, otherwise your mapper will never be called
public class MyExceptionMapper implements ExceptionMapper/* no generic declaration */, ResponseErrorMapper {
...
and may trigger
javax.ws.rs.ProcessingException: Could not find exception type for given ExceptionMapper class: class com...MyExceptionMapper.
c) Register it as resource:
ResourceConfig config = new ResourceConfig();
config.register(new MyExceptionMapper());
or
config.register(MyExceptionMapper.class);
d) make sure you enforce processing errors as well:
config.setProperties(new LinkedHashMap<String, Object>() {{
put(org.glassfish.jersey.server.ServerProperties.PROCESSING_RESPONSE_ERRORS_ENABLED, true);
}});
If you're using Spring and want to register the providers programmatically based on the presence of #Path and #Provider annotation you can use the following technique
#Component
public class JerseyConfig extends ResourceConfig {
#Autowired
private ApplicationContext applicationContext;
#PostConstruct
public init() {
applicationContext.getBeansWithAnnotation(Path.class).values().forEach(
component -> register(component.getClass())
);
applicationContext.getBeansWithAnnotation(Provider.class).values().forEach(
this::register
);
}
}

How to set an AbstractBinder in Jersey

I'm trying to implement my HK2 binding in Jersey, in a servlet / tomcat context.
I do, in a servlet which extends org.glassfish.jersey.servlet.ServletContainer :
#Override
public void init(ServletConfig config) throws ServletException
{
super.init(config);
// BinderInjection extends org.glassfish.hk2.utilities.binding.AbstractBinder
getConfiguration().register(new BinderInjection());
}
... but I get :
java.lang.IllegalStateException: The resource configuration is not modifiable in this context.
at org.glassfish.jersey.server.ResourceConfig$ImmutableState.register(ResourceConfig.java:270)
at org.glassfish.jersey.server.ResourceConfig$ImmutableState.register(ResourceConfig.java:218)
at org.glassfish.jersey.server.ResourceConfig.register(ResourceConfig.java:448)
at A_Servlet.init(RestServlet.java:45)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1190)
So how can I do my own HK2 binding ?
Why this question ? (edit)
It's for EntityManager and JPA in Jersey.
With Netbeans, if I generate an AbstractFacade it put
#PersistenceContext(unitName = "myunit")
private EntityManager em;
... and :
#Override
protected EntityManager getEntityManager()
{
return em;
}
But, when I call the service, em is null. So I suppose it's #PersistenceContext which doesn't work ?
If I use the solution Tutorial: Put JPA in your Web App (tomcat, EclipseLink) and provide Rest JSON output all work like a charm, but I don't like use static variable private static EntityManagerFactory emf; for entity manager.
Thanks.
Below is an example where I am binding a Spring injected jersey resource to the Jetty Webserver. ResourceConfig utility is provided by Jersey. Hope this example helps.
p.s. -- restService is a Spring injected dependency
ResourceConfig config = new ResourceConfig(CustomRestService.class);
config.register(new AbstractBinder() {
#Override
protected void configure() {
bind(restService).to(CustomRestService.class);
}
});
restService.start();
ServletHolder apiServlet = new ServletHolder(new ServletContainer(config));
ServletHolder apiServlet = new ServletHolder(new HttpServletDispatcher());
servletContainer.addServlet(apiServlet, "/api/v1*//*");

Categories