Autowire problems with Spring 3.2 and Jersey 2.4 - java

I'm trying to upgrade a system that's using Spring 3.2 and Jersey from Jersey version 1.17 to Jersey version 2.4. I'm running into an annoying problem with #Autowired where Jersey basically complains it cannot find the bean for a given (generic) type.
We have a base class (BaseService<T>) for database-backed services that provides a basic CRUD-style interface (get, save, delete). We also have a base class for the REST resources that looks similar to this:
public abstract class BaseResource<S extends BaseService<T>>
{
protected S service;
// ... common functions used by BaseService descendants ...
#Autowired
public void setBaseService(S baseService)
{
this.service = baseService;
}
}
And then we have a number of concrete classes that inherit from BaseResource, provide their unique logic, etc. Under Jersey 1.17 this works fine.
After upgrading my environment to Jersey 2.4 and including the jersey-spring3 project, I get different behavior. During service startup I can verify that the setBaseService() routine gets called by Spring and the supplied parameter is not null. However when a client makes a call and an actual REST resource is executed, Jersey logs the following warning
org.glassfish.jersey.server.spring.AutowiredInjectResolver getBeanFromSpringContext
WARNING: No beans found. Resolution failed for type S.
This actually results in Jersey passing a null parameter to the setBaseService() routine, which of course causes NPEs. Now I can work around the null parameter with a check, but I'd like to know why Jersey is having this problem and how I can avoid it.
Interesting fact is that I have another REST resource that does not inherit from BaseResource but does contain its own #Autowired setService() routine. This one works perfectly fine; it gets called correctly by Spring at startup and correctly by Jersey with a non-null parameter upon each call. It's just the generic-based setter that has the problem.
Anyone have any ideas? Thanks.

Please try the following.
Add the following dependency: jersey-spring3
The above allows Spring DI support into JAX-RS classes with spring xml.
If you are using Maven, add the following into your pom.
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>`
<artifactId>jersey-spring3</artifactId>`
<version>2.4.1</version>
<scope>runtime</scope>
</dependency>
See https://jersey.java.net/documentation/latest/spring.html

Related

Jersey HK2 Dependency Injection doesn't work after update to v2.27

I have a project using Jersey v2.25.1. I was using Jersey's inbuilt HK2 injection to perform dependency injection, and everything worked fine. Fast forward to now, I decided to update to Jersey v2.27.
When I ran my project, I got the following exception:
java.lang.IllegalStateException: InjectionManagerFactory not found
After some googling, I found that I needed to add the jersey-hk2 dependency. Doing so made me get the following exception:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=<MyClass>,parent=<MyClass>,qualifiers={},position=0,optional=false,self=false,unqualified=null,1044705957)
Upon reverting all my dependencies to Jersey v2.25.1, everything works fine. What do I need to do to fix these errors, so I can use Jersey v2.27?
Edit:
I don't use Maven so I can't really post a pom.xml, but tommorow I will put together an MVCE with the exact dependencies I have, and a basic example of Dependency Injection.
Answer by Paul Samsotha in a comment:
Try to change your AbstractBinder import. There are two, a Jersey one and an HK2 one. Try to use the Jersey one.
Basically, I needed to change the AbstractBinder class I implemented from
org.glassfish.hk2.utilities.binding.AbstractBinder
to
org.glassfish.jersey.internal.inject.AbstractBinder
The difference is that Jersey decoupled HK2 from it's internal DI mechanism in version 2.26, and thus, I needed to use the new AbstractBinder import, which comes directly from Jersey, and not HK2.
There are a few API differences: for instance, instead of a Factory<T>, bindFactory() takes a java.util.function.Supplier<T>.

Glassfish 4 scans for #PostConstruct with CDI disabled

I'm doing and upgrade from Glassfish 3.1.2.2 to Glassfish 4.1 for a set of Spring applications. Since I use the Spring to handle #Inject annotations, I have disabled Glassfish' CDI using this command:
asadmin set configs.config.server-config.cdi-service.enable-implicit-cdi=false
Still, when I deploy one of my applications, I get the following error message:
The lifecycle method [something] must not throw a checked exception.
Related annotation information: annotation [#javax.annotation.PostConstruct()]
on annotated element [public void com.something.MyClass.something() throws
java.io.IOException] of type [METHOD]. Please see server.log for more details.
The class in question is an abstract class with no implementations in the application that I'm trying to deploy, it's just something that is on my classpath.
Why is Glassfish validating my #PostConstruct when I've disabled CDI? Why is Glassfish validating #PostConstruct on something that can not become a bean?
How can I prevent Glassfish from interferring with anything that I'm using Spring for?
Annotation #PostConstruct is a general annotation used in any dependency injection mechanism. The Javadoc explicitely states that, unless used within an interceptor, it must be put on a method, which has void return type and throws no checked exceptions.
It is weird that Spring allows checked exceptions on post-construct methods, as there is not way how to handle them. But as this requirement is only a validation and can be ignored, Spring probably ignores checked exceptions and Glassfish does not. There is possibly an unnecessary Glassfish feature, that it scans and validates all classes, even if not used in CDI or any other mechanism (EJB, ...)
The best is to remove checked exceptions to align the code with the documentation and make it portable.
You can solve this issue first by adding a web.xml with metadata-complete="true". Next you will want to make sure your context are in the Web root Directory /WEB-INF/.
With this glassfish can load all #PostConstructSpring dependencies.
More of a work around in my opinion.

Classpath scanning of dependencies

I have a 3-tier application: web-service, service-layer and domain-layer. The web service is present in a web application (WAR). The service-layer and domain-layer are two JAR projects. The dependencies are:
web-service --> service-layer --> domain-layer
In the service layer, the services are annotated with #Service. In the domain-layer, the DAOs are annotated with #Repository. The web service implementation class uses the services of the service-layer JAR, so it keeps one instance of each service which is automatically injected (#Autowired).
The dependencies are well defined in my POMs. When I deploy my WAR on Tomcat, I get the following exception:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.mycompany.project.services.MyService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:952)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:821)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:735)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:551)
... 37 more
I quote from one relevant part in the Spring docs:
The scanning of classpath packages requires the presence of
corresponding directory entries in the classpath. When you build JARs
with Ant, make sure that you do not activate the files-only switch of
the JAR task.
I've checked and the service-layer JAR is present in the WEB-INF/lib directory.
Any idea?
Thanks
EDIT: I have only one context file which is located in the web-service layer project (WAR) under src/main/webapp/WEB-INF. In this context, I've enabled classpath scanning as follows:
<context:component-scan base-package="com.mycompany.project" />
The package com.mycompany.project is the base package of my project, under which there are the web-service (com.mycompany.project.server), service-layer (com.mycompany.project.services) and domain-layer (com.mycompany.project.domain) packages.
I've solved the issue. I don't understand why what I've done was causing such an issue. Each service implements an interface that defines its public methods. In my web service implementation class, the references to the services used the implementation classes and not the interfaces. I just changed them to use the interface, and I don't get the issue anymore. Could anyone explain me what's wrong with using the services implementation classes instead of the interfaces for the autowiring?
This is an answer for your EDIT:
The reason why referring to the interface worked but the concrete implementation failed is probably to do with the dynamic proxies that Spring creates for cases where you have your services annotated with #Transactional etc. What happens in such cases is that the type of your beans are not the implementation type anymore, but wrap around your impementation type. So when you have #Autowired by implementation type, it just cannot find it by type (which is the default).
Your fix is very appropriate, as a dynamic proxy continues to derive from the interfaces that you have defined for your implementation and so can inject by interface type - the reference that I have provided does a better job explaining this.
make sure you used <context:component-scan base-package="your.service.package"/>
check your autowired strategy is byName or byType; if byName, the Service annotation's name value should be right.
if problem still exist, check spring's log, it will print all found components' name, you could know the service is founded or not.
Can you show your component scanning configuration? If this is not set up correctly then Spring may not be discovering your service.
You want something like:
<context:component-scan base-package="your.service.package"/>
Edit:
I think the problem is that your #Service annotation is on the interface rather than implementation class.
If you annotate your service implementation then your web controller can use either:
#Autowired
private ExampleService service;
or
#Autowired
private ExampleServiceImpl service;

Apache CXF web services problems

I have a multi-module project using Maven. On one of the modules I have several web services developed using Apache CXF Framework 2.5.4. At the moment I have two "problems" or questions.
First of all, if I call to a method of one of the web services that should return a List, if the list is empty, it returns "null" instead of the empty list.
I was trying to find out what could be the problem, if it's a bug of the CXF version I'm using or if I should use some annotation to modify the definition of the method or the response, but I couldn't find anything. I've seen some people with the same problem, but no solution.
The other thing I wanted to ask is: I'm developing a web application using MVC pattern. I'm wondering which way I should call the web service from the Controller instead of using ClasspathXmlCpplicationContext and then context.getBean().
For example, the bean definition for one of the web services on the client side is:
<jaxws:client id="deviceWSClient"
serviceClass="..IDeviceWebService"
address="http://localhost:8080/../DeviceWS" />
I've already tried usin #Autowired or #WebServiceRef annotations. With these it works but not doing a HTTP request to the web service, I guess it gets the dependency from the local repository. I think what I need is the way of injecting this bean on the Controller.
To answer your questions
For your first question: If the list is empty it is correctly handled by CXF version 2.6.1 - the service returns a empty. Just to demonstrate I have a sample service where types are defined this way:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "MemberSearchResponse", namespace="http://bk.org/memberservice/" )
public class MemberSearchResponse {
#XmlElementWrapper(name="memberDetails")
private List<MemberDetail> memberDetails;
If I return a empty memberDetails above, the xml that goes over the wire is this:
<ns2:searchMemberResponse xmlns:ns2="http://bk.org/memberservice/">
<ns2:MemberSearchResponse>
<memberDetails/>
</ns2:MemberSearchResponse>
</ns2:searchMemberResponse>
EDIT
It is correctly handled as part of a wrapper type like above, but DOES return null if instead of returning a wrapper type, the list is directly returned.
Consider a Webservice interface defined this way:
#WebMethod(operationName = "searchMember")
List<MemberDetail> searchMember(#WebParam(name = "MemberSearchRequest") MemberSearchRequest memberSearchRequest);
If the List returned is an Empty list, it gets serialized as null by CXF 2.6.1 also.
The workaround is to use a wrapper type
EDIT END
For your second question:
You are creating a client bean this way:
<jaxws:client id="deviceWSClient"
serviceClass="..IDeviceWebService"
address="http://localhost:8080/../DeviceWS" />
Once you have created a Spring bean this way, you can treat it just like a normal Spring bean and inject it the way you would do with any normal Spring bean, for eg, either inject it this way:
<bean id="consumerBean" class="...">
<property name="deviceWS" ref="deviceWSClient">
</bean>
or use #Autowired
#Autowired IDWebService deviceWSClient
Or user #Resource
#Resource IDWebService deviceWSClient
These are the usual ways of injecting in a bean.
I have a sample application at this github location that you can play with:
https://github.com/bijukunjummen/memberservice-codefirst.git
Just start up the server using mvn tomcat:run and run a test org.bk.memberservice.TestCxfIntegrationTest which will make a request to the CXF service.
#WebServiceRef probably works if you follow this link on Spring forum. There you use different way for jaxws configuration. See the last post on the list.
Another ways to define the client are discussed on this SO question. There is e.g a solution where you finally use #Autowired annotation after you have given some extra configuration. See the last answer on the question.
The another issue you mentioned was about this cxf List related issue where also a solution is told for a workaround to the problem. So it is a bug. Version 2.2.7 has it fixed, but again in version 2.2.9 problem is arisen again. Wierd that until your version 2.5.4 it is back on error state. You could try the work around still, if it fixes the issue for you.

How are you supposed to access EJB when using Easyrest?

I have been trying to get Resteasy to work (and not it dose). However I now have another headache with accessing the EJB:s. I have tried injecting them, looking them up with jndi and most other solutions but none of them works.
I get massages like: java.lang.RuntimeException: Class is not a root resource.
Or: java.lang.IllegalArgumentException: Wrong target.
Or just: NullPointer
Using JBoss 5.1.0.GA and Resteasy 1.2.1.GA... Can't find any documentation on how this could be done. Do anybody know?
Have you seen this: EJB Integration?
Resteasy currently only has simple integration with EJBs. To make an EJB a JAX-RS resource, you must annotate an SLSB's #Remote or #Local interface with JAX-RS annotations:
Next, in RESTeasy's web.xml file you must manually register the EJB with RESTeasy using the resteasy.jndi.resources

Categories