Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/381.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 通过反射调用Oracle JDBC PreparedStatement方法失败_Java_Oracle_Jdbc_Reflection - Fatal编程技术网

Java 通过反射调用Oracle JDBC PreparedStatement方法失败

Java 通过反射调用Oracle JDBC PreparedStatement方法失败,java,oracle,jdbc,reflection,Java,Oracle,Jdbc,Reflection,我正在使用标准的OracleJDBC驱动程序(JDK6瘦驱动程序),并试图通过反射调用PreparedStatement上的方法。我可以直接调用该方法,但当我试图通过反射调用(我认为是)相同的方法时,我会得到一个IllegalAccessException,指示我尝试调用的方法没有公共访问权限。检查类返回的Method对象,它显示它是一个publci方法(即Modifier=1) 使用其他JDBC驱动程序(IBM的DB2、Microsoft的SQLServer、PostgreSQL等)进行的相同

我正在使用标准的OracleJDBC驱动程序(JDK6瘦驱动程序),并试图通过反射调用PreparedStatement上的方法。我可以直接调用该方法,但当我试图通过反射调用(我认为是)相同的方法时,我会得到一个IllegalAccessException,指示我尝试调用的方法没有公共访问权限。检查类返回的Method对象,它显示它是一个publci方法(即Modifier=1)

使用其他JDBC驱动程序(IBM的DB2、Microsoft的SQLServer、PostgreSQL等)进行的相同测试都能按预期工作

由于此代码最终用于Glassfish容器中的JEE应用程序,因此我使用的是数据源,而不是简单的连接

下面是一个简短测试程序(删除了敏感项)的片段,它说明了问题:-

System.out.println("Creating DataSource");
DataSource ds = new OracleDataSource();
((OracleDataSource) ds).setUser("HINT");
((OracleDataSource) ds).setPassword("hint");
((OracleDataSource) ds).setURL("jdbc:oracle:thin:@server-name:1521:database-name");
Connection dbCon = ds.getConnection();
dbCon.setAutoCommit(true);
System.out.println("Connection obtained : " + dbCon.getClientInfo());
PreparedStatement pstmt = (OraclePreparedStatement)dbCon.prepareStatement("SELECT * FROM \"HINT\".\"COUNTRIES1\" WHERE \"COUNTRY_ID\" = ?");

if (useReflection)  // True=Fails, False=Works!
{
    Class clazz = pstmt.getClass();
    Method method = clazz.getMethod("setString", new Class[]{int.class, String.class});
    System.out.println("Modifiers=" + method.getModifiers());
    System.out.println(method.toGenericString());        
    String value = "EG";
    Object[] pstmtParams = new Object[]{new Integer(1), value};  
    method.invoke(pstmt, pstmtParams);              // <<< Fails here
}
else
{
 pstmt.setString(1, "EG");
}
深入研究,驱动程序返回的PreparedStatement对象似乎是一个包装类(OraclePreparedStatementWrapper),它扩展并实现了各种内部类,因此显然它在幕后做了一些聪明的事情。然而,我一直认为,直接或通过反射调用标记为公共访问的方法应该没有区别


这里显然有点不对劲,但我就是看不出来….

我认为问题在于,您试图使用一种方法,这种方法是通过一个您无权访问的类请求的。这显然隐式地限制了方法的可见性,即使方法本身是公共的

下面是一个类似的例子:

// Foo.java
public interface Foo {
    void method();
}

// FooFactory.java
package foo;

public class FooFactory {
    public static Foo getFoo() {
        return new FooImpl();
    }
}

// FooImpl.java
class FooImpl implements Foo {
   @Override
   public void method() {
       System.out.println("FooImpl.method");
   }
}

// Bar.java
package bar;

import foo.*;
import java.lang.reflect.*;

public class Test {
    public static void main(String[] args) throws Exception {
        Foo foo = FooFactory.getFoo();
        Method method = foo.getClass().getMethod("method");
        method.invoke(foo);
    }
}
这与代码的失败方式相同:

Exception in thread "main" java.lang.IllegalAccessException:
    Class bar.Test can not access a member of class foo.FooImpl with modifiers "public"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:109)
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:261)
    at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:253)
    at java.lang.reflect.Method.invoke(Method.java:599)
如果您通过可以看到的界面询问方法,则可以:

Method method = Foo.class.getMethod("method");
同样,在代码中,您只需更改这一行:

Class clazz = pstmt.getClass();
致:


您是否尝试过调用
PreparedStatement.class.getMethod(…)
?这将更接近无反射方法。是的,这解决了它。非常感谢。虽然我理解为什么这样做可以解决问题,但我仍然不完全理解为什么使用实现类中的Method对象会失败。你愿意让我写下来作为答案吗,还是你打算删除这个问题?我可能会尝试复制它…请随意研究和回答,因为我真的很想理解这一点。谢谢你给了我一个快速的解决方案:-)好的,我想我明白了。。。我会写一个答案。
Class clazz = pstmt.getClass();
// TODO: Change it to Class<?> to avoid the raw type :)
Class clazz = PreparedStatement.class;
Method method = PreparedStatement.class.getMethod(...);