实例化 JNA 结构的子类抛出 IllegalAccessException
Instantiating subclass of JNA Structure throws IllegalAccessException
我无法让 com.sun.jna.Structure
工作,所以我尝试复制 the first JNA test I found 但我什至无法让 that 工作。
为了方便,试试online。
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.List;
public class MyClass {
public void testSimpleSize() throws Exception {
class TestStructure extends Structure {
public int field;
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("field");
}
}
Structure s = new TestStructure();
//assertEquals("Wrong size", 4, s.size());
}
public static void main(String[] args)
{
try
{
new MyClass().testSimpleSize();
}
catch (Exception e)
{
System.out.println(e);
}
}
}
代码编译正常,但是当 运行 我得到
Exception in thread "main" java.lang.Error: Exception reading field 'field' in class MyClassTestStructure
at com.sun.jna.Structure.getFieldValue(Structure.java:639)
at com.sun.jna.Structure.deriveLayout(Structure.java:1285)
at com.sun.jna.Structure.calculateSize(Structure.java:1159)
at com.sun.jna.Structure.calculateSize(Structure.java:1111)
at com.sun.jna.Structure.allocateMemory(Structure.java:414)
at com.sun.jna.Structure.<init>(Structure.java:205)
at com.sun.jna.Structure.<init>(Structure.java:193)
at com.sun.jna.Structure.<init>(Structure.java:180)
at com.sun.jna.Structure.<init>(Structure.java:172)
at MyClassTestStructure.<init>(MyClass.java:8)
at MyClass.testSimpleSize(MyClass.java:15)
at MyClass.main(MyClass.java:23)
Caused by: java.lang.IllegalAccessException: class com.sun.jna.Structure cannot access a member of class MyClassTestStructure with modifiers "public"
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:591)
at java.base/java.lang.reflect.Field.checkAccess(Field.java:1075)
at java.base/java.lang.reflect.Field.get(Field.java:416)
at com.sun.jna.Structure.getFieldValue(Structure.java:636)
... 11 more
我是不是漏掉了什么?
我找到了一个解决方案,它比我想象的要简单得多。
根据 documentation,
An IllegalAccessException is thrown when an application tries to reflectively create an instance (other than an array), set or get a field, or invoke a method, but the currently executing method does not have access to the definition of the specified class, field, method or constructor.
这意味着 com.sun.jna.Structure
需要访问 TestStructure
,以便使用反射(它需要反射才能获取结构字段)。解决这个问题的最简单方法是将 TestStructure
移出函数并使其成为 public。像这样:
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.List;
public class MyClass {
public class TestStructure extends Structure {
public int field;
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("field");
}
}
public void testSimpleSize() throws Exception {
Structure s = new TestStructure();
//assertEquals("Wrong size", 4, s.size());
}
public static void main(String[] args)
{
try
{
new MyClass().testSimpleSize();
}
catch (Exception e)
{
System.out.println(e);
}
}
}
可能有更好的解决方案,但这是最简单的并且适合我。
正如您所发现的 ,问题的根本原因(如堆栈跟踪所示)是缺少对 class 的反射访问。虽然您的回答解决了您的具体问题,但我想详细说明发生这种情况的更多可能原因,这可能会对其他人有所帮助。
您链接到的 JNA 测试用例起作用的原因是因为测试 resides in the same package 作为结构 class,它赋予 Structure
class 包私有访问权限classes。在您的情况下,内部 class TestStructure
没有 public
修饰符,并且位于与 com.sun.jna.Structure
.
不同的包中
您通过将 class 移动到可访问的位置解决了问题,这很有效。在 JNA 实现中,结构通常在接口中声明(因此默认为 public
)。
如果您正在使用 Java 模块 (JPMS),则出现此错误的第二种可能性。 Java 模块默认不允许反射访问,因此必须在 module-info.java
class 中明确允许,或者使用 opens your.package to com.sun.jna;
(以允许 运行time-仅包含私有成员的反射)或 exports your.package to com.sun.jna;
(以允许编译时和 运行 时 public 访问)。虽然这不适用于您的情况(您使用的是未命名模块中的默认包),但如果您创建模块化项目,将来可能会遇到这种情况。
我无法让 com.sun.jna.Structure
工作,所以我尝试复制 the first JNA test I found 但我什至无法让 that 工作。
为了方便,试试online。
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.List;
public class MyClass {
public void testSimpleSize() throws Exception {
class TestStructure extends Structure {
public int field;
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("field");
}
}
Structure s = new TestStructure();
//assertEquals("Wrong size", 4, s.size());
}
public static void main(String[] args)
{
try
{
new MyClass().testSimpleSize();
}
catch (Exception e)
{
System.out.println(e);
}
}
}
代码编译正常,但是当 运行 我得到
Exception in thread "main" java.lang.Error: Exception reading field 'field' in class MyClassTestStructure
at com.sun.jna.Structure.getFieldValue(Structure.java:639)
at com.sun.jna.Structure.deriveLayout(Structure.java:1285)
at com.sun.jna.Structure.calculateSize(Structure.java:1159)
at com.sun.jna.Structure.calculateSize(Structure.java:1111)
at com.sun.jna.Structure.allocateMemory(Structure.java:414)
at com.sun.jna.Structure.<init>(Structure.java:205)
at com.sun.jna.Structure.<init>(Structure.java:193)
at com.sun.jna.Structure.<init>(Structure.java:180)
at com.sun.jna.Structure.<init>(Structure.java:172)
at MyClassTestStructure.<init>(MyClass.java:8)
at MyClass.testSimpleSize(MyClass.java:15)
at MyClass.main(MyClass.java:23)
Caused by: java.lang.IllegalAccessException: class com.sun.jna.Structure cannot access a member of class MyClassTestStructure with modifiers "public"
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:591)
at java.base/java.lang.reflect.Field.checkAccess(Field.java:1075)
at java.base/java.lang.reflect.Field.get(Field.java:416)
at com.sun.jna.Structure.getFieldValue(Structure.java:636)
... 11 more
我是不是漏掉了什么?
我找到了一个解决方案,它比我想象的要简单得多。
根据 documentation,
An IllegalAccessException is thrown when an application tries to reflectively create an instance (other than an array), set or get a field, or invoke a method, but the currently executing method does not have access to the definition of the specified class, field, method or constructor.
这意味着 com.sun.jna.Structure
需要访问 TestStructure
,以便使用反射(它需要反射才能获取结构字段)。解决这个问题的最简单方法是将 TestStructure
移出函数并使其成为 public。像这样:
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.List;
public class MyClass {
public class TestStructure extends Structure {
public int field;
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("field");
}
}
public void testSimpleSize() throws Exception {
Structure s = new TestStructure();
//assertEquals("Wrong size", 4, s.size());
}
public static void main(String[] args)
{
try
{
new MyClass().testSimpleSize();
}
catch (Exception e)
{
System.out.println(e);
}
}
}
可能有更好的解决方案,但这是最简单的并且适合我。
正如您所发现的
您链接到的 JNA 测试用例起作用的原因是因为测试 resides in the same package 作为结构 class,它赋予 Structure
class 包私有访问权限classes。在您的情况下,内部 class TestStructure
没有 public
修饰符,并且位于与 com.sun.jna.Structure
.
您通过将 class 移动到可访问的位置解决了问题,这很有效。在 JNA 实现中,结构通常在接口中声明(因此默认为 public
)。
如果您正在使用 Java 模块 (JPMS),则出现此错误的第二种可能性。 Java 模块默认不允许反射访问,因此必须在 module-info.java
class 中明确允许,或者使用 opens your.package to com.sun.jna;
(以允许 运行time-仅包含私有成员的反射)或 exports your.package to com.sun.jna;
(以允许编译时和 运行 时 public 访问)。虽然这不适用于您的情况(您使用的是未命名模块中的默认包),但如果您创建模块化项目,将来可能会遇到这种情况。