How do I get Web.xml context-param values in controller action method? - spring-mvc

This feels like a basic question, but I haven't had much luck Googling.
My app connects to an SMTP server and sends mail through it. I need this SMTP server to be configurable based on which environment the app is deployed to.
How can I specify the specify the SMTP server name in my web.xml config file and access it from my Spring MVC 3.0 controller?
The controller does not extend or implement anything. It is completely annotation driven with #Controller and #RequestMapping. From what I have seen online, people access context-params via the servlet API. Being annotation driven, I do not have access to the servlet object.

I solved this.
Make your controller implement ServletContextAware, which requires a method called
setServletContext(ServletContext servletContext)
Spring MVC will inject the servlet context into this method if your controller is ServletContextAware.
Create a private variable on your controller to store the servletController that is injected into the above method. You can now use servletContext just as you would if you were using a regular servlet.
hth.

Adding an instance of Servletcontext and autowiring it worked for me
#Controller
public MyController {
// other instances relevant to your requirement
#Autowired
private ServletContext sCtx;
//other methods relevant to your requirement
}

I suppose following also should work:
void action(final HttpServletRequest request) {
final paramValue = request.getSession().getServletContext().getInitParameter("paramName");
...
}

Related

Spring MVC #PreDestroy method not working

I am using #controller in my controller class which internally creates bean. For this controller I need to use #postConstruct and #preDestroy methods, #postConstruct is working fine but #preDestroy is not working. It means Bean is not destroying. So how can I destroy bean in spring MVC(annotation based)(I am not using ApplicationContext).
Correct me if my assumption was wrong.
WHen you say you dont use application context, do you mean to say that you are not using xml based configuration and are using java annotation config?
With spring mvc controllers, #PreDestroy annotated method will be called on session expiry (unless it's prototype scoped)
Here is a post #PreDestroy on Session-scoped Spring MVC Controllers
Here is a good explantation on spring bean life cycle http://www.journaldev.com/2637/spring-bean-life-cycle-methods-initializingbean-disposablebean-postconstruct-predestroy-aware-interfaces
I found out that if I set the bean scope to singleton, I can get PreDestroy called but not if I set it to prototype.

How to create transaction to save several objects in the database?

I have a controller in my Spring Boot application.
The controller receives json from POST request. Parsing the json I need to create three new objects in the database:
accountRepository.save(account);
containerRepository.save(userContainer);
containerRepository.save(operatorContainer);
Saving this three objects to the database should be in one transaction.
For now I'm using #Transactional on controller method. However it seems the bad practice to mark controllers by #Transaction annotation.
Should I create service where I would save three objects passed as arguments and mark the service #Transactional?
What is the best way to do it? Maybe someone can provide an example?
The best place for this would be in a method in your service layer.
#Service
public class MyService {
#Autowired
AccountRepository accountRepository;
#Autowired
ContainerRepository containerRepository;
#Transactional
public void save(Account account, Container userContainer, Container operatorContainer) {
accountRepository.save(account);
containerRepository.save(userContainer);
containerRepository.save(operatorContainer);
}
}
Then wire up the service in your controller.

Mixsing #Transactional & #Controller Semantics on a REST Api

I'd like to expose the backend as 'Resources' (like Restlet) and eliminate the Service Layer so a Rest Resource can direclty interact with a Dao. This way the Resource is the contract and not the Interface.
Is there a problem using #Transactional semantics on a Spring MVC 3 Controller if the transactions are managed locally by Spring? Any gotchas with Rollback and catching exceptions?
#RequestMapping(value = "/user/{userId}", method = RequestMethod.PUT)
#ResponseStatus(HttpStatus.OK)
#Transactional
public void updateUser(#PathVariable Long userId, #RequestBody ProfileUser user) {
// dao update
}
spring config:
<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
I think you could run into issues here. By default Spring will use a JDK dynamic proxy to apply the transactional behaviour to your method. This relies on your controller implementing a suitable interface i.e. one which exposes an updateUser method. There is an excellent blog post on the Spring blog.
It is likely that you'll see an error due to Spring failing to find the method on the proxy.
You can use your above approach if you tell Spring to use CGLIB based proxies. This is described in the documentation here.

Write Junit tests for Spring MVC application which internally relies upon ContextLoader.getCurrentWebApplicationContext()

I'm trying to write integration tests for a controller in our spring mvc application. The controller invokes a service class which in turn invokes a dao to read/write data from the repository. The DAO needs to lookup some configuration. The configuration bean is defined in WEB-INF/applicationContext.xml.
I'm using something like this:
Configuration config =(Configuration)ContextLoader.getCurrentWebApplicationContext().getBean("config");
private String namespace = config.getProperty("someproperty");
The properties are stored in zookeeper so I'm not using spring's property management artifacts.
The problem is that while running the JUnit test ContextLoader.getCurrentWebApplicationContext() always returns null.
I have so far looked at the following approaches:
1. Ted Young's approach ( just google search for spring mvc integration tests ted young)
2. https://github.com/SpringSource/spring-test-mvc
3. this site.. questions/8464919/unit-testing-a-servlet-that-depends-on-springs-webapplicationcontextutils-getre
4. Use Selenium/JWebunit
5. http://confluence.highsource.org/display/Hifaces20/Hifaces20+Testing+package+-+testing%2C+tracing+and+debugging+web+applications+with+Jetty
1 doesn't resolve this issue. WebApplicationContext stays null
2 states that support for WebApplicationContext will be available in spring 3.2
3. I don't understand this. Where do I get the testApplicationContext and the getServletContext() from?
4. I do not want to go this way as this is completely blackbox testing.
5. I'm currently looking at 5. But this requires starting up a servlet container. Is there no other alternative?
I will appreciate any help you can provide.
Thanks
PixalSoft
#Ted Young SO didn't allow me to finish what I was saying.With loader=MockWebApplicationContextLoader,isn't it supposed to be available as the default contextloader exactly as the Spring ContextLoader behaves when the webapp is initialized by a servletcontainer?Is there something special I need to do get a handle on the MockWebApplicationContextLoader?Injecting the config object works for singleton objects. But all can't be singleton. Passing a config object in every constructor sounds too tedious. For now, I have created a class which has a static config object, autowired via a setter method. I will take a look at ApplicationContextAware.Many thx
You have to manually add the WebApplication context to ContextLoderListner.
This will work.
#ContextConfiguration(locations = "classpath:module-test-beans.xml")
#WebAppConfiguration
public class SampleTest extends AbstractTestNGSpringContextTests {
#Autowired
private WebApplicationContext wac;
#BeforeClass
public void setUp() throws ServletException {
MockServletContext sc = new MockServletContext("");
ServletContextListener listener = new ContextLoaderListener(wac);
ServletContextEvent event = new ServletContextEvent(sc);
listener.contextInitialized(event);
}
#Test
public void testMe() {
Assert.assertFalse(ContextLoader.getCurrentWebApplicationContext() == null);
}
}
Add the following code at the beginning of your junit test:
MockServletContext sc = new MockServletContext("");
sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
"/applicationContext-test.xml"); // <== Customize with your paths
ServletContextListener listener = new ContextLoaderListener();
ServletContextEvent event = new ServletContextEvent(sc);
listener.contextInitialized(event);
If you need to add more than one xml for the context path just put them in the same string separated with spaces, like this:
sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
"/applicationContext-test.xml /applicationContext-other.xml");
The reason why ContextLoader.getCurrentWebApplicationContext is returning null is because, when you use my MockWebApplicationContextLoader, you are neither using a web application context nor that particular ContextLoader implementation.
Since your repository is managed by Spring, why do not you simply inject the config object into the repository? Injecting the config object is the most appropriate way to get access to it. You can then initialize your namespace property in a method annotated with #PostConstruct.
Alternatively, your DOA could implement ApplicationContextAware to receive a copy of the application context during construction.
store your property file in your classpath.
now access that property in your controller class like this:
/*to access your filename.properties file */
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("filename.properties"));
String sServerLocation = properties.getProperty("key");
now you can access your property file.
I am sure it will work.

When, exactly, #Inject annotation initiates injection of SessionScoped bean in Servlet?

I need to modify a user session object (SessionScoped bean - CDI) in a Servlet, so I have to obtain that bean somehow. I used injection in the following way:
#Inject
private UserSession user;
where UserSession is the SessionScoped CDI bean. user methods are called from either doPost or doGet servlet methods.
This works perfectly; every time the #Inject annotation injects the appropriate UserSession bean, but I don't understand how this behavior is achieved.
I assumed that the beans, annotated with #Inject, are injected only once (when the object - Servlet instance in this case - is created), but it is obviously a wrong presumption.
So, when are these beans injected into the servlet? Per request? And how does this approach avoids conflicts (one servlet instance - multiple threads to deal with it) when there are multiple UserSession objects?
The CDI uses the proxy pattern. The injected instance is actually not the real instance, but a proxy which locates the real instance depending on the current context and delegates all methods to it (like as how EJBs work). The autogenerated class of your UserSession bean looks roughly like this:
public UserSessionCDIProxy extends UserSession implements Serializable {
public String getSomeProperty() {
UserSession instance = CDI.resolveItSomehow();
return instance.getSomeProperty();
}
public void setSomeProperty(String someProperty) {
UserSession instance = CDI.resolveItSomehow();
instance.setSomeProperty(someProperty);
}
}
This mechanism allows you to inject instances of a narrower scope in instances of a broader scope and allows you to still get the expected instance in the current context. The standard JSF #ManagedProperty annotation doesn't support it, simply because it does not use a proxy, but injects the desired instance directly. That's why it's not possible to inject something of a narrower scope by #ManagedProperty.
See also:
Backing beans (#ManagedBean) or CDI Beans (#Named)?
Get JSF managed bean by name in any Servlet related class
When using #EJB, does each managed bean get its own #EJB instance?
How to choose the right bean scope?
Your answer lies in the C of CDI, which stands for Contexts.
What happens is that not the actual bean is injected, but a proxy. This proxy is contextual and resolves to the actual session scoped bean depending on the context of the caller on who's behalf the proxy is executed.

Resources