首页 > 解决方案 > Java反射错误Java.lang.NoSuchMethodException,但方法存在

问题描述

我无法在 Spring Boot 中使用 Controller 和 JdbcTemplate 进行 Java 反射。

默认控制器如下所示:

public class DefaultController {

private static final Logger logger = LoggerFactory.getLogger(DefaultController.class);

public JsonResponseDataModel selectOneAuto(Long id, Class<?> repository, HttpServletResponse response){

    final JsonResponseDataModel result = new JsonResponseDataModel();
    System.out.println("The name of class is " + repository.getName());

    Method[] methods = repository.getMethods();
    for (Method method : methods) {
        System.out.println("Method: " + method.getName());
    }

    try {
        //Method method = repository.getClass().getMethod("selectOne", Long.class);
        Method method = repository.getClass().getDeclaredMethod("selectOne", Long.class);
        method.invoke(repository, id);

        logger.info("selectOneAuto : id={} ", id);
    } catch (EmptyResultDataAccessException e) {
        result.setEmptyResultDataAccessException("id", id.toString());
    } catch (DataAccessException e) {            
        e.printStackTrace();            
    } catch (NoSuchMethodException e) {            
        e.printStackTrace();            
    } catch (IllegalAccessException e) {            
        e.printStackTrace();            
    } catch (InvocationTargetException e) {            
        e.printStackTrace();            
    }
    return result;
}

}

在 CompanyRepository 类中定义了带有 Long 输入的 selectOne 方法:

@Transactional(readOnly=true)
     public CompanyModel selectOne(Long id) {
     CompanyModel result = null;
     final String sql = "SELECT * FROM company WHERE id=?";
     return jdbcTemplate.queryForObject(sql, new Object[]{id}, new CompanyRowMapper());
}

当我创建一个新类“CompanyController extends DefaultController”并调用方法 selectOneAuto 时:

selectOneAuto(id, new CompanyRepository().getClass(), response);

然后它以“Method method = repository.getClass().getDeclaredMethod("selectOne", Long.class);" 行错误结束

"Java.lang.NoSuchMethodException: java.lang.Class.selectOne(java.lang.Long)"

但是“selectOneAuto”方法中的 for 循环输出名为“selectOne”的方法。这里有什么问题?

标签: javaspring-bootmethodsreflection

解决方案


您的代码尝试在Class.

方法.invoke(存储库,id);

存储库对象是一个实例,Class因为您new CompanyRepository().getClass()作为参数传递。

要注意的第二点是存储库已经是 Class 的实例,因此无需在此对象上调用 getClass()。

您应该使用以下代码获取方法对象:

Method method = repository.getDeclaredMethod("selectOne", Long.class);

然后这应该工作:

CompanyRepository repsitoryObj = new CompanyRepository();
method.invoke(repsitoryObj, id);

或者更好更简洁的方法是简单地更改repository参数的类型,因为CompanyRepository您的方法如下所示:

public JsonResponseDataModel selectOneAuto(Long id, CompanyRepository repository, HttpServletResponse response){

    final JsonResponseDataModel result = new JsonResponseDataModel();
    System.out.println("The name of class is " + repository.getClass().getName());

    Method[] methods = repository.getClass().getMethods();
    for (Method method : methods) {
    System.out.println("Method: " + method.getName());
    }

    try {
    //Method method = repository.getClass().getMethod("selectOne", Long.class);
    Method method = repository.getClass().getDeclaredMethod("selectOne", Long.class);
    method.invoke(repository, id);

    logger.info("selectOneAuto : id={} ", id);
    } catch (EmptyResultDataAccessException e) {
    result.setEmptyResultDataAccessException("id", id.toString());
    } catch (DataAccessException e) {            
    e.printStackTrace();            
    } catch (NoSuchMethodException e) {            
    e.printStackTrace();            
    } catch (IllegalAccessException e) {            
    e.printStackTrace();            
    } catch (InvocationTargetException e) {            
    e.printStackTrace();            
    }
    return result;
}

推荐阅读