I'm using Spring Boot and have an external configuration file called application.yml.
In this file, suppose I have a property foo that takes a fully-qualified class name as value.
Using Java configuration, what is the typical way to create a bean of the type specified by the foo property?
I suppose that foo is implementing some known interface. Otherwise, it is kind of pointless to create a bean of an unknown Type.
Something like:
#Configuration
public class FooConfiguration {
#Value("foo.class-name") // ref to the key used in you application.yml
private String fooClassName;
#Bean
public FooInterface fooBean(){
FooInterface fooImpl = Class.forName(fooClassName).newInstance(); // concreet implemetation
return fooImpl;
}
}
I'm trying to add ConfigSlurper's ConfigObjectinto an application context Environment in order to provide configuration values to the context.
The MapPropertySorce itself only expects its values to be of type Object only. But in the end property resolution fails as the EnvironmentAccessor will try to cast each ConfigObject to String.
So basically the question is, is there support for non String property resource values? Any supporting classes there (different EnvironmentAccessor?)
class ConfigSlurperLearningSpec extends Specification {
def configurationResource = new ClassPathResource("/META-INF/de.troi/application.configuration")
ConfigObject configuration = new ConfigSlurper().parse(configurationResource.getURL())
def "use as application context property source"() {
expect:
AnnotationConfigApplicationContext context= new AnnotationConfigApplicationContext()
context.register(PropertySourceInjection)
context.getEnvironment().getPropertySources().addLast(new MapPropertySource("mapConfiguration", configuration))
context.refresh()
String configuredValue=context.getBean('testBean')
configuredValue=='create'
}
}
#Configuration
class PropertySourceInjection {
#Value("#{environment['entityManagerFactory']['jpaPropertyMap']['hibernate.hbm2ddl.auto']}")
Object hibernateHbm2ddlAuto;
#Bean
String testBean() {
return new String(hibernateHbm2ddlAuto.toString())
}
}
It is definitely possible to inject non-string objects via ConfigSlurper.
Take a look at (shameless plug) https://github.com/ctzen/slurper-configuration
I am looking for a way to store my object and it seems that the best approach is to use proxies. I found 2 annotation in the internet, which one should I use :
#Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
or
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS )
Moreover, is it true that the proxies is the best way to use than using #Component
#Scope("session") or using #SessionAttributes?
You'll need to understand what each of those annotations does to choose for yourself. See the javadoc, here. Continue for a more detailed explanation.
The first
#Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
creates
a JDK dynamic proxy implementing all interfaces exposed by the class of the target object
In other words, the proxy will be a subtype of the interfaces that the target object's class implements, but won't be a subclass of the target object's class itself.
Essentially Spring does the following
public class Example {
public static void main(String[] args) throws Exception {
Foo target = new Foo();
InvocationHandler proxyHandler = ... // some proxy specific logic, likely referencing the `target`
// works fine
Printable proxy = (Printable) Proxy.newProxyInstance(Example.class.getClassLoader(),
target.getClass().getInterfaces(), proxyHandler);
// not possible, ClassCastException
Foo foo = (Foo) proxy;
}
public static class Foo implements Printable {
#Override
public void print() {
}
}
public interface Printable {
void print();
}
}
The proxy returned won't be of type Foo and you therefore can't inject it into any targets of that type. For example, Spring will fail to inject it into a field like
#Autowired
private Foo foo;
but will successfully inject the proxy into a field like
#Autowired
private Printable printable;
All calls to the proxy will be handled by the InvocationHandler (which usually performs some use case specific logic then delegates to the target object).
The second annotation
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS )
creates
a class-based proxy (uses CGLIB).
In addition to interfaces, with CGLIB Spring will be able to create a proxy whose class is a subclass of the target's class. In essence, it does the following
Foo target = new Foo();
net.sf.cglib.proxy.Enhancer enhancer = new net.sf.cglib.proxy.Enhancer();
enhancer.setInterfaces(target.getClass().getInterfaces());
enhancer.setSuperclass(target.getClass());
net.sf.cglib.proxy.MethodInterceptor interceptor = ... // some proxy specific logic, likely referencing the `target`
enhancer.setCallback(interceptor);
// works fine
Foo proxy = (Foo) enhancer.create();
CGLIB creates a new class that is a subclass of Foo and instantiates it (invoking the constructor of Foo). All calls to the proxy will be intercepted by the provided callback (which usually performs some use case specific logic and then delegates to the target object).
Since the proxy class extends Foo, Spring can inject the proxy into a field (or constructor/method parameter) like
#Autowired
private Foo injectMe;
All this to say, if you're programming to interfaces, then ScopedProxyMode.INTERFACES will be sufficient. If you're not, then use ScopedProxyMode.TARGET_CLASS.
As for using #SessionAttributes, it is not an alternative to session scoped beans. Session attributes are just objects, they are not beans. They don't possess the full lifecycle, injection capabilities, proxying behavior that a bean may have.
If you want to store the whole bean in the session, use #Scope, otherwise use #SessionAttributes. In the case of using #Scope, if the class implements some interfaces then use INTERFACES proxy mode, if not use TARGET_CLASS.
Usually your service implements an interface, which allows the use of JDK proxies (INTERFACES mode). But if that is not the case then use TARGET_CLASS, which creates a CGLIB proxy.
Using INTERFACES should be used if possible and TARGET as last resort if the bean does not implement interfaces.
While going through a blog post provided in the comments above, I found a comment stating cons of interface-based proxies.
On the post, user Flemming Jønsson posted this:
Be careful with using interface-based proxies.
If you are using Spring Security or Spring Transactions you might experience oddities when using interface-based proxies.
E.g. if you have a bean T and that bean has methods a() and b() that are both annotated transactional. Calls from other beans directly to a() or b() will behave properly (as configured). However if you introduce an internal call - where a() calls b() then b's transactional metadata will have no effect. The reason is that when you are using interface-based proxies the internal call will not go through the proxy - and thus the transactional interceptor will not have a chance to start a new transaction.
The same goes for Security. If method a() only requires USER-role but calls b() that requires ADMIN-role, then the internal call from a to b will be performed for any USER with no warnings. Same reason as above, internal calls do not go through the proxy and thus the security interceptor does not have a chance to act upon the call to b() from a().
To solve issues like these use targetClass.
I am currently implementing SiteMinder for the site, which looks for a key called SM_USER in the request header. I retrieve it using the function below:
public string ReadUser()
{
return HttpContext.Current.Request.Headers["SM_USER"];
}
I wish to test if functionality releated to this function work; I have already tried unit testing using a mock class so I am looking to create the key SM_USER in the request header. How can I do that?
I am implementing the application with MVC3.
As long as you are using HttpContext.Current you will not be able to test it as Unit Test will not have HttpContext.Current.
Try to use an Interface with method returning string, say ReadUser(). Implement this interface in a class in your application. Use the interface variable whichever class you are using this method in. In that class' default constructor set that interface variable value to 'new' implementer class. Add an overload of the constructor which will take a parameter of type interface and set that parameter to interface variable.
Now in your UnitTest project implement same interface in another class. In this implementation you can now pass whatever mock value you want test.
public interface IReadUserInfo
{ string ReadUser(); }
public class ReadUserInfo: IReadUserInfo
{
public string ReadUser()
{
return HttpContext.Current.Request.Headers["SM_USER"];
}
}
public class UserClass
{
IReadUserInfo userinfo;
public UserClass()
{
userinfo = new ReadUserInfo();
}
public USerClass(IReadUserInfo newuserinfo)
{
userinfo = newuserinfo;
}
}
public class TestReadUserInfo : IReadUSerInfo
{
public string ReadUser()
{ return "testvalue"; }
}
If ReadUser is the only value you are using from Request header, then this approach will solve the problem. However, if you using more values from Request object, you might want to mock entire request object in similar way.
I'm creating spring.net proxy in code by using ProxyFactory object with ProxyTargetType to true to have a proxy on a non interfaced complex object.
Proxying seems ok till i call a method on that object. The method references a public property and if this property is not virtual it's value is null.
This doesn't happen if i use Spring.Aop.Framework.AutoProxy.InheritanceBasedAopConfigurer in spring config file but in this case i can't use this because spring context doesn't own this object.
Is this normal to have such behavior or is there a tweak to perform what i want (proxying object virtual method without having to change properties virtual)?
Note that i tried factory.AutoDetectInterfaces and factory.ProxyTargetAttributes values but doesn't help.
My proxy creation code:
public static T CreateMethodCallStatProxy<T>()
{
// Proxy factory
ProxyFactory factory = new ProxyFactory();
factory.AddAdvice(new CallMonitorTrackerAdvice());
factory.ProxyTargetType = true;
// Create instance
factory.Target = Activator.CreateInstance<T>();
// Get proxy
T proxiedClass = (T)factory.GetProxy();
return proxiedClass;
}
Thanks for your help
OK so properties need to be virtual.