We're currently adding some new features to an old webapp which was using only JSP without any framework for the front. We have added Spring recently, and we would like to autowire our beans in our modified JSP, while not rewriting everything to use SpringMVC, Struts2 or Tapestry5.
We're using autowiring by type, so it leads to get some code like this in the JSP, while previously getting the web application context ( as "wap") :
MyDao myDao = (MyDao) wap.getBeansOfType(MyDao.class).values().toArray()[0];
We would like not to use such a code but rather automagically inject our beans directly in our JSPs as we would in a business bean using #Autowired annotation.
In fact we're looking to the cleanest ways to inject our beans in our JSPs. What do you use ?
You can use Spring's ContextExposingHttpServletRequest:
HttpServletRequest decorator that
makes all Spring beans in a given
WebApplicationContext accessible as
request attributes, through lazy
checking once an attribute gets
accessed.
This would require your controller code to wrap the original HttpServletRequest in a ContextExposingHttpServletRequest, and then forward that to the JSP. It can either expose specific named beans, or every bean in the context.
Of course, this just shifts the problem from your JSPs to your controller code, but that's perhaps a more manageable problem.
You can't use #Autowired directly because both your jsps and servlets are instantiated by the servlet conainer. So they are not part of the spring context and hence their dependencies aren't injected.
You can:
move all code that to pure servlets, rather than in jsps - leave only presentation in the jsps.
use #Configurable on your servlets (and add a javaagent, as described in the linked docs)
Another way, is to make the servlet part of the current context manually. This is possible in both jsps and servlets:
public void init() {
WebApplicationContext ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(getServletContext());
AutowireCapableBeanFactory bf = ctx.getAutowireCapableBeanFactory();
bf.autowireBean(this);
}
This will resolve the #Autowired annotated dependencies.
Now, I'm not sure whether servlet containers are required to use only one instance of a servlet class. If not, you'd better place the above code in a getter-method for the dependency (getDao()) and if the #Autowired property is null (i.e. another instance of the servlet-class is used by the container) - perform the above operation.
That all said, really consider using a web framework (any of the ones you listed). Having logic in jsps is completely wrong, hard to support, hard to read, etc.
What about overriding jspInit() method and adding Autowiring support:
<%# page import="com.example.ExampleService"%>
<%# page import="org.springframework.beans.factory.annotation.Value"%>
<%# page import="org.springframework.beans.factory.annotation.Autowired"%>
<%# page import="org.springframework.web.context.support.SpringBeanAutowiringSupport"%>
<%!
public void jspInit()
{
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
getServletContext());
}
#Value("${example.property}")
private String someField;
#Autowired
private ExampleService exampleService;
%>
<% final Object data = exampleService.getSomething(someField); %>
I doubt that there is a clean way to inject dependencies into a JSP.
I think that the clean solution would be to start refactoring your code to get the business logic out of the JSPs, using either SpringMVC or one of the alternatives you cited.
Start with one or more minimalist controllers that simply pass the request to the JSPs with the injected beans as attributes; #skaffman's answer gives one way to do that, or you could do it more selectively. Then progressively migrate code out of the JSPs and into the controllers.
This isn't autowired, but Spring can expose your bean names into the request context, you just need to configure it in the viewResolver.
From: https://raibledesigns.com/rd/entry/spring_mvc_jstlview_and_exposecontextbeansasattributes
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="exposeContextBeansAsAttributes" value="true"/>
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
Related
I have a TestUtil class that I need to use in almost each of my other classes in a Spring MVC web application.
In my application context, I have done the following bean definitions:
<bean id="masterbo" class="com.bo.master.MasterBO">
<property name="masterdao" ref="masterdao"></property>
<property name="testutil" ref="testutil"></property>
</bean>
<bean id="masterdao" parent="daoSupport" class="com.dao.master.MasterDAO"></bean>
<bean id="testutil" class="com.util.TestUtil"></bean>
I have autowired the TestUtil class in MasterBO and simply used the testutil.someMethod() call.
Using this I am able to use the static method from TestUtil in MasterBO. Now, I would like to do the same in the MasterController. Similar bean definition is not working in that case
Can anyone guide me regarding the bean definition that needs to be done?
EDIT: Calling static methods directly is working on Tomcat. Facing this issue on WildFly and JBoss, which supposedly require proper bean definition.
SOLVED: It seems there was an incorrect ParseException being used in the Util which was conflicting with WildFly
You don't need to instantiate a bean to call a static method, just call the method directly by the class itself: TestUtil.someMethod().
I already know how to handle internationalization in a Spring application using <spring:message code="xxx"/> in a JSP page. Now my users are allowed to change languages using simple links like
IT and EN
Now, I have to handle internationalization inside a class. This is what I did:
1) I created a text.xml file to identify where my texts are
.....
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="struttura"></property>
</bean>
......
2) I created a different properties files according to different languages
3) I use this method to get the message according to the locale
......
ApplicationContext context = new ClassPathXmlApplicationContext("text.xml");
String stringa = context.getMessage("textCode",null, locale);
.......
Everything works. But I'm sure this is not the fastest and cleanest way to do it. It looks too intricate!
Does anybody know a better way to reach my goal?
MessageResource is a Spring managed bean so you can just inject it into your controllers (or other Spring managed classes):
#Autowired
private MessageSource messageResource;
I need to inject a object of a java class in spring controller through applicaionContext.xml. My controller will be ,
#Controller
public class SpringController{
private MyClass obj;
}
I know I can do it with #Autowired annotation.
Is this really good to create a object for a controller through applicaionContext.xml ? Also can I inject a object of a class in controller using the <property> tag inside a <bean> tag ?
Is this really possible ? or please forgive me if it is a stupid question.
I need to know the possible ways for how to inject a object of a class in Spring controller ?
You can of course use #Autowired annotation to autowire the relationships, which can reduce the need to define the properties and constructor arguments for the controller in your applicationContext.xml file. And also to add a dependency to a class, you don't need to modify the configuration files.
But it has some disadvantages too, like if you use #Autowired, there will not be any explicit documentation for the wiring details between Spring managed beans. And to know the relationships between the beans, you have to go through your managed beans. But, if you use configuration files to define the relationships, the relationship details can be found in one place.
You can inject an object of a class into your controller through your applicaionContext.xml as below:
Constructor based injection:
#Controller
public class SpringController{
private MyClass obj;
public SpringController(MyClass obj){
this.obj=obj;
}
}
<bean id="myClassImpl" class="x.y.z.MyClassImpl"></bean>
<bean id="springController" class="x.y.z.web.controllers.SpringController">
<constructor-arg ref="myClassImpl"></constructor-arg>
</bean>
Setter based injection:
#Controller
public class SpringController{
private MyClass obj;
public void setObj(MyClass obj){
this.obj=obj;
}
public MyClass getObj(){
return obj;
}
}
<bean id="myClassImpl" class="x.y.z.MyClassImpl"></bean>
<bean id="springController" class="x.y.z.web.controllers.SpringController">
<property name="obj" ref="myClassImpl"></property>
</bean>
If you want to inject an object in a controller and you particularly want to you use xml,then instead of component scanning of Controller you should create a bean of the controller class of singleton scope in the application context.
Your controller class need not be annotated with #Controller.
you then have to you extend some Controller also like AbstractCommandController, AbstractController, AbstractFormController, AbstractWizardFormController, BaseCommandController, CancellableFormController, MultiActionController SimpleFormController, UrlFilenameViewController
Now to inject a particular object you can use Either Constructor and Setter based injection.
or you can use Autowring by name or type to auto inject the object.
Make sure that you have also declared the bean of that object also in Application Context.
After a DispatcherServlet has received a request and has done its work to resolve locales, themes and suchlike, it then tries to resolve a Controller, using a HandlerMapping. When a Controller has been found to handle the request, the handleRequest method of the located Controller will be invoked; the located Controller is then responsible for handling the actual request and - if applicable - returning an appropriate ModelAndView.
Thats it.
Actually, injection with xml and annotation is same behind the scene. Xml is old fashion while annotations are newer.
Basically, there are 2 types of injection types.
byName
Autowiring by property name. Spring container looks at the properties
of the beans on which autowire attribute is set to byName in the XML
configuration file. It then tries to match and wire its properties
with the beans defined by the same names in the configuration file.
You can give explicit names to beans both with xml and annotation.
#Service("BeanName")
#Component("BeanName")
#Controller("BeanName")
<bean name="BeanName" class="someclass"></bean>
and inject beans by using #Qualifier annotation.
#Autowired
#Qualifier("BeanName")
and with xml
<bean id="MyBean2" class="MyBean2 class">
<property name="Property of MyBean2 which refers to injecting bean" ref="BeanName" />
</bean>
byType
Autowiring by property datatype. Spring container looks at the
properties of the beans on which autowire attribute is set to byType
in the XML configuration file. It then tries to match and wire a
property if its type matches with exactly one of the beans name in
configuration file. If more than one such beans exists, a fatal
exception is thrown.
Default auto wiring mode is byType, so spring will look for matching type in auto wiring. However, older versions of Spring has default behavior none on injection. If you want to inject byType using xml, you should tell spring contaioner explicitly.
For example MyBean2 has a reference to MyBean, by setting autowired attribute to byType it handles injection automatically.
<bean id="MyBean" class="MyBean class">
<property name="Property of MyBean2 which refers to injecting bean" ref="BeanName" />
</bean>
<bean id="MyBean2" class="MyBean2 class"
autowire="byType">
</bean>
It also depends on where the injection take place in your code. There are 2 types, setter getter injection and constructor injection.
Note : There is no difference in #Controller since they are already in spring context.
See also
Spring Beans Auto wiring
I ran into such problem. I was getting "Ambiguous mapping found". (I use xml configuration as well and i am injecting a bean into my controller)
Then looking at my console i realized that my controller was being instantiated twice.
In more detailed look i noticed that my annotation
#Controller(value = "aController")
(Note value = "aController")
was different from my xml configuration where i was instatiating the same controller with different bean id
<bean id="aControleRRRRR" class="package.ControllerClassName"
p:property-ref="beanToInject" />
(Note id="aControleRRRRR")
So in conclusion your #Controller name (value = "aController") needs to be exactly the same as the name you give in the XML configuration (id="aControleRRRRR"), so that Spring can manage to distinct that they refer to the same bean (instance)
Hope this helps
I have a spring component which was used as a flex-blazeds endpoint (using #RemotingDestination) and I now need to reuse it as a REST endpoint.
What I did was create an additional rest servlet (of type DispatcherServlet of courser) in addition to the existing blaze-ds servlet I had.
I then wanted to access the same components using REST (hence my previous question) and I found that I'm getting a 404.
My rest-servlet.xml configuration file looked something like:
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter" />
</list>
</property>
</bean>
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
</bean>
And my ContextLoaderListener uses all my spring context files, which included the compontent-scan of those components.
Since the flex-servlet had no problem accessing these #Component beans which were scanned by the global context I assumed that the rest-servlet will also had access to them and I just need to add the annotations to the components.
The strange part was that when I explicitely added the component-scan for the package where these components reside then the rest call worked.
This meant that these component beans were being created twice, once for the global context (as it scans a config file containing this scan for the flex servlet) and one for the rest-servlet context (I verified this with a simple static counter and a lock on the class).
My question is why can't the rest-servlet see the beans the flex-servlet can?
While it's true that the servlet appcontext can access the beans from the ContextLoaderListener appcontext, those beans will not be consulted when mapping HTTP calls to controllers. All controller beans must be declared (or scanned) directly in the servlet's appcontext, else they will be ignored.
I suggest that you separate the REST entry point annotations (i.e. #RequestMapping) from your BlazeDS ones. For example, take your UserService class from your other post: create a UserController class, put the REST annotations on that, and delegate from UserController to UserService. UserController would be declared in the servlet app context, and injected with the UserService from the ContextLoaderListener context.
You need to use Spring Web context and define a DispatcherServlet, which will be a child context for the one loaded by ContextLoaderListener.
It is DistpatcherServlet that should load your rest-servlet.xml, not ContextLoaderListener. Otherwise, the guys whom you call "servlets" and who, in fact, I assume, are controllers, just won't get the requests from your client.
You can read about all this stuff here: http://static.springsource.org/spring/docs/3.1.0.RC1/spring-framework-reference/html/mvc.html
This is a standard way of doing Web-related things in Spring, and you definetely need to follow it.
To be exact, how can I get the value of the <display-name> tag under the <web-app> tag stored in an application's web.xml in a Spring application context configuration XML file.
Ideally I would like something like the following...
<bean><property value="${servletContext.servletContextName}/></bean>
It seem like ServletContext.getServletContextName() does what I want but I can't seem to figure out how to get a handle on that in the Spring application context file.
Ok, the answer is trivial in Spring 3.0.x. Per the documentation for ServletContextFactory
Deprecated. as of Spring 3.0, since "servletContext" is now available as a default bean in every WebApplicationContext
So I decided to try the following and it worked!
<bean><property value="#{servletContext.servletContextName}/></bean>
Since servletContext object is implicitly defined we can access it via Spring EL using the #{} syntax.
I don't think you can do this via the XML config.
You can autowire a bean to receive the ServletContext object (or implement ServletContextAware), and fetch it from that programmatically, but I don't think the XML expressions have any visibility of it.
Maybe try the Expression Language?
<bean>
<property value="#{T(javax.servlet.ServletContext).getServletContextName()}"/>
</bean>
I suspect that would print null if it works though, since there is no context yet.