I'm using Spring MVC with Freemarker as view technologie. I have a TemplateDirectiveModel object which needs to access Spring's RequestContext within the execute method. Currently I do it like this:
public class MyDirective implements TemplateDirectiveModel
{
public void execute(Environment env, Map params, TemplateModel[] loopVars,
TemplateDirectiveBody body) throws TemplateException, IOException
{
StringModel model = (StringModel) env.getGlobalVariable("springMacroRequestContext");
RequestContext requestContext = (RequestContext) model.getWrappedObject();
}
}
But I can't believe that this is the right way to do it. I have the feeling I missed something important. Maybe there are special classes and annotations for handling Freemarker direcives in Spring? Maybe I can let Spring inject something into the directive class with which I can access Springs request scope?
You could subclass FreeMarkerConfigurer, overriding its postProcessConfiguration(Configuration config)method.
Your implementation would just put a request-aware dependency in the configuration, as a shared variable for example (as preconised by the FM documentation).
Should do the trick, Spring-style...
There is an easier way to do this. If you are already using spring's FreeMarkerConfigurer, you can hand it a map of variables:
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"
p:templateLoaderPath="/some_path_here">
<property name="freemarkerVariables">
<map>
<entry key='macroName' value-ref="templateModelRef" />
</map>
</property>
</bean>
<bean id="templateModelRef" class="...class..extends TemplateModel">
<property name="someResource" value-ref="resourceRef"/>
</bean>
Now at least in a class that extends TemplateDirectiveModel's execute method you have access to that injected property.
public class MyDirective extends TemplateDirectiveModel {
private MyResource someResource;
#Override
public void execute(Environment env, Map params, TemplateModel[] loopVars,TemplateDirectiveBody body) throws TemplateException, IOException {
StringModel sharedVariable = (StringModel)env.getConfiguration().getSharedVariable("beanName");
MyClass sweetness = (MyClass)sharedVariable.getWrappedObject();
}
}
Now in your .ftl you can use:
<#macroName />
and it will have spring dependencies auto injected.
Related
i have requirement to replace private method of spring bean, can i achieve through spring replace.
My Code :
Replacer Class :
public class PrivateCarRep extends Car implements MethodReplacer{
#Override
public Object reimplement(Object obj, Method method, Object[] args) throws
Throwable {
// new property of Car.breaks() method.
System.out.println("New privateBreaksIs Done from Shiv");
return obj;
}
}
Car.java
package org.websparrow.beans;
public class Car {
private void privateBreaks() {
System.out.println("Old car break. privateBreaks");
}
}
My Spring Configuration:
<bean id="PrivateCarRep" class="org.websparrow.beans.PrivateCarRep"/>
<bean id="car" class="org.websparrow.beans.Car">
<replaced-method name="privateBreaks" replacer="PrivateCarRep" />
</bean>
Dear All,
i already know that i can't replace private method through spring replacer but is there any workaround for this in spring..
You need to define PrivateCarRep as a bean:
<bean id="privateCarReplacer" class="com.xx.yy.zz.PrivateCarRep" />
<bean id="car" class="org.websparrow.beans.Car">
<replaced-method name="privateBreaks" replacer="privateCarReplacer" />
</bean>
I'm afraid you can't do that,I thing the method should be be protected or public.
How can we switch between different Implementations in Spring Context XML with an Boolean?
for example:
<bean id="detailsController" class="com.something.detailsController" >
if true then
<property name="dao" ref="firstDao"/>
else
<property name="dao" ref="secoundDao"/>
I know in Spring3 we can work with profiles
You could do that by modifying your Java code and use Spring EL together with ApplicationAware and InitializingBean.
public class DetailsController implements ApplicationContextAware, InitializingBean {
private DetailsControllerDAO dao;
private String daoName;
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void afterPropertiesSet() {
dao = applicationContext.getBean(daoName);
}
public void setDaoName(String daoName) {
this.daoName = daoName;
}
}
In XML:
<bean id="detailsController" class="com.something.detailsController">
<property name="daoName" value="#{myCondition ? 'firstDao' : 'secondDao'}" />
</bean>
Of course, this solution has the disadvantage to add dependency to Spring code in your controller. To avoid that, you could move that code in a proxy class, as described by Guillaume Darmont.
I dont think this can be done at the XML level.
Spring really cannot do that. See the bean lifecycle. Been classes are created, than properties are injected and than afterPropertiesSet() or #PostConstructor methods are invoked. Of course when I omit lazy initialized beans.
But if you want for testing etc. and so you need just the firstDao or the secondDao in your application at the sametime that depends just on your settings, you can use a bean factory. The bean factory creates your bean as you want. I also use it for to split development environment, test environment and production environment.
package com.dummyexample.config;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Factory bean to create real or test dao.
* The result depends on realDaoEnabled configuration parameter.
*
* #author Martin Strejc
*/
#Configuration
public class DaoBeanFactory {
// mapping to servlet context configuration
#Resource(mappedName = "realDaoEnabled")
private Boolean realDaoEnabled = true;
// TestDao extends or implements Dao
#Autowired
private TestDao testDao;
// ProdDao extends or implements Dao
#Autowired
private ProdDao prodDao;
public DaoBeanFactory() {
}
#Bean(name="dao")
public Dao getDao() {
if(realDaoEnabled) {
return prodDao;
}
return testDao;
}
}
Since your DAOs are exchangeable, they inherits the same type (abstract class or interface). Thus you can write a RoutingDetailsControllerDAO.
Let's say that your common interface is named DetailsControllerDAO, with two methods getDetails and getMoreDetails inside, the code would be :
public class RoutingDetailsControllerDAO implements DetailsControllerDAO {
private DetailsControllerDAO firstDAO;
private DetailsControllerDAO secondDAO;
protected DetailsControllerDAO getDAOToUse() {
return YOUR_BOOLEAN_CONDITION ? firstDAO : secondDAO;
}
#Override
public Details getDetails() {
return getDAOToUse().getDetails();
}
#Override
public Details getMoreDetails() {
return getDAOToUse().getMoreDetails();
}
// Insert firstDAO and secondDAO setters below
...
}
Your Spring XML config is now :
<bean id="detailsController" class="com.something.detailsController" >
<property name="dao" ref="routingDetailsControllerDAO"/>
</bean>
<bean id="routingDetailsControllerDAO" class="com.something.RoutingDetailsControllerDAO">
<property name="firstDao" ref="firstDao"/>
<property name="secondDao" ref="secondDao"/>
</bean>
Few possibilities:
You can either use profiles (<beans profiles="profileOne">).
You can use FactoryBean to create the correct DAO
You can use SPeL
The last one is the easiest:
<bean id="detailsController" class="com.something.detailsController">
<property name="dao" ref="#{condition ? 'firstDao' : 'secondDao'}" />
</bean>
Of course you can load bean name from properties file via property configurer:
<bean id="detailsController" class="com.something.detailsController">
<property name="dao" ref="${bean.name.from.properties.file}" />
</bean>
I have log4j DailyRollingFileAppender class in which setFile() method I need to check database value to decide which file to used for logging.
DailyRollingFileAppender class
public void setFileName()
{
isLoginEnabled = authenticationManager.checkLoginLogging();
}
Here 'authenticationManager' is object of class used to make database call using spring dependency injection feature.
spring-beans.xml
<bean id="dailyRollingFileAppender" class="com.common.util.DailyRollingFileAppender">
<property name="authenticationManager">
<ref bean="authenticationManager"/>
</property>
</bean>
<bean id="authenticationManager" class="com.security.impl.AuthenticationManagerImpl">
<property name="userService">
<ref bean="userService"/>
</property>
</bean>
Now when I start my application log4j gets initiated first and since spring-beans is yet to invoked it throws NullPointerException in method setFileName().
So is there a way I can make call to 'authenticationManager.checkLoginLogging();' from DailyFileAppender class so that when log4j loads it should able to get database value?
A few years late, but I hope this is of help to someone.
I was after similar functionality - I have a custom appender, and i wanted to use an autowired bean to perform some logging using a service we'd built. By making the appender implement the ApplicationContextAware interface, and making the field that i'd normally autowire static, i'm able to inject the spring-controlled bean into the instance of the appender that log4j has instantiated.
#Component
public class SslErrorSecurityAppender extends AppenderSkeleton implements ApplicationContextAware {
private static SecurityLogger securityLogger;
#Override
protected void append(LoggingEvent event) {
securityLogger.log(new SslExceptionSecurityEvent(SecurityEventType.AUTHENTICATION_FAILED, event.getThrowableInformation().getThrowable(), "Unexpected SSL error"));
}
#Override
public boolean requiresLayout() {
return false;
}
#Override
public synchronized void close() {
this.closed = true;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) {
if (applicationContext.getAutowireCapableBeanFactory().getBean("securityLogger") != null) {
securityLogger = (SecurityLogger) applicationContext.getAutowireCapableBeanFactory().getBean("securityLogger");
}
}
}
I have a set of classes with a complex initialization scheme. Basically, I start with the interface I need to get a hold of, and then make a bunch of calls, and I end up with an object that implements that interface.
In order to handle this, I made a factory class that can, given an interface, produce the final object. I made this factory into a bean, and in XML I specified my various service beans as being instantiated via this factory object with a parameter of the interface that they will implement.
This works great, and I totally get exactly the beans I need. Unfortunately, I would like to access them from my controller classes, which are discovered via component scanning. I use #Autowired here, and it appears that Spring has no idea what type of object these are, and since #Autowired works by type, I'm SOL.
Using #Resource(name="beanName") here would work perfectly, however it seems odd to use #Resource for some beans and #Autowired for others.
Is there a way to get Spring to know what interface the factory will be creating for each of these beans without having a different factory method for each type?
I'm using Spring 2.5.6, by the way, otherwise I'd just JavaConfig the whole thing and forget about it.
Factory class:
<T extends Client> T buildService(Class<T> clientClass) {
//Do lots of stuff with client class and return an object of clientClass.
}
app context:
<bean id="serviceFactoryBean" class="com.captainAwesomePants.FancyFactory" />
<bean id="userService" factory-bean="serviceFactoryBean" factory-method="buildService">
<constructor-arg value="com.captain.services.UserServiceInterface" />
</bean>
<bean id="scoreService" factory-bean="serviceFactoryBean" factory-method="buildService">
<constructor-arg value="com.captain.services.ScoreServiceInterface" />
</bean>
my controller:
public class HomepageController {
//This doesn't work
#Autowired #Qualifier("userService") UserServiceInterface userService;
//This does
#Resource(name="scoreService") ScoreServiceInterface scoreService;
}
I suggest you take the factory pattern one step further and implement your factories as Spring FactoryBean classes. The FactoryBean interface has a getObjectType() method which the contain calls to discover what type the factory will return. This gives your autowiring something to get its teeth into, as long as your factory returns a sensible value.
I had a similar problem, but for me I wanted to use a single factory for creating mocked-out implementations of my auto-wired dependencies using JMockit (the testing framework that I am required to use).
After finding no satisfactory solution on the interwebs, I threw together a simple solution that is working really well for me.
My solution uses a Spring FactoryBean as well, but it only uses a single factory bean for creating all my beans (which the original asker seems to have wished to do).
My solution was to implement a factory-of-factories meta-factory that serves-up FactoryBean wrappers around the real, single factory.
Here is the Java for my JMockit mock bean factory:
public class MockBeanFactory<C> implements FactoryBean<C> {
private Class<C> mockBeanType;
protected MockBeanFactory(){}
protected <C> C create(Class<C> mockClass) {
return Mockit.newEmptyProxy(mockClass);
}
#Override
public C getObject() throws Exception {
return create(mockBeanType);
}
#Override
public Class<C> getObjectType() {
return mockBeanType;
}
#Override
public boolean isSingleton() {
return true;
}
public static class MetaFactory {
public <C> MockBeanFactory<C> createFactory(Class<C> mockBeanType) {
MockBeanFactory<C> factory = new MockBeanFactory<C>();
factory.mockBeanType = mockBeanType;
return factory;
}
}
}
And then in the Spring context XML file, you just can simply create the meta factory that creates the specific bean-type factories:
<bean id="metaFactory" class="com.stackoverflow.MockBeanFactory$MetaFactory"/>
<bean factory-bean="metaFactory" factory-method="createFactory">
<constructor-arg name="mockBeanType" value="com.stackoverflow.YourService"/>
</bean>
To make this work for the original asker's situation, it could be tweaked to make the FactoryBeans into wrappers/adapter for the serviceFactoryBean:
public class FancyFactoryAdapter<C> implements FactoryBean<C> {
private Class<C> clientClass;
private FancyFactory serviceFactoryBean;
protected FancyFactoryAdapter(){}
#Override
public C getObject() throws Exception {
return serviceFactoryBean.buildService(clientClass);
}
#Override
public Class<C> getObjectType() {
return clientClass;
}
#Override
public boolean isSingleton() {
return true;
}
public static class MetaFactory {
#Autowired FancyFactory serviceFactoryBean;
public <C> FancyFactoryAdapter<C> createFactory(Class<C> clientClass) {
FancyFactoryAdapter<C> factory = new FancyFactoryAdapter<C>();
factory.clientClass = clientClass;
factory.serviceFactoryBean = serviceFactoryBean;
return factory;
}
}
}
Then in the XML (notice the userServiceFactory id and the userService bean id are necessary only to work with the #Qualifier annotation):
<bean id="metaFactory" class="com.stackoverflow.FancyFactoryAdapter$MetaFactory"/>
<bean id="userServiceFactory" factory-bean="metaFactory" factory-method="createFactory">
<constructor-arg name="clientClass" value="com.captain.services.UserServiceInterface"/>
</bean>
<bean id="userService" factory-bean="userServiceFactory"/>
<bean id="scoreServiceFactory" factory-bean="metaFactory" factory-method="createFactory">
<constructor-arg name="clientClass" value="com.captain.services.ScoreServiceInterface"/>
</bean>
<bean id="scoreService" factory-bean="scoreServiceFactory"/>
And that's it, just one little Java class and a smidge of boiler-plate configuration and your custom bean factory can create all of your beans and have Spring resolve them successfully.
You should be able to achieve this using:
<bean id="myCreatedObjectBean" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass">
<value>com.mycompany.MyFactoryClass</value>
</property>
<property name="targetMethod">
<value>myFactoryMethod</value>
</property>
</bean>
Then you can use either #Resource or #Autowired + #Qualifier to inject into your object directly.
Is there any way to use Lookup Method Injection using annotations?
Given the following class:
#Service
public abstract class A {
protected abstract createB();
}
In order to get it to work I have to declare in spring applicationContext.xml the following:
<bean id="b" class="com.xyz.B">
</bean>
<bean id="a" class="com.xyz.A">
<lookup-method name="createB" bean="b"/>
</bean>
Even though I am using <context:component-scan base> I have to declare it also in the XML. Not a good approach I think.
How to do it with annotations?
It is possible to use javax.inject.Provider. All thanks go to Phil Webb.
public class MySingleton {
#Autowired
private Provider<MyPrototype> myPrototype;
public void operation() {
MyPrototype instance = myPrototype.get();
// do something with the instance
}
}
It is also possible with org.springframework.beans.factory.ObjectFactory if you want to keep up with Spring API
public class MySingleton {
#Autowired
private ObjectFactory<MyPrototype> myPrototypeFactory;
public void operation() {
MyPrototype instance = myPrototypeFactory.getObject();
// do something with the instance
}
}
you can read more in the documentation.
It is implemented only with Spring >= 4.1 See the ticket.
Finally introduced as #Lookup annotation. Here is discussion on how to use it.