从带有反射的解析字符串中获取正确的方法

时间:2013-05-31 15:54:41

标签: java parsing reflection

我创建了一个泛型类,它将Object作为输入,并实现了一个方法,该方法给出了该对象的方法及其参数之一的字符串表示(即“charAt(3)”),进行解析并查找并擦拭正确的方法。 我能够让它为没有参数的方法运行但是由于我不理解的原因而继续对其他一些方法(如charAt for strings)失败。 这是代码。

public class MiniInterpreter<T> 
{
private Class<?> objClass;
private T object;

public MiniInterprete(T object)
{
    objClass = object.getClass();
    this.object = object;
}

private static boolean isNumeric(String str)  
{  
  try  
  {  
    @SuppressWarnings("unused")
    int i = Integer.parseInt(str);  
  }  
  catch(NumberFormatException nfe)  
  {  
    return false;  
  }  
  return true;  
}

private static boolean isBoolean(String str)
{
    return (str.equalsIgnoreCase("true") || str.equalsIgnoreCase("false"));
}


private static boolean isDouble(String str)
{
    try
    {
        @SuppressWarnings("unused")
        double d = Double.parseDouble(str);
    }
    catch(NumberFormatException nfe)
    {
        return false;
    }
    return true;
}

public String getName(int index, String str)
{
    if(str.charAt(index) == '(' || str.charAt(index) == ')')
        return "";
    else
        return str.charAt(index) + getName(index + 1, str);
}

public String getParameters(int index, String str)
{
        switch(str.charAt(index))
        {
        case '(': return "" + getName(index + 1, str);
        default: return getParametri(index + 1, str);
        }
}

public Object parse(String method) throws GenericErrorException
{
    String name = getName(0,method);
    String parameters = getParameters(0,method);

    if(!parameters.equals(""))
    {
        return parseParameters(name, parameters.split(","));
    }

    Method m = null;

    try 
    {
        m = objClass.getMethod(name);
    } 
    catch (NoSuchMethodException e) {e.printStackTrace();} 
    catch (SecurityException e) {e.printStackTrace();}

    try 
    {
        return m.invoke(object);
    } 
    catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {throw new GenericErrorException();}

}

private Object parseParameters(String name, String[] parameters) throws GenericErrorException
{
    List<Class<?>> parametersList = new ArrayList<Class<?>>();
    List<Object> parametersArray = new ArrayList<Object>();

    for(String s : parameters)
    {
        Object obj = null;

        if(isNumeric(s))
        {
            obj = Integer.parseInt(s);
        }
        else if(isDouble(s))
        {
            obj = Double.parseDouble(s);
        }
        else if(isBoolean(s))
        {
            obj = Boolean.parseBoolean(s);
        }
        else
            obj = s;

        parametersList.add(obj.getClass());
        parametersArray.add(obj);
    }

    Method m = null;
    Class<?>[] parametersTypeArray = parametersList.toArray(new Class<?>[parametersList.size()]);

    try 
    {
            m = objClass.getMethod(name, parametersTypeArray );
    } 
    catch (NoSuchMethodException | SecurityException e) {e.printStackTrace();}

    try 
    {

        return m.invoke(object, parametersArray.toArray());
    } 
    catch (IllegalAccessException | IllegalArgumentException
            | InvocationTargetException e) {throw new GenericErrorException();}

}

}

唯一允许的类型是String,Integer,Boolean和Double,它对于查找方法也是如此,我还假装没有多个方法使用该名称和参数,我只是好奇要知道我是否忽略了某些内容,或者代码是否由于此限制而无法正常工作。 当它不起作用时,我得到noSuchMethod异常,当然,nullPointer是因为它没有初始化Method。

2 个答案:

答案 0 :(得分:0)

正如user1676075建议的那样,您的问题是您正在寻找一种不存在的方法,因为您的签名错误。

String#charAt(int)就是你举的例子。签名是基本类型int,它与类Integer不同。你正在使用

obj = Integer.parseInt(s)

返回int类型,所以你可能认为你得到了一个原语。但是你不能在对象中存储原语,而Java知道这一点。由于objObject,因此Java会将原始int自动加载到Integer。然后你要求一个名为charAt和签名Integer的方法,JRE说它从未听说过。

如果您满足使用int的方法,并忽略任何需要Integer的方法(将覆盖大部分标准库),你可以指定类型:

obj = Integer.parseInt(s);
parametersList.add(Integer.TYPE);  // the type of primitive ints

但是,如果您想要正确执行此操作,则需要使代码更复杂。我打电话给Class#getMethod(),而不是打电话给Class#getDeclaredMethods(),找到那些有您正在寻找的名字的子集,然后看看该方法的参数列表是否与您的类型兼容参数。

答案 1 :(得分:0)

添加.class修复程序在所有公共方法上顺利运行,错误在私有方法parseParameters中,甚至不需要为两个不同的情况(解析带参数的字符串或空( )),给getMethod一个空列表无论如何都会得到正确的结果,谢谢你的支持。

for(String s : parameters)
    {

        if(isNumeric(s))
        {
            parametersList.add(int.class);
            parametersArray.add(Integer.parseInt(s));
        }
        else if(isDouble(s))
        {
            parametersList.add(double.class);
            parametersArray.add(Double.parseDouble(s));
        }
        else if(isBoolean(s))
        {
            parametersList.add(boolean.class);
            parametersArray.add(Boolean.parseBoolean(s));
        }
        else
        {
            parametersList.add(s.getClass());
            parametersArray.add(s);
        }