Results 1 to 4 of 4

Thread: Inject a Map defined in a properties file

  1. #1

    Default Inject a Map defined in a properties file

    I want to inject a Map from a property file into my Bean. What is the best way to configure that?

    My props:
    Code:
    a.b.c.1=foo
    a.b.c.2=bar
    Inside my bean I want a Map with the pairs (1, foo) (2, foo).

    I have found a post on stackoverflow.com which stated:
    - implement ApplicationContextAware and set the ApplicationContext as a field in your bean.
    - in a @PostConstruct method call context.getBean("${aaa.props}")
    - parse the result manually and set it to the desired fields
    Only it seems that
    Code:
    context.getBean("${a.b.c.1}");
    doesn't resolve to my property.

    I also tried to add a property which was:
    a.b.c.list=1,2,3
    but I can't get those properties from the context.

    Is there a way to solve this?

  2. #2
    Join Date
    Jun 2009
    Location
    Vicenza, Italy
    Posts
    84

    Default

    Maybe it's a silly question, but just to be sure, did you add the line
    HTML Code:
    <context:property-placeholder location="classpath:/META-INF/....." />
    to your app config?

    Regards,
    Stefano

  3. #3

    Default

    Quote Originally Posted by zakhrim View Post
    Maybe it's a silly question, but just to be sure, did you add the line
    HTML Code:
    <context:property-placeholder location="classpath:/META-INF/....." />
    to your app config?

    Regards,
    Stefano
    Yes, I added the property-placeholder, other properties were being resolved.

    My current solution is:
    Code:
    /**
     * Allows for making a Map from a properties file from a classpath location available in a bean factory. Can be used to
     * populate any bean property of type Map via a bean reference.
     * 
     * <p>
     * Supports loading from a properties file and/or setting local properties on this FactoryBean. The created Properties
     * instance will be merged from loaded and local values. If neither a location nor local properties are set, an
     * exception will be thrown on initialization.
     * 
     * @see #setLocation
     * @see #setProperties
     * @see #setLocalOverride
     * @see java.util.Properties
     */
    public class MapFactoryBean extends PropertiesLoaderSupport implements FactoryBean<Map<String, String>> {
    
        private static final Logger LOG = LoggerFactory.getLogger(MapFactoryBean.class);
        private String mapPropertyName;
    
        @Override
        public Map<String, String> getObject() throws IOException {
            Properties props = mergeProperties();
            Map<String, String> map = Maps.newHashMap();
            boolean valid = true;
    
            String keyList = props.getProperty(mapPropertyName + ".list");
            if (StringUtils.isEmpty(keyList)) {
                LOG.error("Failed to read map '{}', missing list property.", mapPropertyName);
                valid = false;
            } else {
                valid = createMap(props, map, keyList);
            }
            if (valid) {
                return map;
            } else {
                throw new IllegalStateException("Failed to read map '" + mapPropertyName + "'.");
            }
        }
    
        private boolean createMap(final Properties props, final Map<String, String> map, final String keyList) {
            boolean valid = true;
            String[] keys = StringUtils.split(keyList, ",");
            for (String key : keys) {
                String value = props.getProperty(mapPropertyName + "." + key);
                if (value == null) {
                    LOG.error("Failed to read map '{}': Missing value for key '{}'", mapPropertyName, key);
                    valid = false;
                } else {
                    map.put(key, value);
                }
            }
            return valid;
        }
    
        @Override
        public Class<?> getObjectType() {
            return Map.class;
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    
        /**
         * @param mapPropertyName
         *            the mapPropertyName to set
         */
        public void setMapPropertyName(final String mapPropertyName) {
            this.mapPropertyName = mapPropertyName;
        }
    }
    And configure it like this:
    Code:
        <bean id="sampleBean" class="com.example.SampleBeanl">
            <property name="mapName">
                <bean class="com.example.spring.MapFactoryBean">
                    <property name="location" value="classpath:example.properties" />
                    <property name="mapPropertyName" value="com.example.map" />
                </bean>
            </property>
        </bean>
    And this works. (And I now see I won't need the list property, I could just iterate over all the properties and only pick the ones starting with the mapPropertyName.)

  4. #4
    Join Date
    Dec 2009
    Location
    India
    Posts
    108

    Default

    Spring doesn't have any in-built support for use-cases like this and your solution seems fine if its working correctly as per expectations in your code-base.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •