replace one class in bean property list in spring - spring

I am working in broadleaf which is based on spring-mvc.
there are 3-4 blCustomPersistenceHandlers bean definition in different xml file based on project module.
<bean id="blCustomPersistenceHandlers" class="org.springframework.beans.factory.config.ListFactoryBean" scope="prototype">
<property name="sourceList">
<list>
<bean class="org.broadleafcommerce.admin.server.service.handler.CategoryCustomPersistenceHandler"/>
<bean class="org.broadleafcommerce.admin.server.service.handler.CustomerPasswordCustomPersistenceHandler"/>
<bean class="org.broadleafcommerce.openadmin.server.security.handler.AdminUserCustomPersistenceHandler"/>
<bean class="org.broadleafcommerce.admin.server.service.handler.CustomerCustomPersistenceHandler"/>
<bean class="org.broadleafcommerce.admin.server.service.handler.ProductCustomPersistenceHandler"/>
<bean class="org.broadleafcommerce.admin.server.service.handler.ChildCategoriesCustomPersistenceHandler"/>
<bean class="org.broadleafcommerce.admin.server.service.handler.SkuCustomPersistenceHandler"/>
</list>
</property>
</bean>
below in different xml files
<bean id="blCustomPersistenceHandlers" class="org.springframework.beans.factory.config.ListFactoryBean" scope="prototype">
<property name="sourceList">
<list>
<bean class="org.broadleafcommerce.cms.admin.server.handler.PageTemplateCustomPersistenceHandler"/>
<bean class="org.broadleafcommerce.cms.admin.server.handler.StructuredContentTypeCustomPersistenceHandler"/>
<bean class="org.broadleafcommerce.cms.admin.server.handler.SandBoxItemCustomPersistenceHandler"/>
<bean class="org.broadleafcommerce.cms.admin.server.handler.PendingSandBoxItemCustomPersistenceHandler"/>
<bean class="org.broadleafcommerce.cms.admin.server.handler.TimeDTOCustomPersistenceHandler"/>
<bean class="org.broadleafcommerce.cms.admin.server.handler.RequestDTOCustomPersistenceHandler"/>
<bean class="org.broadleafcommerce.cms.admin.server.handler.StructuredContentItemCriteriaCustomPersistenceHandler"/>
<bean class="org.broadleafcommerce.cms.admin.server.handler.PageItemCriteriaCustomPersistenceHandler"/>
</list>
</property>
</bean>
Above definitions reside into jar files that we included.
Now i want to replace one of this handler , for example ProductCustomPersistenceHandler,
I need to change some functionality regarding that handler, so I changed that handler as below in my xml file.
<bean id="org.broadleafcommerce.admin.server.service.handler.ProductCustomPersistenceHandler"
class="com.mycompany.server.service.handler.HCProductCustomPersistenceHandler" />
and also put bean defination into xml files
<bean id="blCustomPersistenceHandlers" class="org.springframework.beans.factory.config.ListFactoryBean"> <!-- scope="prototype" -->
<property name="sourceList">
<list>
<bean class="com.mycompany.server.service.handler.HCProductCustomPersistenceHandler"/>
</list>
</property>
</bean>
ProductCustomPersistenceHandler class
public class ProductCustomPersistenceHandler extends CustomPersistenceHandlerAdapter {
#Resource(name = "blCatalogService")
protected CatalogService catalogService;
private static final Log LOG = LogFactory.getLog(ProductCustomPersistenceHandler.class);
#Override
public Boolean canHandleAdd(PersistencePackage persistencePackage) {
String ceilingEntityFullyQualifiedClassname = persistencePackage.getCeilingEntityFullyQualifiedClassname();
String[] customCriteria = persistencePackage.getCustomCriteria();
return !ArrayUtils.isEmpty(customCriteria) && "productDirectEdit".equals(customCriteria[0]) && Product.class.getName().equals(ceilingEntityFullyQualifiedClassname);
}
#Override
public Boolean canHandleUpdate(PersistencePackage persistencePackage) {
return canHandleAdd(persistencePackage);
}
#Override
public Entity add(PersistencePackage persistencePackage, DynamicEntityDao dynamicEntityDao, RecordHelper helper) throws ServiceException {
Entity entity = persistencePackage.getEntity();
try {
PersistencePerspective persistencePerspective = persistencePackage.getPersistencePerspective();
Product adminInstance = (Product) Class.forName(entity.getType()[0]).newInstance();
Map<String, FieldMetadata> adminProperties = helper.getSimpleMergedProperties(Product.class.getName(), persistencePerspective);
adminInstance = (Product) helper.createPopulatedInstance(adminInstance, entity, adminProperties, false);
adminInstance = (Product) dynamicEntityDao.merge(adminInstance);
CategoryProductXref categoryXref = new CategoryProductXrefImpl();
categoryXref.setCategory(adminInstance.getDefaultCategory());
categoryXref.setProduct(adminInstance);
if (adminInstance.getDefaultCategory() != null && !adminInstance.getAllParentCategoryXrefs().contains(categoryXref)) {
categoryXref = (CategoryProductXref) dynamicEntityDao.merge(categoryXref);
adminInstance.getAllParentCategoryXrefs().add(categoryXref);
}
//Since none of the Sku fields are required, it's possible that the user did not fill out
//any Sku fields, and thus a Sku would not be created. Product still needs a default Sku so instantiate one
if (adminInstance.getDefaultSku() == null) {
Sku newSku = catalogService.createSku();
adminInstance.setDefaultSku(newSku);
adminInstance = (Product) dynamicEntityDao.merge(adminInstance);
}
//also set the default product for the Sku
adminInstance.getDefaultSku().setDefaultProduct(adminInstance);
dynamicEntityDao.merge(adminInstance.getDefaultSku());
return helper.getRecord(adminProperties, adminInstance, null, null);
} catch (Exception e) {
LOG.error("Unable to add entity for " + entity.getType()[0], e);
throw new ServiceException("Unable to add entity for " + entity.getType()[0], e);
}
}
#Override
public Entity update(PersistencePackage persistencePackage, DynamicEntityDao dynamicEntityDao, RecordHelper helper) throws ServiceException {
Entity entity = persistencePackage.getEntity();
try {
PersistencePerspective persistencePerspective = persistencePackage.getPersistencePerspective();
Map<String, FieldMetadata> adminProperties = helper.getSimpleMergedProperties(Product.class.getName(), persistencePerspective);
Object primaryKey = helper.getPrimaryKey(entity, adminProperties);
Product adminInstance = (Product) dynamicEntityDao.retrieve(Class.forName(entity.getType()[0]), primaryKey);
adminInstance = (Product) helper.createPopulatedInstance(adminInstance, entity, adminProperties, false);
adminInstance = (Product) dynamicEntityDao.merge(adminInstance);
CategoryProductXref categoryXref = new CategoryProductXrefImpl();
categoryXref.setCategory(adminInstance.getDefaultCategory());
categoryXref.setProduct(adminInstance);
if (adminInstance.getDefaultCategory() != null && !adminInstance.getAllParentCategoryXrefs().contains(categoryXref)) {
adminInstance.getAllParentCategoryXrefs().add(categoryXref);
}
return helper.getRecord(adminProperties, adminInstance, null, null);
} catch (Exception e) {
LOG.error("Unable to update entity for " + entity.getType()[0], e);
throw new ServiceException("Unable to update entity for " + entity.getType()[0], e);
}
}
}
I just extend this handler and make my new handler , as it runs only core handler is executing, I want to execute my handler.
But this is not working.
I can't change into core part, so I just need to replace handler with my handler.
How can I do that?
Is that possible in spring?

For custom persistence handlers specifically, you can remove the core handlers by using the blCustomPersistenceHandlerFilters bean. So in your case you would define your beans like this:
<bean id="blCustomPersistenceHandlerFilters" class="org.springframework.beans.factory.config.ListFactoryBean" scope="prototype">
<property name="sourceList">
<list>
<bean class="org.broadleafcommerce.openadmin.server.service.handler.DefaultCustomPersistenceHandlerFilter">
<property name="filterCustomPersistenceHandlerClassnames">
<list>
<value>org.broadleafcommerce.admin.server.service.handler.ProductCustomPersistenceHandler</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
Then you can add your own CPH to the list like you were doing before:
<bean id="blCustomPersistenceHandlers" class="org.springframework.beans.factory.config.ListFactoryBean"> <!-- scope="prototype" -->
<property name="sourceList">
<list>
<bean class="com.mycompany.server.service.handler.HCProductCustomPersistenceHandler"/>
</list>
</property>
</bean>
And now the BLC Product custom persistence handler will not run but yours will.
This is probably a little too complex for your simple purposes of wanting to replace the out-of-the-box one with your custom one. It's possible that there is a good reason why we did it like this, but I added a GitHub Issue for it to investigate further.

Related

Spring collection merge

I have two lists generated with a FactoryBean and I would like to initialize a bean with the merged version of this two. Is there a way doing this?
<bean id="listA" class="XFactoryBean" >
...
</bean>
<bean id="listB" class="YFactoryBean">
...
</bean>
<bean >
<property name="AwithB" ...>
</bean>
There is a solution that works with static lists (http://vikdor.blogspot.hu/2012/10/using-collection-merging-in-spring-to.html), but does not work with those generated lists.
Java #Configuration FTW:
#Configuration
public class Config {
#Resource
private List listA;
#Resource
private List listB;
#Bean
public List AwithB() {
List mergedList = new ArrayList(listA);
listB.addAll(listB);
return mergedList;
}
}
Much less boilerplate.
There is a sublte bug with the ListMergerFactoryBean solution above.
Config:
<util:list id="listA" value-type="java.lang.String">
<value>fooA</value>
<value>barA</value>
</util:list>
<util:list id="listB" value-type="java.lang.String">
<value>fooB</value>
<value>barB</value>
</util:list>
<util:list id="listC" value-type="java.lang.String">
<value>fooC</value>
<value>barC</value>
</util:list>
<bean id="AwithB" class="com.util.ListMergerFactoryBean">
<property name="listOfLists">
<list>
<ref bean="listA" />
<ref bean="listB" />
</list>
</property>
</bean>
<bean id="AwithC" class="com.util.ListMergerFactoryBean">
<property name="listOfLists">
<list>
<ref bean="listA" />
<ref bean="listC" />
</list>
</property>
</bean>
With this config you might be surprised when bean AwithB has the expected content of AwithC. ListA is a singleton and the getObject method alters it, therefore alters it for all users of ListMergerFactoryBean, even though the bean factory is not a singleton. The fix is to not re-use the first list in the listOfLists:
#Override
public List getObject() throws Exception {
List mergedList = new ArrayList();
for (List list : listOfLists) {
mergedList.addAll(list);
}
return mergedList;
}
After checking the SpEL-related solutions (how to extend a list in spring config) and extending the ListFactoryBean (http://ericlefevre.net/wordpress/2008/04/02/merging-lists-in-a-spring-configuration-file/) I came up with the following solution:
config:
<bean id="AwithB" class="com.util.ListMergerFactoryBean">
<property name="listOfLists">
<list>
<ref bean="listA" />
<ref bean="listB" />
</list>
</property>
</bean>
java:
public class ListMergerFactoryBean implements FactoryBean<List> {
private List<List> listOfLists;
#Override
public List getObject() throws Exception {
List mergedList = new ArrayList();
for (List list : listOfLists) {
mergedList.addAll(list);
}
return mergedList;
}
#Override
public Class<?> getObjectType() {
return (new ArrayList()).getClass();
}
#Override
public boolean isSingleton() {
return false;
}
public void setListOfLists(List<List> listOfLists) {
this.listOfLists = listOfLists;
}
}
UPDATE: I have eliminated a bug using Aron Bartle's solution. Thanks!

Filtering JSON response based on authentication

I want to filter object properties based on authentication or even roles.
So, for example full user profile will be returned for authenticated user and filterd for non authenticated.
How can I achieve it with MappingJacksonHttpMessageConverter? I have already declared custom beans for Jaskon:
<bean id="objectMapper" class="com.example.CustomObjectMapper"/>
<bean id="MappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="objectMapper"/>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="order" value="1" />
<!-- <property name="customArgumentResolver" ref="sessionParamResolver"/> -->
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<!-- <property name="conversionService" ref="conversionService" /> -->
<!-- <property name="validator" ref="validator" /> -->
</bean>
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<ref bean="MappingJacksonHttpMessageConverter"/>
</list>
</property>
</bean>
Note: In controllers I am writing results as:
public void writeJson (Object jsonBean, HttpServletResponse response) {
MediaType jsonMimeType = MediaType.APPLICATION_JSON;
if (jsonConverter.canWrite(jsonBean.getClass(), jsonMimeType)) {
try {
jsonConverter.write(jsonBean, jsonMimeType, new ServletServerHttpResponse(response));
} catch (IOException m_Ioe) {
} catch (HttpMessageNotWritableException p_Nwe) {
} catch (Exception e) {
e.printStackTrace();
}
} else {
log.info("json Converter cant write class " +jsonBean.getClass() );
}
}
If you're wanting to return two separate types of JSON objects (e.g. fullProfile and partialProfile), then you would be best-off making two different services with two different urls. Then you could control access to those urls in the normal manner with Spring Security's intercept-url tags.
I did most of that here https://stackoverflow.com/a/39168090/6761668
All you need to do is pencil in your own security rules, perhaps injecting the current user and deciding what to include or not based on their role. I used an annotation on the entity column:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Set;
#Retention(RetentionPolicy.RUNTIME)
public #interface MyRestricted {
String[] permittedRoles() default {};
}
The column looked like this:
#Column(name = "DISCOUNT_RATE", columnDefinition = "decimal", precision = 7, scale = 2)
#MyRestricted(permittedRoles = { "accountsAdmin", "accountsSuperUser" })
private BigDecimal discountRate;
The rules looked like this:
final MyRestricted roleRestrictedProperty = pWriter.findAnnotation(MyRestricted.class);
if (roleRestrictedProperty == null) {
// public item
super.serializeAsField(pPojo, pJgen, pProvider, pWriter);
return;
}
// restricted - are we in role?
if (permittedRoles.contains(myRole)) {
super.serializeAsField(pPojo, pJgen, pProvider, pWriter);
return;
}
// Its a restricted item for ME
pWriter.serializeAsOmittedField(pPojo, pJgen, pProvider);

spring mybatis transaction getting committed

I am trying to use mybatis spring transaction management
My problem is that the transactions are getting committed even if an exception is thrown.
Relatively new to this, anykind of help is much appreciated.
Following are the code snippets
spring xml configuration
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:Config.properties</value>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.user}"/>
<property name="password" value="${db.pass}"/>
<property name="defaultAutoCommit" value="false" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:Configuration.xml" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean class="org.mybatis.spring.SqlSessionTemplate" id="sqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory"/>
</bean>
Service class
#Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRED)
public void insertNotes(String noteTypeId,String confidentialValue,String summaryValue,String notes ,String notesId,String noteTypeValue,
String claimNumber,String notepadId,String mode)
{
NotepadExample notepadExample= new NotepadExample();
//to be moved into dao class marked with transaction boundaries
Notepad notepad = new Notepad();
notepad.setAddDate(new Date());
notepad.setAddUser("DummyUser");
if("true".equalsIgnoreCase(confidentialValue))
confidentialValue="Y";
else
confidentialValue="N";
notepad.setConfidentiality(confidentialValue);
Long coverageId=getCoverageId(claimNumber);
notepad.setCoverageId(coverageId);
notepad.setDescription(summaryValue);
notepad.setEditUser("DmyEditUsr");
//notepad.setNotepadId(new Long(4)); //auto sequencing
System.out.println(notes);
notepad.setNotes(notes);
notepad.setNoteType(noteTypeValue); //Do we really need this?
notepad.setNoteTypeId(Long.parseLong(notesId));
if("update".equalsIgnoreCase(mode))
{
notepad.setNotepadId(new Long(notepadId));
notepad.setEditDate(new Date());
notepadMapper.updateByPrimaryKeyWithBLOBs(notepad);
}
else
notepadMapper.insertSelective(notepad);
throw new java.lang.UnsupportedOperationException();
}
Not sure where I am going wrong...
The current call is from the controller as given below
#Controller
public class NotesController {
private static final Logger logger = LoggerFactory
.getLogger(NotesController.class);
#Autowired
private Utils utility;
#Autowired
NotepadService notepadService;
public #ResponseBody List<? extends Object> insertNotes(HttpServletRequest request,
HttpServletResponse response,#RequestParam("noteTypeValue") String noteTypeId,
#RequestParam("confidentialValue")String confidentialValue,
#RequestParam("summaryValue")String summaryValue,
#RequestParam("notes")String notes ,
#RequestParam("notesId")String notesId,
#RequestParam("noteTypeValue")String noteTypeValue,
#RequestParam("claimNumber")String claimNumber,
#RequestParam("notepadId")String notepadId,
#RequestParam("mode")String mode) {
try {
notepadService.insertNotes(noteTypeId, confidentialValue, summaryValue, notes, notesId, noteTypeValue, claimNumber, notepadId, mode);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
I had the same issue. I am also relatively new to spring. But according to me it depends on how you are calling your insertNotes() method. If you are calling it from another local method then it will not work, because spring has no way of know that it is called and to start the transaction.
If you are calling it from a method of another class by using autowired object of the class which contains insertNotes() method, then it should work.
For example
class ABC
{
#Autowired
NotesClass notes;
public void testMethod() {
notes.insertNotes();
}
}
class NotesClass
{
#Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRED)
public void insertNotes(String noteTypeId,
String confidentialValue,
String summaryValue,String notes ,
String notesId,String noteTypeValue,
String claimNumber,
String notepadId,
String mode) {
//Your code
}
}
You can try using transaction template. Remove #Tranasactional annotation from method and following code to xml file.
<bean id="trTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="timeout" value="30"/>
<property name="transactionManager" ref="transactionManager"/>
</bean>
Create object of Trasactiontemplate and call insertNotes from controller like this
#Autowired
private TransactionTemplate transactionTemplate;
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
insertNotes();
} catch (Exception e) {
transactionStatus.setRollbackOnly();
logger.error("Exception ocurred when calling insertNotes", e);
throw new RuntimeException(e);
}
}
});
Note : You have to make all parameters final before calling insertNotes method

Why is Spring #Transactional returning old data and how can I get it to return up-to-date data?

I'm using Spring 3.1.0.RELEASE with Hibernate 4.0.1.Final. I'm trying to use the Spring transaction manager but am having an issue where Spring is returning old data for a find method. In my Spring application, I call a save method, and then a find method. After I call save, I can see the changes in the database, but when I call the find, it is returning the old state of the object. Here is the controller methods ...
// method to save
#RequestMapping(method = RequestMethod.POST)
public String saveUserEventFeeds(final HttpServletRequest request,
#ModelAttribute("eventFeeds") final Set<EventFeed> eventFeeds) {
final String nextPage = "user/eventfeeds";
try {
final String[] eventFeedIds = request.getParameterValues("userEventFeeds");
final Set<EventFeed> userEventFeeds = new HashSet<EventFeed>();
if (eventFeedIds != null) {
for (final String eventFeedId : eventFeedIds) {
final EventFeed eventFeed = getEventFeed(eventFeeds, Integer.parseInt(eventFeedId));
userEventFeeds.add(eventFeed);
} // for
} // if
final Registration currentUser = (Registration) securityContextFacade.getContext().getAuthentication().getPrincipal();
userService.saveUserEventFeeds(currentUser.getId(), userEventFeeds);
} catch (Exception exc) {
LOG.error(exc.getMessage(), exc);
} // try
return nextPage;
} // saveUserEventFeeds
// method to retrieve user
#ModelAttribute("user")
public UserDetails getUser() {
final Registration reg = (Registration) securityContextFacade.getContext().getAuthentication().getPrincipal();
final int id = reg.getId();
final Registration foundUser = userService.findUserById(id);
return (UserDetails) foundUser;
} // getUser
and here is the service where i declare everything transactional ...
#Transactional(rollbackFor = Exception.class)
#Component("userService")
public class UserServiceImpl implements UserService {
...
#Override
public void saveUserEventFeeds(Integer userId, Set<EventFeed> eventFeeds) {
final Registration searchUser = new Registration();
searchUser.setId(userId);
final Registration user = usersDao.getUser(searchUser);
if (user != null) {
user.setUserEventFeeds(eventFeeds);
usersDao.saveUser(user);
} else {
throw new RuntimeException("User with id " + userId + " not found.");
} // if
}
#Override
public Registration findUserById(Integer id) {
final Registration searchUser = new Registration();
if (id != null) {
searchUser.setId(id);
} // if
return usersDao.getUser(searchUser);
}
Below is the transaction manager I've declared in my application context file. If you can see how I can configure things differently so that I can get the most current data on my finds, please let me know.
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/myproj"/>
<property name="username" value="myproj"/>
<property name="password" value="password"/>
<property name="maxActive" value="10"/>
<property name="minIdle" value="5"/>
<!-- SELECT 1 is a simple query that returns 1 row in MySQL -->
<property name="validationQuery" value="SELECT 1"/>
</bean>
<bean class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" id="sessionFactory">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.myco.myproj.domain.Registration</value>
<value>com.myco.myproj.domain.Role</value>
<value>com.myco.myproj.domain.EventFeed</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="show_sql">true</prop>
<prop key="dialect">org.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
<tx:annotation-driven />

Reading a list from a file .properties using Spring properties place holder

I want to fill a bean list property using Spring properties place holder.
Context file
<bean name="XXX" class="XX.YY.Z">
<property name="urlList">
<value>${prop.list}</value>
</property>
</bean>
Properties File
prop.list.one=foo
prop.list.two=bar
Any help would be much appreciated
Use a util:properties element to load your properties. You can use PropertyPlaceholderConfigurer to specify the path to your file:
<bean name="XXX" class="XX.YY.Z">
<property name="urlList">
<util:properties location="${path.to.properties.file}"/>
</property>
</bean>
Update I've misunderstood the question; you only want to return properties where key starts with specific string. The easiest way to achieve that would be to do so within setter method of your bean. You'll have to pass the string to your bean as a separate property. Extending the above declaration:
<bean name="XXX" class="XX.YY.Z" init-method="init">
<property name="propertiesHolder">
<!-- not sure if location has to be customizable here; set it directly if needed -->
<util:properties location="${path.to.properties.file}"/>
</property>
<property name="propertyFilter" value="${property.filter}" />
</bean>
In your XX.YY.Z bean:
private String propertyFilter;
private Properties propertiesHolder;
private List<String> urlList;
// add setter methods for propertyFilter / propertiesHolder
// initialization callback
public void init() {
urlList = new ArrayList<String>();
for (Enumeration en = this.propertiesHolder.keys(); en.hasMoreElements(); ) {
String key = (String) en.nextElement();
if (key.startsWith(this.propertyFilter + ".") { // or whatever condition you want to check
this.urlList.add(this.propertiesHolder.getProperty(key));
}
} // for
}
If you need to do this in many different places you can wrap the above functionality into a FactoryBean.
A simpler solution:
class Z {
private List<String> urlList;
// add setters and getters
}
your bean definition
<bean name="XXX" class="XX.YY.Z">
<property name="urlList" value="#{'${prop.list}'.split(',')}"/>
</bean>
Then in your property file:
prop.list=a,b,c,d
<bean id="cpaContextSource" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="urls">
<bean class="org.springframework.util.CollectionUtils" factory-method="arrayToList">
<constructor-arg type="java.lang.Object">
<bean class="org.springframework.util.StringUtils" factory-method="tokenizeToStringArray">
<constructor-arg type="java.lang.String" value="${myList}"/>
<constructor-arg type="java.lang.String" value=" "/>
</bean>
</constructor-arg>
</bean>
</property>
where:
myList=http://aaa http://bbb http://ccc
The only way i see here is, implement the interface 'MessageSourceAware' to get the messageResource, and then manually populate your list.
class MyMessageSourceAwareClass implemets MessageSourceAware{
public static MessageSource messageSource = null;
public void setMessageSource(MessageSource _messageSource) {
messageSource = _messageSource;
}
public static String getMessage( String code){
return messageSource.getMessage(code, null, null );
}
}
--- Properties File ---
prop.list=foo;bar;one more
Populate your list like this
String strlist = MyMessageSourceAwareClass.getMessage ( "prop.list" );
if ( StringUtilities.isNotEmptyString ( strlist ) ){
String[] arrStr = strList.split(";");
myBean.setList ( Arrays.asList ( arrStr ) );
}
Just add the following Bean definition
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:myprops.properties</value>
</list>
</property>
</bean>
To use it like so please note port is defined in myprops.properties
<bean id="mybean" class="com.mycompany.Class" init-method="start">
<property name="portNumber" value="${port}"/>
</bean>
There are several ways , one of them is below.
XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));
cfg.postProcessBeanFactory(factory);

Resources