How to pass Injected/Autowired object from Spring to ManagedBean? - spring

I am working on a project with Spring and EJB/Primefaces and I want to pass values from the spring context to a managed bean. I will demonstrate with a sample code to clarify further.
Let's say we have the following domain class (I keep it simple for better readability):
public class Store {
#JsonProperty("store_name")
private String storeName;
//constructors, getters and setters...
}
The reason of #JsonProperty is because I am getting this value from an other application that POSTs a Json to the following Controller:
#Controller
#RequestMapping("/store")
public class StoreController {
#Autowired
private Store store;
#RequestMapping(method = RequestMethod.POST)
public String getStoreResponse(#RequestBody String store) throws JsonParseException, JsonMappingException, IOException {
ObjectMapper mapper = new ObjectMapper();
LOGGER.info("Store Before Post: " + store.getName());
store = mapper.readValue(request, Store.class);
LOGGER.info("Store After Post: " + store.getName());
return "store";
}
}
I have configured the store bean at a BeanConfig class:
#Configuration
public class BeanConfig {
#Bean(name = "store")
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Store store() {
Store store = new Store();
store.setName("Test Store Name");
return store;
}
}
This is my managed bean:
#ManagedBean
#SessionScoped
public class StoreView extends SpringBeanAutowiringSupport {
private static final Logger LOGGER = LoggerFactory.getLogger(Store.class);
//#ManagedProperty("#{store}")
#Autowired
private Store store;
public void test() {
LOGGER.info("TEST " + store.getName());
}
//getters and setters
}
finally my xhtml:
<h:panelGrid columns="3">
<p:outputLabel for="j_store" value="#{messages['storeview.name']}" />
<p:inputText id="j_store" value="#{storeView.store.name}" />
<p:message for="j_store" />
<h:panelGroup />
<p:commandButton value="#{messages['storeview.test']}" action="#{storeView.test}" update="#form" ajax="false" />
</h:panelGrid>
When I am posting sample data using postman, the first time, the logger outputs:
10:35:57,433 INFO [com.store.test.controllers.StoreController] (default task-2) Store Before Post: Test Store Name
10:35:57,488 INFO [com.store.test.controllers.StoreController] (default task-2) Store After Post: posted store name
and if I continue calling the controller I keep getting the "posted store name", so it has kept the value.
But when I am going to the store.xhtml and hit the test button to submit the form, it still has the value set in the bean configuration file ("Test Store Name") and from that point on it keeps the value that I submit in the inputText.
I suspect it has to do with Spring and Faces context, I do not know if what I want to do is possible. If it is, please point out what should I change to make it work, otherwise, please provide me with an alternative solution.
Thanks in advance.

You are mixing #Autowired and #ManagedBean annotations.
#Autowired is managed by Spring while #ManagedBean is managed by JSF.
That means that probably you will have 2 instances of Store, the one modified by controller is not the same instance used by the managed bean.
You should annotate as #ManagedProperty("#{store}") your store attribute in managed bean and define getter and setter.
To get it to work you also must define spring Expression Language resolver in faces-config.xml
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
Since jsf session is different from mvc session, you also have to use singleton scope in the definition of Store object.
#Scope(value = "singleton"........

Related

How to add object to session in spring app

I have a kind of online store in Spring. I want to create a shopping cart for each new user who visits the site and stored it in the session. How can this be done? It's just that I've never worked with sessions in Spring. Perhaps there is a good resource to study this stuff.
#Controller
class example{
#RequestMapping("/")
public String test(HttpSession session){
session.addAttribute("cart",new Cart());
}
}
Make your controller session scoped
#Controller
#Scope("session")
then add one attribute to session
#RequestMapping(method = RequestMethod.GET)
public String testMestod(HttpServletRequest request){
ShoppingCart cart = (ShoppingCart)request.getSession().setAttribute("cart",valueOfCart);
return "testJsp";
}
then Scope the user object that should be in session every time:
#Component
#Scope("session")
public class User
{
String user;
/*getter setter*/
}
then inject class in each controller that you want
#Autowired
private User user
The AOP proxy injection : in spring -xml:
<bean id="user" class="com.User" scope="session">
<aop:scoped-proxy/>
</bean>
refer:How to use Session attributes in Spring-mvc

I cannot keep the bean stateful when the spring bean is value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS

here is the spring bean:
#Repository
#Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class TestBean {
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
and here is the very simple codes to access the bean:
TestBean testBean = (TestBean) SpringContext.getBean("testBean");//#1
testBean.setText("aaaaa"); //#2
System.out.println(testBean.getText()); //#3
and the result is that testBean.getText() is null.
When i try to debug the codes, i found that the instance of testBean in #2 is not the same instance as that in #3. for example:
#2: TestBean#988995e
#3: TestBean#69bf7e71
Any help? Thanks!
SpringContext.getBean("testBean") returns the Proxy object for you. And any method invocation is delegates to the DynamicAdvisedInterceptor. Which, in turn, does target = getTarget(); to generate CglibMethodInvocation. And the magic is hidden in that getTarget(), which is SimpleBeanTargetSource for the prototype beans and has a code:
public Object getTarget() throws Exception {
return getBeanFactory().getBean(getTargetBeanName());
}
So, any method invocation on the TestBean asks BeanFactory for the new instance of that class. That's why your setText("aaaaa") isn't visible for testBean.getText(), because each method is for its TestBean object, not the same.
Such prototype objects can't be changed from the code manually. They are managed by ApplicationContext and only the last one can populate their internal state. From the code you can only read them.
And if your TestBean is populated with the same values you will get the same from the testBean.getText(), but all those call will be done for different objects.

How to get properties in JSP files using spring mvc 3

I am very new to spring mvc 3 annotation based application. I have two properties files -
WEB-INF\resources\general.properties,
WEB-INF\resources\jdbc_config.properties
Now I want to configure them through spring-servlet.xml. How I can achieve this?
In general.properties,
label.username = User Name:
label.password = Password:
label.address = Address:
...etc
jdbc_config.properties,
app.jdbc.driverClassName=com.mysql.jdbc.Driver
app.jdbc.url=jdbc:mysql://localhost:[port_number]/
app.jdbc.username=root
app.jdbc.password=pass
---etc
If I want to get label.username and app.jdbc.driverClassName in my jsp page, how do I code for them?
I also want to access these properties values from my service. How to get these property values using respective keys in method level in service class or controller class?
You need to distinguish between application properties (configuration) and localisation messages. Both use JAVA properties files, but they serve different purpose and are handled differently.
Note: I am using Java based Spring configuration in the examples bellow. The configuration can be easily made in XML as well. Just check Spring's JavaDoc and reference documentation.
Application Properties
Application properties should be loaded as property sources within your application context. This can be done via #PropertySource annotation on your #Configuration class:
#Configuration
#PropertySource("classpath:default-config.properties")
public class MyConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Then you can inject properties using #Value annotation:
#Value("${my.config.property}")
private String myProperty;
Localisation Messages
Localisation messages is a little bit different story. Messages are loaded as resource bundles and a special resolution process is in place for getting correct translation message for a specified locale.
In Spring, these messages are handled by MessageSources. You can define your own for example via ReloadableResourceBundleMessageSource:
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("/WEB-INF/messages/messages");
return messageSource;
}
You can access these messages from beans if you let Spring inject MessageSource:
#Autowired
private MessageSource messageSource;
public void myMethod() {
messageSource.getMessage("my.translation.code", null, LocaleContextHolder.getLocale());
}
And you can translate messages in your JSPs by using <spring:message> tag:
<spring:message code="my.translation.code" />
I ended up using Environment
Add these lines to config
#PropertySource("classpath:/configs/env.properties")
public class WebConfig extends WebMvcConfigurerAdapter{...}
You can get the properties from controller using autowired Environment
public class BaseController {
protected final Logger LOG = LoggerFactory.getLogger(this.getClass());
#Autowired
public Environment env;
#RequestMapping("/")
public String rootPage(ModelAndView modelAndView, HttpServletRequest request, HttpServletResponse response) {
LOG.debug(env.getProperty("download.path"));
return "main";
}
}
Firstly import spring tag lib:
<%# taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
Than import property from your application.properties
<spring:eval var="registration_url" expression="#environment.getProperty('service.registration.url')"/>
Than use your variable
test

Using JSF2 #ManagedProperty in Spring managed backing bean

I have a JSF backing bean that is Spring managed but I would like to be able to make use of the #ManagedProperty from JSF. The following does not work:
#Component
#Scope(Scopes.REQUEST)
public class MyRequestBean {
#ManagedProperty(value="#{param.bcIndex}")
private int bcIndex;
public int getBcIndex() {
return bcIndex;
}
public void setBcIndex(int bcIndex) {
this.bcIndex = bcIndex;
}
}
Suggestions?
Actually it is quite simple. I know of three ways to do your injection:
Use Spring's #Value annotation together with implicit El #{param} object:
#Value("#{param.bcIndex}")
private int bcIndex;
Make use of ExternalContext#getRequestParameterMap in a #PostConstruct / preRenderView listener:
//#PostConstruct
public void init() {
bcIndex = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("bcIndex");
}
Make a binding in your view utilizing <f:viewParam>:
<f:metadata>
<f:viewParam name="index" value="#{myRequestBean.bcIndex}" />
</f:metadata>

Accessing a session-scoped bean inside a controller

I'm experimenting with session-scoped beans in Spring 3. I have the following bean definition:
<bean id="userInfo" class="net.sandbox.sessionbeans.UserInfo" scope="session" />
Here is net.sandbox.controllers.RegistrationController, a controller class that needs access to this bean. I've taken out the imports for brevity's sake.
#Controller
#RequestMapping("/register")
public class RegistrationController {
private UserInfo userInfo; // This should reference the session-scoped bean
#RequestMapping(method = RequestMethod.GET)
public String showRegForm(Model model) {
RegistrationForm regForm = new RegistrationForm();
model.addAttribute("regform", regForm);
return "regform";
}
#RequestMapping(method = RequestMethod.POST)
public String validateForm(#Valid RegistrationForm regForm, BindingResult result, Model model) {
if (result.hasErrors()) {
return "regform";
}
userInfo.setUserName(regForm.getFirstName());
model.addAttribute("regform", regForm);
return "regsuccess";
}
}
Is there a way to automatically tie the session-scoped bean I defined to the member variable private UserInfo userInfo in RegistrationController?
Yes - see section 3.4.5.4 of the Spring manual, "Scoped beans as dependencies".
Briefly, you can ask Spring to wrap your session-scoped bean in a singleton proxy, which looks up the correct session when you invoke a method on the scoped bean. This is called a "scoped proxy", and uses the <aop:scoped-proxy> config macro. You can then inject the reference as you would any other (e.g. <property>, or #Autowired). See the above link for details.
By default, Spring creates a proxy by implementing an interface at run-time. So, the only methods available on the proxy are those defined in any interfaces UserInfo implements (if any). You may have to create a suitable interface that includes the setUserName() method.
Alternatively, you will need to force a CGI based proxy (the proxy is a sub-class of your class created at run-time so it doesn't need an interface). Specify:
<bean id="userInfo" class="net.sandbox.sessionbeans.UserInfo" scope="session" >
<aop:scoped-proxy proxy-target-class="true"/>
</bean>
About this comment:
I tried applying this technique. I put
inside the bean
definition and I #Autowired'd private
UserInfo userInfo. It seems to work,
but for some reason the bean's setter
function isn't executed properly...
i.imgur.com/zkxVA.png – Pieter 1 hour
ago
If you use interface-based proxies, the setter method is not available on the Proxy unless the interface has the setter method.
If you don't like XML, you can also use ObjectFactory<T> like this :
#RestController
public class MyController {
private final ObjectFactory<MySessionScopedComponent> OFSession;
#Autowired
public MyController(ObjectFactory<MySessionScopedComponent> OFSession) {
this.OFSession = OFSession;
}
#RequestMapping(path = "/path", method = RequestMethod.GET)
public String myMethod () {
MySessionScopedComponent sessionBean = OFSession.getObject();
// Do some stuff
return bean.myValue();
}
}
Note: Tested with Spring Boot 1.5.6 (Spring 4.3)

Resources