使用iPOJO时抛出异常java.lang.UnsupportedOperationException: Cannot add elements inside this collection

 

felix ipojo
felix ipojo

Felix iPOJO的功能很强大,配置也比较复杂,配置和实现代码之间有着千丝万缕的关联,完全脱离代码去配置iPOJO的component和instance势必不会达到自己想要的依赖注入效果,甚至很难查到问题的原因。尽管iPOJO的配置有iPOJO xml schemaiPOJO Annotation,但是仅仅按照schema和annotation来不一定能配置正确,还需要理解iPOJO配置背后的一些机制和原理,否则会出现一些奇怪的异常。见如下的代码和iPOJO annotation注解:

上面的代码乍一看没啥问题,但是其实这个component的timeoutConfigList属性是无法注入成功的,这和iPOJO的一些的依赖注入实现机制有关系,如果用以上的代码来配置instance,在启动这个component和instance所在的bundle时会抛出以下的异常堆栈:

我们可以看到属性timeoutConfigList是List集合类型,它上有@Requires的annotaion,又有对这个属性的@Bind和@Unbind方法。这种用法是不合适的。如果使用不当就会出现上面的异常。因为当在一个属性上注明了@Requires的annotaion时,就表示这个属性需要由ipojo来负责依赖注入,ipojo默认会为集合类型的属性创建一个ServiceCollection类的代理对象,也就是说timeoutConfigList属性在被替换成了ServiceCollection类的对象,调用这个对象里的所有修改方法都会抛出UnsupportedOperationException异常,因为这个属性已经交由ipojo的来维护了,对其进行修改、添加或者删除的话,可能会导致ipojo维护对象的混乱。而@Bind和@Unbind方法是在属性的代理对象创建后,当有适合的属性类型的对象满足注入条件时回调的方法,在以上的代码中有add和remove的操作自然会导致抛出上面的异常了。

解决办法

方法一: 同时使用@Requires注解以及@Bind和@Unbind方法时,保证@Bind和@Unbind方法中没有修改操作(可以执行非修改操作,比如contains、size、get等,详见ServiceCollection类的源码)

方法二: @Requires注解与@Bind、@Unbind方法不同时出现。其实@Bind、@Unbind方法基本包含了@Requires注解的功能,而且还可以对这个属性对象的注入进行aop操作,相比@Requires注解只是需要多写些判空和初始化的代码而已。

方法三:在示例代码的基础上,在@Requires的注解中添加proxy=false,这样示例代码就不会抛出异常了(这个时候这个属性在没有被bind过前,其值为null,所以需要做判空处理),比如下面的写法:

(如果没有使用annotation,而是component的配置也是用的xml方式,解决方案还是如上面的讲的三点相类似。)

 

发表评论

电子邮件地址不会被公开。

eight × 1 =