Java-使用实例反射防止字段分配?

Java-使用实例反射防止字段分配?,java,reflection,constructor,Java,Reflection,Constructor,我在第三方库中有一个java类,它有一个私有成员,在类实例化时分配 public class CacheLookupUtil extends AbstractCacheLookupUtil<InvocationContext> { @Inject private BeanManagerUtil beanManagerUtil; private CacheKeyGenerator defaultCacheKeyGenerator = new DefaultCacheKey

我在第三方库中有一个java类,它有一个私有成员,在类实例化时分配

public class CacheLookupUtil extends AbstractCacheLookupUtil<InvocationContext> {
  @Inject
  private BeanManagerUtil beanManagerUtil;

  private CacheKeyGenerator defaultCacheKeyGenerator = new DefaultCacheKeyGenerator();
  private CacheResolverFactory defaultCacheResolverFactory = new DefaultCacheResolverFactory();

  ...
  ...
}
公共类CacheLookupUtil扩展了AbstractCacheLookupUtil{
@注入
私人Bean管理Rutil Bean管理Rutil;
private CacheKeyGenerator defaultCacheKeyGenerator=新的defaultCacheKeyGenerator();
private CacheResolverFactory defaultCacheResolverFactory=new defaultCacheResolverFactory();
...
...
}
我的问题是,
defaultCacheResolverFactory
的赋值导致异常,因为选择了错误的构造函数

如果我尝试子类化
CacheLookupUtil
,这个赋值仍然是在父类中完成的,因此我不再领先了

Java反射中是否有任何机制允许我构造/实例化对象,但阻止分配
defaultCacheResolverFactory
,并允许我通过反射设置值


我知道这是一个丑陋的解决方案,但老实说,我无法想象任何其他方式继续进行。

DefaultCacheSolverFactory是您的库jar的一部分吗

  • 如果不是,我猜这是一个版本问题

  • 否则,您应该查找库的错误修复版本或打开票据

  • 最后但并非最不重要的一点是,您可以使用AspectJ加载时编织在类加载时操作字节码。但这要求您总是以加载时编织开始代码。看


  • 所以我个人更喜欢选项1或2。

    检查包含
    CacheLookupUtil
    的库的版本(我知道它是第三方类)。例如,假设它是jar-A

    然后检查包含
    DefaultCacheResolverFactory
    的jar版本。如果它也是jar-A,这实际上意味着这个库在这个版本下不工作,所以您应该升级。 如果它在某个jar-B中,那么检查jar-A本身的
    pom.xml
    ,需要对jar-B的依赖关系的哪个版本,可能您覆盖了这个jar的版本

    然后调整版本,使jar-A对jar-B版本的期望值匹配:)

    对我来说,这是最好的解决办法

    至于肮脏的把戏。一个技巧是创建自己的
    CacheLookupUtil
    副本并将其放入同一个包中,这取决于类装入器策略(您没有指定在哪个环境中运行,所以我假设是纯java),它可能会首先从jar中有效地“替换”
    CacheLookupUtil

    当然,
    DefaultCacheResolverFactory
    也可以这样做(这样您就可以修复那里的no-op构造函数)

    如果你认为它是一个真正的bug,那么另一个选择就是从“Bugy”库中分叉,并用固定方法创建它自己的版本。当然,您最好让原始库的开发人员来修复这个bug,这样最终您就可以返回到官方版本,在开源世界中,有时像这样的解决方案可以工作,只要许可证允许这样做


    如果没有帮助,那么字节码操作是修复@PowerStat的唯一方法。我相信,Java代理、类加载修补、AspectJ等等。希望您不会仅仅因为这个问题而到达那里:)

    不幸的是,这是库的设计(org.jsr107.ri:cache annotations ri cdi:1.1.1)。
    CacheLookupUtil
    类就是这样设计的,即使是最新版本也是这样实现的。我希望我可以用反射来玩一些把戏,但是没有AspectJ我无论如何也找不到。我通过在自己的包中创建自己的类,然后将整个库着色到自己的包结构中,成功地解决了这个问题,但这是一个非常丑陋的解决方案,我并不特别喜欢。反射不允许更改类的结构。仅查询结构并将值设置为字段…看起来我坚持使用AJ。但我不确定我需要在这样的东西上设置什么样的切入点。如果我对字段的set()方法设置切入点,它将拦截任何setter。如果我在CacheLookupUtil类的构造函数上设置一个切入点,我不确定这会如何影响私有字段的初始化,
    DefaultCacheResolverFactory()是否会
    仍然被调用?我想这会更好地回答您的问题,就像我自己写的那样:我仍然不确定使用哪个切入点来替换字段的初始化。它必须是
    初始化(*.new(..)
    切入点吗?但是,如何防止原始类执行实际的初始化呢?或者我必须组合
    初始化(*.new(..)
    集合(CacheResolverFactory defaultCacheResolverFactory)
    ?或者我可以对初始化和设置使用一个环绕切入点来防止该字段被设置并替换对象吗?我认为这需要深入理解对象实例化,如中所述:在此之后,您可能很幸运,
    defaultCacheResolverFactory
    不是最终的,这样您就可以在构造函数中再次初始化它。最后但并非最不重要的一点是:请记住,您需要一个精确的签名才能与
    CacheLookupUtil
    的构造函数匹配,因此不要使用星号。