Thursday, November 28, 2013

Spring 3 - SpEl solution for non existing optional @Resource injection

@Resource is used to inject resources into Spring beans - like in example below: MyService uses #serverMapping to map server aliases into full names.

  1 public class MyService {
  2
  3     @Resource(name = "serverMappingConf")
  4     private Map<String, String> serverMapping;
  5
  6     public String getFullName(String alias){
  7         return serverMapping.get(alias);
  8     }
  9 }

  1 <beans xmlns=....">
  2
  3      <util:map id="serverMappingConf">
  4          <entry key="serverEU" value="my-domain.eu" />
  5          <entry key="serverUS" value="my-domain.us" />
  6      </util:map>
  7 </beans>

This is not really spectacular, but in some cases it is required to inject null if #serverMappingConf is not defined (optional functionality). This is simple in case of spring bean, because you can use @Autowired(required="false"). But you cannot inject collections of resources using @Autowired - this was discussed in this JIRA case  - autowired would collect all beans of given type and try to inject it (case describes collections, but the same rules apply to maps).

This is the solution:
  1 public class MyService {
  2
  3     @Value("#{getObject('serverMappingConf')}")
  4     private Map<String, String> dcMappingInitial;
  5 }

@Value supports SpEl expressions. SpEl's root object has method getObject(String) which returns spring bean or resource, or null if was not found. We are calling this method with name of our resource - it returns Map<String, String> or null.