How to inject spring properties into wicket components? - spring

I'm searching for a possibility to inject a property which is defined in a spring context (provided by a propertiesFactoryBean) into a wicket component. I know the way to inject beans into components by using the #SpringBean-Annotation, but whats the corresponding way for properties?
The way my property is defined:
<bean id="myPropertiesFactory" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="mySpringProperty">mySpringProperty</prop>
</property>
</bean>
Things I've tried. The way it works usually with self defined beans:
#Inject
#Value("${mySpringProperty}")
Using the name of the propertiesFactory to access the property value
#Inject
#Value("$myPropertiesFactory.properties.mySpringProperty")
Using the Value Annotation
#Value("#myPropertiesFactory['mySpringProperty']")
Using SpringBean
#SpringBean(name="myPropertiesFactory.mySpringProperty")
None of these solutions works. So to get mySpringProperty injected i use the workaround to create a bean of the type String which get's injected properly by wicket when i annotate the corresponding member of my component with SpringBean but i think there must be a better solution.
<bean id="mySpringPropertyBean" class="java.lang.String">
<constructor-arg type="java.lang.String" value="https://foobar.com" />
</bean>
Annotate
#SpringBean
private String mySpringPropertyBean;

#SpringBean only supports injection of spring beans. I suppose someone could implement a #SpringValue annotation that does what you want, but as far as I know noone ever did.
What I usually do is:
My wicket application class is a spring bean.
It has properties with #Value annotations - as the object is a spring bean, these are evaluated and set properly
I access the actual values by calling MyApplication.get().getXXX() or ((MyApplication)getApplication()).getXXX()
If the app grows and the number of attributes approach a limit, I refactor them into separate Settings or Config classes - each one a spring bean of it's own, accessible from the application class.

In your Wicket class use instead of #Value("${mySpringProperty}"):
#SpringBean
private PropertiesConfiguration propertiesConfiguration;
Create a new PropertiesConfiguration class:
#Component
public class PropertiesConfiguration {
#Value("${mySpringProperty}")
private String mySpringProperty;
//getters & setters
}
Use in your wicket class:
System.out.println("mySpringProperty=" + propertiesConfiguration.getMySpringProperty());

Related

Spring inject bean is always singleton

We are using spring 3.2.
We defined a bean myAccountVO in spring.xml files and set the scope to prototype, but the spring creates this bean as singleton bean.
Here is the spring xml:
<bean name="myAccountVO1"
class="valueobject.AccountVO"
scope="prototype" >
<property name="accountNo" value="0105069413007" />
<property name="accountType" value="01" />
</bean>
The service class is:
#Service //I've tested the #Scope("prototype") but no luck
public class AccountSummary {
#Autowired //I also tested #Resource but same result
private AccountSummaryVO myAccountSummaryVO1;
AccountSummaryVO getAccount(){
return myAccountSummaryVO1
}
}
Later we use this service as:
#Autowired
AccountSummary accountSummary;
............
accountSummary.getAccount()
As far as I get the AccountSummary class, itself, is a singleton and will not be instantiated every time.
It seems are very basic usecase, but I don't know what am I missing.
I don't see where you are injecting myAccountVO1.
But I guess when you reveal the injected place that it's probably a member of a bean which itself is not in the scope prototype, e.g. #Service or #Controller. The service bean will be instantiated with a newly created myAccountVO1, but this instance stays there forever.
Change the scope of the containing bean. See 4.5.3 Singleton beans with prototype-bean dependencies.
This applies as well to the beans which have the service beans injected.

reusing spring beans - name collisions

What is the preffered approach for reusing other jar containing spring-annotated classes in spring (3.2) ?
Example of a problem:
I have a jar that has #Autowired SessionFactory, but it needs different session factory than the rest of the application (it talks to a different database)
So, if I just put that jar in my classpath the application won't start because there are 2 beans with the same type/name. I need to have that jar isolated from the rest of the application.
How to achieve that?
Selecting a particular bean when multiple candidates are present is addressed by #Qualifier. Just declare the same beans in your application context and assign them with different id's or qualifier names. Lets take a look at this class:
public class Foo{
#Autowired
private SessionFactory sessionFactory;
}
Assuming both SessionFactoryImpl1 and SessionFactoryImpl2 are both candidates for bean wiring, and you want to point sessionFactory to SessionFactoryImpl1 instance instead, then you need to add the #Qualifier annotation just like in the example below:
public class Foo{
#Autowired
#Qualifier("sessionFactory1")
private SessionFactory sessionFactory;
}
And in your application context
<bean class="example.SessionFactoryImpl1">
<qualifier value="sessionFactory1"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SessionFactoryImpl2">
<qualifier value="sessionFactory2"/>
<!-- inject any dependencies required by this bean -->
</bean>

spring: need for an example of using prototype bean in a web environment

I wonder how can I properly inject a prototype bean to a singleton one in a web app. Consider this example:
<bean id="order" class="com.foo.Order" scope="prototype"/>
<bean id="orderService" class="com.foo.OrderService">
<property name="userPreferences" ref="userPreferences"/>
</bean>
I thought of using getBean() but isn't that a way to make my code dependent to spring itself?
I need a short java code example to demonstrate how to inject an order bean in my OrderService singleton.
Thanks
You can use jsr-330 Providers, just put:
#Autowired
Provider<Order> orderProvider;
in your singleton bean, and then use the provider:
public Whatever yourMethod() {
Order order = orderProvider.get();
}

Spring injection bind toInstance

Is there a way to bind an injected object to a specific instance using Spring DI similar to Google Guice's
bind(MyClass.class).toInstance(myclassobject);
If the constructor or member variable is annotated with #Autowired, Spring will try to find a bean that matches the type of the Object. You can get similar functionality to the annotation using #Qualifier, for example:
bind(MyClass.class).annotatedWith(Names.named("main")).toInstance(myclassobject);
would become in Spring:
#Autowired #Qualifier("main") private MyClass myClassObject;
<bean name="myClassObject" class="example.MyClassImpl">
<qualifier value="main"/>
</bean>
See http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-autowired-annotation for more.

Spring 3.0.5 doesn't evaluate #Value annotation from properties

Trying to auto-wire properties to a bean in Spring 3.0.5.RELEASE, I'm using:
config.properties:
username=myusername
main-components.xml:
<context:property-placeholder location="classpath:config.properties" />
MyClass:
#Service
public class MyClass {
#Value("${username}")
private String username;
...
}
As a result, username gets set to literally "${username}", so the expression doesn't get parsed. My other auto-wired dependencies on this class get set, and Spring doesn't throw any exception. I also tried to add #Autowired but it didn't help.
If I parse properties to a separate bean and then use #Autowired + #Qualifier, it works:
<bean id="username" class="java.lang.String">
<constructor-arg value="${username}"/>
</bean>
Any ideas how to use just #Value? Maybe I need to include some Spring dependency that I haven't? Thank you
Found what the issue was. Copy/paste from comments:
Are you sure you have <context:property-placeholder> in the same application context as your MyClass bean (not in the parent context)? – axtavt
You're right. I moved <context:property-placeholder> from the context defined by the ContextLoaderListener to the servlet context. Now my values get parsed. Thanks a lot! - alex

Resources