I've a Bean named as Bucket, it has a HashMap. I want to initialize the bean and polulate the HashMap in the faces-config.xml with a property file. How can I do that?
Bean:
public class BundleBean {
private Map<String, String> bundlePropertiesMap = new HashMap<String, String>();
private String bundleFileName;
// Setter, getter goes here....
}
Property file, named as bundle.properties, and it's on the classpath.
bucket.id=DL_SERVICE
faces-config.xml file :
<managed-bean>
<description>
Java bean class which have bundle properties.
</description>
<managed-bean-name>bundleBean</managed-bean-name>
<managed-bean-class>org.example.view.bean.BundleBean</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<managed-property>
<property-name>bundleFileName</property-name>
<value>bundle.properties</value>
</managed-property>
</managed-bean>
That Map has to have the bucket.id as the key and DL_SERVICE as the value.
Thanks in Advanced~
Assuming the properties file is in the same ClassLoader context as BundleBean, call a method like this:
#SuppressWarnings("unchecked")
private void loadBundle(String bundleFileName, Map<String, String> map)
throws IOException {
InputStream in = BundleBean.class.getResourceAsStream(bundleFileName);
try {
Properties props = new Properties();
props.load(in);
((Map) map).putAll(props);
} finally {
in.close();
}
}
This is best invoked using the #PostConstruct annotation. If that is not an option, call it either in the bundleFileName setter or perform a lazy check in the bundlePropertiesMap getter.
you can do that with spring that has a more advanced dependency injection mechanism.
when you integrate spring with jsf, you can define your jsf bundlebean in the spring context
<bean id="injectCollection" class="CollectionInjection">
<property name="map">
<map>
<entry key="someValue">
<value>Hello World!</value>
</entry>
<entry key="someBean">
<ref local="oracle"/>
</entry>
</map>
</property>
If I'm not mistaken, JSF calls the corresponding setters when initializing the bean. Thus providing a method public void setBundleFileName(String filename) should work.
Related
I recently switched from using Spring's XML configuration to its Java configuration and am encountering a strange issue.
The XML configuration was:
<util:map id="myMap">
<entry key="a" value="aValue"/>
<entry key="b" value="bValue"/>
<entry key="c" value="cValue"/>
</util:map>
<bean id="myBean" class="my.MyClass">
<property name="myMap" ref="myMap"/>
</bean>
The Java configuration is:
#Bean
public Map<String, Object> myMap() {
Map<String, Object> myMap = new HashMap<>();
myMap.put("a", "aValue");
myMap.put("b", "bValue");
myMap.put("c", "cValue");
return myMap;
}
#Bean
public MyClass myBean(#Qualifier("myMap") final Map<String, Object> myMap) {
MyClass myBean = new MyClass();
myBean.setMyMap(myMap);
return myBean;
}
Both beans are declared in different files, I grouped them here to make it easier to read. The map contains references too, not only strings.
I would expect to be able to use myMap in the second bean but instead Spring injects the following map:
{ myMap = { a=aValue, b=bValue, c=cValue } }
I don't understand why Spring wraps the map into another map, and why it doesn't behave the same way with the XML configuration.
Any ideas?
There is an issue #Autowired-ing a Map even defining the bean name and since as-per the comments you can't use the suggested #Resource annotation there is an alternative by using the #Value annotation defining the bean name:
#Bean
public MyClass myBean(#Value("#{myMap}") final Map<String, Object> myMap) {
//..
}
i want pass parameter to #autowired ref like
public CoreDao {
private String taskId;
private final String sql = "select ....."+getTaskId()+".....";
public CoreDao(String taskId){
if(taskId.length != 0){
this.taskId = taskId;
}else{
this.taskId = "0";
}
public getTaskId(){
return this.taskId;
}
}
xml is:
<bean id="coreDao" class="Coredao" scope="prototype">
<constructor-arg type="java.lang.String" value=""/>
</bean>
and the CoreService is
#service
CoreService implement ICoreService{
#Autowired
pirvate CoreDao;
}
and xml is
<bean id="coreService" class="CoreService" scope="prototype">
<property name="coreDao" ref="coreDao"/>
</bean>
and i want use getBean("coreService","123") to get the bean with dynamic reference of coreDao.
However,when i use getBean("coreService","123"),the exception is:
error creating bean with name "coreService" defined in file ....xml,could not resolve matching constructor (hint:specify index/type/name arguments for simple parameter to avoid ambiguities.
how could do that?thanks your help.
getBean(String, Object ...) is applicable to bean's constructors or factory methods.
Your CoreService should have CoreService(String s) constructor in order to use this method.
If you want to create many CoreService instances with different parameters, you can create a factory bean which creates all instances for you and puts them together, like
#Component
public class CoreServiceFactoryBean {
#Autowired ApplicationContext ctx;
public CoreService getBean(String param) {
CoreService coreService = ctx.getBean("coreService");
CoreDao coreDao = ctx.getBean("coreDao", parameter);
coreService.setCoreDao(coreDao);
return coreService;
}
}
This way, the logic of creating bean and using it remains separate. Using factories is pretty common to configure prototype scoped beans.
Normally i would populate a field using annotations when I knew the property name like so :
#Value("${myproperties.myValue}")
private String myString
However I now want to loop through all the properties in a file, when their names are unknown, and store both there value and name. What's the best way with spring and java ?
Actually if you need only to read properties from a file and not to use these properties in Spring's property placeholders, then the solution is simple
public class Test1 {
#Autowired
Properties props;
public void printProps() {
for(Entry<Object, Object> e : props.entrySet()) {
System.out.println(e);
}
}
...
<util:properties id="props" location="/spring.properties" />
The #Value mechanism works through the PropertyPlaceholderConfigurer which is in turn a BeanFactoryPostProcessor. The properties used by it are not exposed at runtime. See this previous answer of mine for a possible solution.
I could not find a simpler solution than this
class PropertyPlaceholder extends PropertyPlaceholderConfigurer {
Properties props;
#Override
protected Properties mergeProperties() throws IOException {
props = super.mergeProperties();
return props;
}
}
public class Test1 {
#Autowired
PropertyPlaceholder pph;
public void printProps() {
for(Entry<Object, Object> e : pph.props.entrySet()) {
System.out.println(e);
}
}
...
...
<bean class="test.PropertyPlaceholder">
<property name="locations">
<value>/app.properties</value>
</property>
</bean>
Using enumeration to loop through Properties
I'm trying to add some Spring configuration to an existing utility class. It doesn't seem to work and I'm not sure why (my first time using these Spring options, I'm not even sure I'm doing it correctly).
The class in question
#Configurable(autowire=Autowire.BY_NAME, preConstruction=true)
public class DataUtility
{
private static final DataUtility INSTANCE = new DataUtility();
#Autowired(required=true) //This is the new field and annotation
private Map<String,String> dataFileMapping = new HashMap<String, String>();
public static DataUtility getInstance()
{
return INSTANCE;
}
private DataUtility()
{
//Do a bunch of setup work here
for (String s : dataFileMapping)
{
addDataToCache(dataFileMapping(s))
}
}
The spring config looks like this:
<context:annotation-config/>
<context:spring-configured/>
<bean id="util" class="com.myCompany.DataUtility">
<property name="dataFileMapping">
<map>
<entry key="data1" value="data/file1.dat"/>
<entry key="data2" value="data/file2.dat"/>
<entry key="data3" value="data/file3.dat"/>
</map>
</property>
</bean>
The problem is that when I step through my code in the debugger, I can see that dataFileMapping is empty. I'm not even sure if the spring config is even running.
I think you just need to add getters and setters for dataFileMapping
Also, remember that you can't iterate through the map in the constructor, spring wouldn't have had a chance to set it until after the constructor executes.
In addition to this, you can't make your constructor private and expect spring to be able to instantiate it.
The root of your problem is that you seem to be using a static reference INSTANCE to access the object. Spring is making a bean named 'util' and setting it up with your data, but that isn't becoming the object that INSTANCE points to. The initialization of static fields happens when the class is first loaded, long before spring ever gets a chance to create and inject beans.
You can sort of fake it like this, but of course attempts to access instance before bean initialization will fail:
#Configurable(autowire=Autowire.BY_NAME, preConstruction=true)
public class DataUtility
{
private static final DataUtility INSTANCE = null;
#Autowired(required=true) //This is the new field and annotation
private Map<String,String> dataFileMapping = new HashMap<String, String>();
public static DataUtility getInstance()
{
return INSTANCE;
}
public postInit()
{
INSTANCE = this;
//Do a bunch of setup work here
for (String s : dataFileMapping)
{
addDataToCache(dataFileMapping(s))
}
}
<bean id="util" class="com.myCompany.DataUtility" init-method="postInit">
<property name="dataFileMapping">
<map>
<entry key="data1" value="data/file1.dat"/>
<entry key="data2" value="data/file2.dat"/>
<entry key="data3" value="data/file3.dat"/>
</map>
</property>
</bean>
I have written a factory bean that creates a cache manager based on the properties that are configured in a application specific properties file.
The concept is that multiple implementations can be chosen, each using other configuration properties.
For example:
noop cache, without parameters,
ehcache with #max objects
memcache with multiple ips and ports configured.
I think it is nice to not specify all cache-application specific parameters in the application-context.xml, but read them from the existing properties sources.
My attempt was using a EnvironementAware interface to get access to the Environement. But it seems that the property file that is configured using <context:property-placeholder> is not contained in the PropertiesSources.
example.properties
cache.implementation=memcached
cache.memcached.servers=server1:11211,server2:11211
application-context.xml
<context:property-placeholder location="example.properties"/>
<bean id="cacheManager" class="com.example.CacheManagerFactory"/>
In CacheManagerFactory.java
public class CacheManagerFactory implements FactoryBean<CacheManager>, EnvironmentAware {
private Environement env;
#Override
public CacheManager getObject() throws Exception {
String impl = env.getRequiredProperty("cache.implementation"); // this fails
//Do something based on impl, which requires more properties.
}
#Override
public void setEnvironment(Environment env) {
this.env = env;
}
#Override
public Class<?> getObjectType() {
return CacheManager.class;
}
#Override
public boolean isSingleton() {
return true;
}
}
In config file like this :
<context:property-placeholder location="classpath:your.properties" ignore-unresolvable="true"/>
...
<property name="email" value="${property1.email}"/>
<!-- or -->
<property name="email">
<value>${property1.email}</value>
</property>
or in code :
#Value("${cities}")
private String cities;
where the your.properties contains this :
cities = my test string
property1.email = answer#stackvoerflow.com