将未知对象转换为适当的Method.invoke参数的有效方法?

时间:2009-09-29 19:18:00

标签: java reflection

我正在编写一个基于反射的RPC服务,它通过各种机制传递参数。有时参数正确地匹配参数类型,有时它们总是字符串,有时它们被包含在需要提取适当值的动态类型“scripty”对象中。

在我调用method.invoke之前,我需要构建参数列表,如下所示:

Object a[] = new Object[method.parameterClasses.length];
for (int i = 0; i < a.length; ++i)
{
   a[i] = prepare(method.parameterClasses[i], rpc.arguments[i]);
}

“prepare”方法类似于:

Object prepare(Class clazz, Object o)
{
   if (o == null) return null;
   if (clazz == o.getClass()) return o;
   if (clazz == String.class) return o.toString();

   // skip a bunch of stuff for converting strings to dates and whatnot

   // skip a bunch of stuff for converting dynamic types

   // final attempts:
   try
   {
       return clazz.cast(o);
   }
   catch (Exception e)
   {
       return o;     // I give up.  Try the invoke and hope for the best!
   }


}

在单元测试期间,我最近很惊讶地发现一个方法传递了一个盒装的Integer,它期望一个原始long实际上使得强制转换失败并从底部掉落,然后在invoke()期间被某些东西正确转换。我假设“演员”的召唤可以解决问题。有没有办法通过调用显式执行和检查正常完成的参数转换?

缺乏这一点,我考虑过对数字类型进行显式检查,但是排列的数量似乎无法控制。当我添加从脚本动态类型和转换字符串中提取数字的支持时,它会变得更糟。我设想了每个可能的数字目标类的一组条件类型检查,其中包含Integer.decode,Long.decode等用于String参数,Short.decode和Number.intValue,Number.longValue等用于Numbers。

有没有更好的方法来做这整件事?起初它似乎是一种很好的方法,但它变得非常令人讨厌。

3 个答案:

答案 0 :(得分:2)

这确实令人惊讶,但那是当前的行为。请参阅错误6456930

就解决问题的更好方法而言,不是你必须定义所有这些规则。但是,有一系列if的更好(更易于维护)的模式。对于初学者,我有一些策略对象可以调用这些对象的一侧(可能是类侧),以便您根据类查找相应的对象(比如从Map),然后您可以限制你的转换到一边(每个对象都会关心如何把东西放到那个特定的类中)。这样,当你需要支持一种新的类转换时,你可以为它编写一个对象,单独测试它,然后只需将其插入地图而不需要更改其他代码。

答案 1 :(得分:1)

真的没有更好的方法。有无数的潜在转换,但只有极少数真正有意义。我建议不要试图给予客户完全的自由,而是建议签订类型强制合同。

作为一个起点,请查看JSP Expression Language.使用的类型转换规则。它们非常强大,允许进行多种类型的转换,但它们也定义明确,易于记忆,并且可以实施。

答案 2 :(得分:0)

您可以使用至少一些快捷方式来简化代码:

  • 如果参数是java.lang.Number的一个实例,并且参数类型是byte,short,int,long,float或double(作为基元或包装类),则可以使用数字中的方法,如byteValue(),shortValue()等,以转换参数。

  • 如果参数是java.lang.String的一个实例,并且参数类型是上面提到的一个,则可以在相应的类中使用静态valueOf(String)方法进行转换。

进一步转换,甚至专有类型当然需要更多的工作。如果真的有必要并且您的准备方法变得越来越大,您应该考虑抽象接口后面的转换并允许可插拔转换提供程序动态添加到应用程序中吗?