Spring : Autowired bean is null - java

I am working on a Spring-MVC application in which I am autowiring a field, but it is getting set as NULL. I checked the solutions on net for the same problem, as they describe, I should not create a new instance of classes when working, rather get it from spring. I tried that as well, but it always complains the resource is not found.
Here is the class :
#Service
#Transactional
public class GoogleAuthorization{
#Autowired
private DriveQuickstart driveQuickstart; // This guy is null
public void saveCredentials(final String authCode) throws IOException {
GoogleTokenResponse response = flow.newTokenRequest(authCode).setRedirectUri(CALLBACK_URI).execute();
Credential credential = flow.createAndStoreCredential(response, null);
System.out.println(" Credential access token is "+credential.getAccessToken());
System.out.println("Credential refresh token is "+credential.getRefreshToken());
// It fails at below point.
this.driveQuickstart.storeCredentials(credential);
}
Controller code :
#RequestMapping(value = "/getgooglelogin")
public String getGoogleLogin(HttpServletRequest request, HttpServletResponse response, HttpSession session,Model model) {
/* ApplicationContext applicationContext = new ClassPathXmlApplicationContext("../WEB-INF/spring/root-context.xml");
GoogleAuthorization helper = (GoogleAuthorization) applicationContext.getBean("helper");*/
GoogleAuthorization helper = new GoogleAuthorization();
}
I tried getting it via the root-context.xml as you can see above, but no matter what path I would put, it could not find it.
DriveQuickStartImpl :
#Service
#Transactional
public class DriveQuickstartImpl implements DriveQuickstart{
// All these below guys work just fine.
#Autowired
private PersonService personService;
#Autowired
private GoogleDriveService googleDriveService;
#Autowired
private GroupAttachmentsService groupAttachmentsService;
#Autowired
private GroupAccountService groupAccountService;
}
What am I doing wrong. Any help would be nice. Thanks a lot.
Update
Image for where root-context.xml belongs :

Just autowire the GoogleAuthorization helper (you can do this as you are already in a Spring-managed controller):
#Service
#Transactional
public class DriveQuickstartImpl implements DriveQuickstart{
// Other stuff...
#Autowired
private GoogleAuthorization helper;
#RequestMapping(value = "/getgooglelogin")
public String getGoogleLogin(HttpServletRequest request, HttpServletResponse response, HttpSession session,Model model) {
// use "helper"
}
If you autowire the helper, it is injected and managed by Spring. So Spring will build and autowire it correctly.

if you create an instance with 'new' on your own there will be no spring wiring at all.
if you use Spring in a Web-App Context you could use the ContextLoaderListener to initialize your Spring-Context.
<!-- inside WEB-INF/web.xml -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- path to your Spring context configuration-->
<!-- for example -->
<param-value>/WEB-INF/spring-webapp-config.xml</param-value>
</context-param>
you can then inject the GoogleAuthorization Bean in your controller as well, so there is no need to get hold of the application context to do a 'lookup' ... if you use spring try to let spring do the wiring instead of relying on 'lookups'.

Problem is here:
GoogleAuthorization helper = new GoogleAuthorization();
As you created with GoogleAuthorization with new, Spring container wont be aware of the class which we might think as a spring bean and as a result it fails to Autowire it. Make sure your class in which #Autowiring is done is a spring bean. Trying instantiating GoogleAuthorization using FileSystemXmlApplicationContext as :
ApplicationContext applicationContext = new FileSystemXmlApplicationContext(
"src/main/webapp/WEB-INF/spring/root-context.xml");
GoogleAuthorization helper = (GoogleAuthorization)applicationContext.getBean("helper");

Related

How to autowire a bean into a 2 different controllers (Spring)

I am learning spring and i have a problem that i do not know how to solve.
#Service
#Transactional
public class SchoolService {
#Autowired
private CourseDao courseDao;
#Autowired
private EducationDao educationDao;
#Autowired
private StudentDao studentDao;
#Autowired
private TeacherDao teacherDao;
#Autowired
private StatisticsDao statisticsDao;
............
}
This code is injecting my DAOS into this service class but then i need to inject the class above into two controllers.
One way i have tried was with this code but that did not work.
#Autowired
SchoolService sm;
How would i inject it into my controller class. I have tried making the controller class a #Component but nothing seems to work.
ClassPathXmlApplicationContext container = new ClassPathXmlApplicationContext("application.xml");
SchoolService sm = container.getBean(SchoolService.class);
This way works but i do not want to create a new applicationcontext for each time i want to get that bean.
Yes i am using xml at the moment, please don't shoot me :D
Thanks.
Try creating the controller bean in the application.xml file instead of annotating the controller.
Since its obviously an educational question, I'll try to provide a very detailed answer as much as I can:
Once basic thing about spring that all the auto-wiring magic happens only with beans that are managed by spring.
So:
Your controllers must be managed by spring
Your service must be managed by spring
Your DAOs must be managed by spring
Otherwise, autowiring won't work, I can't stress it more.
Now, Think about the Application Context as about the one global registry of all the beans. By default the beans are singletons (singleton scope in terms of spring) which means that there is only one object (instance) of that bean "retained" in the Application Context.
The act of autowiring means basically that the bean (managed by spring) - controller in your case has dependencies that spring can inject by looking in that global registry, getting the matching bean and setting to the data field on which the #Autowired annotation is called.
So, if you have two controllers (again, both managed by spring), you can:
#Controller
public class ControllerA {
#Autowired
private SchoolService sm;
}
#Controller
public class ControllerB {
#Autowired
private SchoolService sm;
}
In this case, the same instance of school service will be injected into two different controllers, so you should good to go.

In Spring Web, how do I get the full URL of a #RestController?

Lets say I inject an ApplicationContext into a bean. I can then discover all the beans annotated with RestController. How would I discover the base URL associated with said beans?
Example:
#Component
public class ServiceEnumerator {
#Autowired
private ApplicationContext context;
#PostConstruct
private void postConstruct() {
final Map<String, Object> beansToExpose = context.getBeansWithAnnotation(RestController.class);
}
}
As per standard, Base URL (Context root) needs to setup in configuration file.
Not sure if below will help you....Try to inject HttpServletRequest in controller then from controller, pass it to required service
#Context
private HttpServletRequest httpRequest;
LOGGER.info("URL "+httpRequest.getRequestURI());
will give /services/v1/hello if your URL is http://localhost:8080/services/v1/hello
This could be possible by retrieving bean definition from bean factory and parsing its metadata. for instance:
retrieve beanFactory from your application Context
getting your bean definition from bean factory
retrieving its metadata
fetching attributes
metadata.getAnnotationAttributes(
"org.springframework.web.bind.annotation.RestController")

Avoid creating ApplicationContext in each method

I have my REST controller and method inside:
#GET
#Path("/tests/{id}")
#Produces("application/json")
public Response getAvailableTestsNames(#PathParam("id") String id){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
StudentService studentService = (StudentService)context.getBean("studentService");
Set<TestDTO> testDTOs = studentService.getAvailableTestsNames(id);
return Response.status(200).entity(testDTOs).build();
}
How cain i avoid creating ApplicationContext each time? I want to create it on start and use #Autowired annotation to inject my beans
I also asked about that here:
jboss spring applicationContext load on start in web.xml
However, the solution does not work for me. i still get an error
You can annotate your rest controller with #RestController annotation and start injecting your services with #Autowired.

How to instantiate a Class/Bean in Spring MVC by request?

First of all I'm quite new to Springframwork.
Let's say I have a controller in Spring-MVC:
#Controller
public class FooController {
#Autowired
private Foo foo;
#Autowired
private FooService fooService;
#RequestMapping(value="/addfoo", method = RequestMethod.GET)
public void addRequest(
#RequestParam(value="rq_param", required=true) String param){
foo.setValue(param);
fooService.addFoo(foo);
}
}
I need to add Foo into a database. But before I need to set a value. This should happen when a certain request comes in (from elsewhere).
Here's my Service:
#Service
public class FooServiceImpl implements FooService {
#Autowired
private FooDAO fooDAO;
#Transactional
public void addFoo(Foo foo) {
fooDAO.addFoo(foo);
}
}
But this doesn't work. I get
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'fooController': Injection of autowired dependencies failed;
I'm quite sure that I've a made a basic mistake due to my lack of knowledge about IoC...
Thanks!
I don't think you should inject the Foo. It looks like a model object to me, not an interface-based service or controller.
You should create one using new when the request comes in, outside of Spring's control. You want to bind the value from the request parameter into the new Foo object and persist it.
Every object in a Spring project need not be under the control of the bean factory.
Usually you see calls to new for objects within method scope. They're usually POJO model objects that don't have interfaces. Your cases seems to be one of them to me.
<context:component-scan base-package="service,controllers,dao"></context:component-scan>
edit it in your servlet.xml after dtd.
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
this one in your web.xml file.
for dao u should add an annotation #Repository
may be i am wrong.. but try this one..

Jax-ws, spring and SpringBeanAutowiringSupport

although in my #Webservice class
I extend SpringBeanAutowiringSupport, autowiring simply does not work for Spring 2.5,
tomcat6.
nothing is injected.
I tested those beans autowiring in main method, using classpathcontext, everything is injected fine.
But not for jax-ws endpoint.
do you have ideas?
I've found the solution. The problem is that Spring doesn't autowire beans for #WebService classes (as found on other forums it might be a current bug).
The solution:
Use org.springframework.beans.factory.config.AutowireCapableBeanFactory.class instead of using #Autowired annotation for injecting your beans (e.g. #Service, #Repository etc).
So:
include #Resource WebServiceContext
#Resource
private WebServiceContext context;
use it for getting your bean
MyDAO myDAO = null;
ServletContext servletContext = (ServletContext) context
.getMessageContext().get("javax.xml.ws.servlet.context");
WebApplicationContext webApplicationContext = WebApplicationContextUtils
.getRequiredWebApplicationContext(servletContext);
myDAO = (MyDAO) webApplicationContext
.getAutowireCapableBeanFactory().getBean("myDAO");
MyDAO class can be as follows:
#Service
#Qualifier("myDAO")
#Transactional
public class MyDAO {
private HibernateTemplate hibernateTemplate;
#Required
#Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
public MyInfo getMyInfo(Long id){
return this.hibernateTemplate.get(MyInfo.class, id);
}
//...
}
after this you can use myDAO object in the #WebMethod method.
I don't know if it's the same case as everyone else. It worked for me by changing the order of the listeners in web.xml. Putting the ContextLoaderListener before WSServletContextListener resolved the issue.
I'm guessing that you're using this config element:
<context:annotation-config />
But to enable support for the #Endpoint annotation, you must add this element:
<context:component-scan base-package="" />
It would be better if you used some reference implementation, like Metro, Axis2, apache-cxf for easy configuration of such endpoint on web service.

Categories

Resources