1

I would like to initialize a bean having the following property:

private Iterable<Map.Entry<String, String>> groupToAuthorityMappings;

In my context.xml, I expected to do it this way:

<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
         xmlns="http://www.springframework.org/schema/security"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
         http://www.springframework.org/schema/security
         http://www.springframework.org/schema/security/spring-security-3.1.xsd"
         default-autowire="byName">

    <beans:bean id="crowdUserDetailsService"
        class="com.atlassian.crowd.integration.springsecurity.user.CrowdUserDetailsServiceImpl">
        ...
        <beans:property name="groupToAuthorityMappings">
            <beans:map>
                <beans:entry key="Manager" value="ROLE_ADMINISTRATOR,ROLE_USER"/>
            </beans:map>
        </beans:property>
        ...
    </beans:bean>
</beans:beans>

But I get the following error:

java.lang.IllegalStateException: Cannot convert value of type [java.util.LinkedHashMap] to required type [java.lang.Iterable] for property 'groupToAuthorityMappings': no matching editors or conversion strategy found

I cannot change the bean since it comes from a provided library. Does anybody know how I can achieve my goal?

Kara
  • 6,115
  • 16
  • 50
  • 57
Asterius
  • 2,180
  • 2
  • 19
  • 27

2 Answers2

1

If you're defining this data as a Map, you can use a factory-method to get an iterator over the entries:

<util:map id='groupToAuthority>
    <beans:entry key="some-group" value="specific-authority-for-group" />
    ...
</util:map>

<bean class='ClassRequiringAnIterable'>
    <constructor-arg>
        <bean factory-bean='groupToAuthority' factory-method='entrySet'/>
    </constructor-arg>
</bean>

However, note that you require an Iterable<Map.Entry<String, String>>, and your sample defines a Map<String, List<String>>, so make sure that each group is mapped to exactly one role.

Joe
  • 29,416
  • 12
  • 68
  • 88
  • Indeed, my map cannot works this way. I will update my question. I tried your code, but I cannot create beans:map as a direct child of beans:beans. How to declare it? – Asterius Sep 30 '14 at 08:36
  • Ok, I successfully solved my issue: 1) Add http://www.springframework.org/schema/util and http://www.springframework.org/schema/util/spring-util-3.0.xsd in xsi:schemaLocation 2) Add xmlns:util="http://www.springframework.org/schema/util" in beans:beans 3) Use instead of as suggested in your answer 4) contructor-arg does not fit for the property, I used instead: – Asterius Sep 30 '14 at 08:59
0

Rather than mess around with trying to create iterables in spring xml, I would use this approach. Create a factory for the bean:

public class ThirdPartyBeanFactory {

    public ThirdPartyBean getInstance(Map<String,String> map) {
        ThirdPartyBean tpb = new ThirdPartyBean(); //This is the provided object you cant change
        tpb.setGroupToAuthorityMappings(map.entrySet());
        return tpb;
    }
}

Then in XML First create instance of the factory (thirdPartyBeanFactory) and map (mapBean).Then define your bean like so:

<bean id="thirdPartyBean" factory-bean="thirdPartyBeanFactory"
        factory-method="getInstance">
    <constructor-arg ref="mapBean" />
</bean>
cowls
  • 24,013
  • 8
  • 48
  • 78