Pyjnius: 在 1.2.1 中无法访问超类方法

创建于 2019-12-13  ·  20评论  ·  资料来源: kivy/pyjnius

arraylist = autoclass("java.util.ArrayList")()
arraylist.iterator()
arraylist.stream()

这适用于 1.2.0 但不适用于 1.2.1。

AttributeError                            Traceback (most recent call last)
<ipython-input-7-5e67e1c90388> in <module>()
----> 1 arraylist.stream()

AttributeError: 'java.util.ArrayList' object has no attribute 'stream'

可复制的笔记本在https://colab.research.google.com/drive/1F9u2jVQR5JFw_mk5Bq--VH1Ki91Xe5x3

stream() 在超级接口中定义为默认值。

我们在访问扩展 java.util.List 的接口中的方法时也遇到了问题。

最有用的评论

我观察到同样的问题,在 1.2.1 中无法访问超类方法,但在 1.2.0 中一切正常。 这是一个非常讨厌的错误,您认为删除 1.2.1 版本或以某种方式将其标记为不可用是否有意义?

所有20条评论

我可以在本地重现它,让我们看看它是否也发生在CI中,有时间我会寻找修复程序。

CI 失败了,但我看不出我们是如何在 1.2.1 中破坏它的。 我可以看到 getDeclaredMethods() 不包含默认实现的方法。 (它们没有在类或其超类型中声明)。

https://blog.jooq.org/2018/03/28/correct-reflective-access-to-interface-default-methods-in-java-8-9-10/中有一些讨论 - 我不_think_这个是相关的。

解决方案是否也遍历所有接口及其父接口添加默认方法? (我们可以添加抽象方法,但这似乎是多余的,因为它们必须由具体对象实现)。

这是我发现的最相关的 stackoverflow 线程: https :

似乎在不同的 JVM 实现中可能存在一些差异......

如果我首先转换为 java.util.Collection,它确实有效,但它应该没有必要......:/

我也认为这是因为使用 getDeclaredMethods 而不是 getMethods,我试图遍历所有接口,但不知何故它没有在 getInterfaces() 中找到 Collection 接口......

嗯,这似乎有效……不完全确定为什么。
https://github.com/kivy/pyjnius/pull/466/files#diff -06f2b31838f083623d82353f734d644a

编辑:呃,除了段错误...... https://github.com/kivy/pyjnius/runs/348651345
尝试再次运行,以防出现故障,在 ubuntu、python3.8、java 10 上再次崩溃……
编辑2:非常困惑,当我将 3.8/java10/ubuntu 排除在外时,所有当前组合都有效,然后我启用了 java 9 和 11,并且与 3.7/11/ubuntu 发生了相同的崩溃……至少我可以安装 openjdk-11-jdk在我的 ubuntu 和 python3.7 上轻松测试...... ...它工作正常。 格姆布尔。

https://dev.azure.com/conda-forge/feedstock-builds/_build/results?buildId=100815&view=logs&j=696704cc-6fef-57a3-ea36-f27779b8cd5e&t=06421391-4b55-8104b-fc
顺便说一句,似乎在 linux 上构建的 conda-forge 在 1.2.1 上也有一些段错误,所以这个问题可能在我改变之前就已经存在。

补丁对我有用

礼貌的撞。 把这个合并就好了。 我在 diff 中添加了一条注释,建议使用代码注释。

很抱歉让这个逗留,我真的不知道是什么阻止了 CI 的通过,而且我真的不喜欢禁用部分目标只是为了消除一个难以理解的错误,我同意让这个 bitrot 不是更好,但我'我不知道如何从这里开始。

我想知道这是否是 #480 中的并发问题,但我不认为 pytest 默认是并发的。

我尝试在本地复制,但没有成功复制#480。 这是我的命令 - 它是基于 Debian 的映像:

docker run -i continuumio/anaconda3 /bin/bash <<EOF

cat /etc/os-release
apt-get update
mkdir /usr/share/man/man1
apt-get -y install openjdk-11-jdk-headless gcc ant

conda create -y -n pyjnius python=3.7.5
conda activate pyjnius

git clone https://github.com/kivy/pyjnius.git
cd pyjnius/
python -m pip install -U setuptools cython
python setup.py bdist_wheel
pip install --timeout=120 .[dev,ci]
ant all
cd tests/
CLASSPATH="../build/test-classes:../build/classes" PYTHONPATH=/opt/conda/envs/pyjnius/lib/python3.7/site-packages/ pytest -v
cd ../
git checkout -b issue_465 origin/issue_465

python setup.py bdist_wheel
pip install --timeout=120 .[dev,ci]
ant all
cd tests/
CLASSPATH="../build/test-classes:../build/classes" PYTHONPATH=/opt/conda/envs/pyjnius/lib/python3.7/site-packages/ pytest -v

EOF

所有测试都在 master 和 branch 上通过。

我观察到同样的问题,在 1.2.1 中无法访问超类方法,但在 1.2.0 中一切正常。 这是一个非常讨厌的错误,您认为删除 1.2.1 版本或以某种方式将其标记为不可用是否有意义?

很抱歉让这个逗留,我真的不知道是什么阻止了 CI 的通过,而且我真的不喜欢禁用部分目标只是为了消除一个难以理解的错误,我同意让这个 bitrot 不是更好,但我'我不知道如何从这里开始。

我可以建议重新运行 CI 测试吗? 我们可以尝试缩小范围吗 - 这是这个补丁的问题,还是之前版本的问题?

回到这个:

我不认为混合getDeclaredMethods()getMethods()是答案。 getMethods()就足够了。

我的测试用例是:

 def test_super_interface(self):
        LinkedList = autoclass('java.util.LinkedList')
        words = LinkedList()
        words.add('hello')
        words.add('world')
        q = cast('java.util.Queue', words)
        self.assertEqual(2, q.size())
        self.assertIsNotNone(q.iterator())

    def test_super_object(self):
        LinkedList = autoclass('java.util.LinkedList')
        words = LinkedList()
        words.hashCode()

    def test_super_interface_object(self):
        LinkedList = autoclass('java.util.LinkedList')
        words = LinkedList()
        q = cast('java.util.Queue', words)
        q.hashCode()

当我们只使用 getDeclaredMethods() 时,各种失败。

我对getMethods()唯一问题是test_inheritance.py失败了。 这只是轻微的问题 - org.jnius.Child 的静态newInstance()覆盖了 org.jnius.Parent newInstance()方法。 发生的情况是getMethods()看到了两个newInstance()方法,因此构造了一个 JavaMultipleMethod。 这是错误的: Child.newInstance()应该隐藏Parent.newInstance() - 参见https://www.java67.com/2012/08/can-we-override-static-method-in-java.html。 我还使用 Jshell 验证了这一点:

jshell> org.jnius.Child.newInstance()
$3 ==> org.jnius.Child<strong i="24">@506c589e</strong>

@tshirtman我看到你提交了 getMethods()。 我也推荐上面的其他测试用例。
我不确定如何解决隐藏 Child.newInstance() 应该隐藏 Parent.newInstance() 的静态方法。 我认为您必须在 autoclass() 中重新排序类和接口的迭代 - 遍历树以获取类,然后以相反的顺序应用它们,即从 java.lang.Object 开始。

嗯,确实添加此测试表明,当前转换为java.util.Queue自动类的对象没有size属性,这是错误的。
我同意你的分析,反向查找,用相同的签名替换父方法而不是创建 JavaMultipleMethod,这似乎是一个很好的策略。

501 通过了所有测试。 关闭这个问题。 (赞美)。

仍然缺少受保护的字段!

将此行public更改protected测试失败。

关于#500 是否应该公开私有/受保护方法/字段的讨论。

我认为这是不同的,目前我们应该拥有一切,并且通过您的修复,方法似乎是正确的,但显然它不是(并且可能永远不是?)对于字段,所以我认为这是一个首先要解决的错误,然后我们是否决定允许过滤我们想要查看的方法/字段,具体取决于它们的隐私级别。 由于此错误已关闭,因此我为该案例打开一个新错误对我来说很有意义。

这对于方法来说似乎是正确的,但显然它不是(可能从来都不是?)对于字段来说是正确的

它适用于 <1.2.1,所以我希望它也适用于 >1.2.1,<2.0,即使它不应该适用于任何版本。

此页面是否有帮助?
0 / 5 - 0 等级