How to set an AbstractBinder in Jersey - java

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*//*");

Related

Using Spring Data Rest RepositoryEntityLinks outside of Controller

I would like to use the RepositoryEntityLinks class to get the link to a resource at various places in my code as per section 12.1 of the current Spring Data Rest manual
12.1. Programmatic Links Sometimes you need to add links to exported resources in your own custom built Spring MVC controllers. There are
three basic levels of linking available:
...
3 Using Spring Data REST’s implementation of RepositoryEntityLinks.
http://docs.spring.io/spring-data/rest/docs/current/reference/html/#_programmatic_links
I note the docs refer explicitly to "...your own custom built Spring MVC controllers" and it would seem that is the only place it is available. I would like to use the configured instance in a Spring Security AuthenticationSuccessHandler however the application fails to start with the error:
No qualifying bean of type[org.springframework.data.rest.webmvc.support.RepositoryEntityLinks] found
I have been able to successfully inject it to a controller as expected.
Can I use the RepositoryEntityLinks class outside of a Spring MVC Controller?
public class RestAuthenticationSuccessHandler implements AuthenticationSuccessHandler
{
#Autowired
private RepositoryEntityLinks entityLinks;
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException
{
//do something with entityLinks
}
}
Yes, You can. I have successfully used it in Assembler which generates links from HATEOAS model. Altough there may be some restrictions on where RepositoryEntityLinks class can be injected, for sure it can be used outside of Controllers.
Below you can see my working example. If anyone wnders this class extends ResourceAssemblerSupport which is part of spring-hateoas module. Maybe that's the thing that enables injection here.
#Component
public class UserAssembler extends ResourceAssemblerSupport<UserEntity, UserResource> {
#Autowired
private RepositoryEntityLinks repositoryEntityLinks;
public UserAssembler() {
super(UserController.class, UserResource.class);
}
#Override
public UserResource toResource(UserEntity userEntity) {
Link userLink = repositoryEntityLinks.linkToSingleResource(UserEntity.class, userEntity.getId());
Link self = new Link(entryLink.getHref(), Link.REL_SELF);
return new UserResource(userEntity, self);
}
}
The following works for me:
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class RestApiIntegrationTests {
#Autowired
private RepositoryEntityLinks repositoryEntityLinks;
#BeforeEach
public void initServletRequestAttributes() {
MockHttpServletRequest request = new MockHttpServletRequest();
ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request);
RequestContextHolder.setRequestAttributes(requestAttributes);
}
#Test
void test() {
System.out.println(repositoryEntityLinks.linkToCollectionResource(SomeClass.class));
}
}
The code is based on spring-data-rest-tests-core: AbstractControllerIntegrationTests, TestMvcClient.

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.

EntityManager injection in Tomcat

I'm trying to write a web application that will run on Tomcat 8 using Spring MVC 4, Hibernate and JPA.
I'm doing this annotation driven so no XML in the Spring code if I can help it.
I have several layers in the application: Controllers that are part of the Spring MVC web app; services and repositories (although these are not annotated as Spring services etc.), all are in different JAR files that are distributed in the web app's WAR.
I'd like to inject either EntityManager or EntityManagerFactory into my code (I'm using a variation of the repository pattern) but can't get it to work.
I also have a persistence.xml defined that sets up a persistence unit.
I've tried several things and nothing works.
I've added #PersistenceContext to both an EntityManager and EntityManagerFactory variable;
I've tried #PersistenceUnit in the repository code but no luck.
The last thing I tried (following this post Injecting EntityManager with a producer in tomcat) was to add a listener to the web app and use #Inject in my code. The listener is created but the 'createEntityManager' method is never called (and yes, I've changed it to add the #Produces annotation)
So my listener looks like this:
#Produces
public EntityManager createEntityManager() {
System.out.println("*********** EntityManagerFactoryListener - createEntityManager: ");
if (entityManagerFactory == null) {
throw new IllegalStateException("Context is not initialized yet.");
}
return entityManagerFactory.createEntityManager();
}
And my reoository looks like this
#Inject
public void setEntityManager(final EntityManager entityManager) {
this.entityManager = entityManager;
System.out.println("*********** entityManager: " + entityManager);
}
The error I get is
Error creating bean with name 'hibernateRepository': Injection of autowired dependencies failed
...
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManager] ...
Am I missing something? Can I even do this in Tomcat or do I need an EJB container?
EDIT
In answer to the question I have a WebApplictionInitializer that looks like this:
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = getContext();
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", new DispatcherServlet(context) );
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
private WebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(WebConfig.class);
return context;
}
and a WebMvcConfigurerAdapter that looks like:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.pluralsight")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public InternalResourceViewResolver getInternalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
}

Embedded Tomcat 7 passing Spring application context to servlets

I would like to add web interface to my Java application, so that I can manipulate it's state using HTTP.
I have added to application context a Spring bean for some class that starts embedded Tomcat. This class of course has access to context that creates it. But I would like to store this context somehow in Tomcat class (org.apache.catalina.startup.Tomcat) so that later in can be retrieved in Servlets, so that I can do something like this:
public SomeClass extends extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ApplicationContext appContext = getContextStoredEarlierInTomcatClass();
SomeBeanFromContext sbfc = appContext.getBean("sbfc", ApplicationContext.class);
sbfc.setSomeProperty(newValue);
}
}
Any idea how I could achieve it?
Thanks!
Classes including Servlets do not require an ApplicationContext to obtain references to String beans. This is done using dependency injection
#Controller
#RequestMapping("/mypage")
public class SomeClass {
#Autowired
private SomeBeanFromContext sbfc;
#RequestMapping(value = "/individualRequest", method = RequestMethod.GET)
public String doIndividualRequest(HttpServletRequest request) {
sbfc.setSomeProperty(newValue);
...
}
}
Spring MVC offers a complete method of injecting beans into target web controller classes using #Controller annotated classes.

Inject EntityManagerFactory in a servlet dispatcher (non managed)

I want to create a servlet dispatcher capable of doing some JPA operations. This servlet must not have any dependencies on Spring or EJB. So, my intention is to inject EntityManagerFactory to it programatically. Then, the dispatcher must handle transactions and create/open/close EntityManager when required.
So I did this code in a sample application, using Spring 3 and EclipseLink:
public class Initializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext context) {
AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
appContext.scan(...);
appContext.refresh();
EntityManagerFactory emf = appContext.getBean(EntityManagerFactory.class);
MyDispatcher dispatcher = new MyDispatcher(emf);
context.addServlet("my", dispatcher).addMapping("/my/*");
}
}
public class MyDispatcher extends HttpServlet {
...
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
emf.createEntityManager();
// java.lang.IllegalStateException: Attempting to execute an operation on a closed EntityManagerFactory.
}
}
The problem is when this dispatcher needs to create an EntityManager an IllegalStateExceptionis thrown. Debugging I have seen that EntityManagerFactoryImpl.close() is called automatically after all beans are instantiated.
What am I doing wrong? Is there some way of achieving what I need?
Thanks.

Categories