Jdbi: JDK9 заблокирует setAccessible на модулях

Созданный на 21 сент. 2016  ·  22Комментарии  ·  Источник: jdbi/jdbi

Мы используем setAccessible(true) для получения рефлексивного доступа к частному API в нескольких местах. Мы не можем рассчитывать на это после выхода JDK9.

В частности, DefaultMethodHandler в объекте SQL использует setAccessible для получения доступа к MethodHandle.Lookup для частных членов, чтобы мы могли вызвать метод по умолчанию («супер»).

Видеть:

Самый полезный комментарий

Это должно поддерживаться в следующем выпуске Jdbi - вероятно, v3.2.0.

Все 22 Комментарий

Я протестировал последний снимок состояния JDBI на JDK 9-ea + 136, и, к сожалению, методы по умолчанию не работают.

java.lang.RuntimeException: java.lang.IllegalAccessException: access to public member failed: org.jdbi.v3.sqlobject.TestSqlObject$Dao.doesTransactionAnnotationWork()boolean/invokeSpecial, from org.jdbi.v3.sqlobject.TestSqlObject$Dao/2 (unnamed module @34b7bfc0)

    at org.jdbi.v3.sqlobject.DefaultMethodHandler.invoke(DefaultMethodHandler.java:63)
    at org.jdbi.v3.sqlobject.TransactionDecorator.lambda$invoke$0(TransactionDecorator.java:54)
    at org.jdbi.v3.core.transaction.LocalTransactionHandler.inTransaction(LocalTransactionHandler.java:173)
    at org.jdbi.v3.core.Handle.inTransaction(Handle.java:478)
    at org.jdbi.v3.sqlobject.TransactionDecorator.invoke(TransactionDecorator.java:57)
    at org.jdbi.v3.sqlobject.SqlObjectFactory.lambda$createInvocationHandler$18(SqlObjectFactory.java:241)
    at com.sun.proxy.$Proxy16.doesTransactionAnnotationWork(Unknown Source)
    at org.jdbi.v3.sqlobject.TestSqlObject.testTransactionAnnotationWorksOnInterfaceDefaultMethod(TestSqlObject.java:115)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@9-ea/Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@9-ea/NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@9-ea/DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(java.base@9-ea/Method.java:535)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
    at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@9-ea/Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@9-ea/NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@9-ea/DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(java.base@9-ea/Method.java:535)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: java.lang.IllegalAccessException: access to public member failed: org.jdbi.v3.sqlobject.TestSqlObject$Dao.doesTransactionAnnotationWork()boolean/invokeSpecial, from org.jdbi.v3.sqlobject.TestSqlObject$Dao/2 (unnamed module @34b7bfc0)
    at java.lang.invoke.MemberName.makeAccessException(java.base@9-ea/MemberName.java:915)
    at java.lang.invoke.MethodHandles$Lookup.checkAccess(java.base@9-ea/MethodHandles.java:1924)
    at java.lang.invoke.MethodHandles$Lookup.checkMethod(java.base@9-ea/MethodHandles.java:1864)
    at java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(java.base@9-ea/MethodHandles.java:2013)
    at java.lang.invoke.MethodHandles$Lookup.getDirectMethodNoSecurityManager(java.base@9-ea/MethodHandles.java:2007)
    at java.lang.invoke.MethodHandles$Lookup.unreflectSpecial(java.base@9-ea/MethodHandles.java:1539)
    at org.jdbi.v3.sqlobject.DefaultMethodHandler.invoke(DefaultMethodHandler.java:51)
    ... 38 more

К сожалению, я также не вижу обходного пути для этого.

Странно, что все люди в Интернете, которые сталкиваются с одной и той же проблемой, в конечном итоге используют этот взлом как единственное решение. Похоже, команда JDK допустила небольшую оплошность, чтобы не обратить внимание на вариант использования «методы по умолчанию в прокси».

Хм, заработал с:

Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
field.setAccessible(true);
MethodHandles.Lookup lookup = (MethodHandles.Lookup) field.get(null);
Class<?> declaringClass = method.getDeclaringClass();
return lookup.unreflectSpecial(method, declaringClass)
                    .bindTo(target)
                    .invokeWithArguments(args);

Понятия не имею, почему это работает с JDK9.

Вздох. Вероятно, мы должны обсудить это с разработчиками openjdk раньше, чем позже ...

Я смотрел jigsaw-dev последние несколько дней. Было некоторое обсуждение этого конкретного варианта использования, но, насколько я могу судить, это была скорее сноска по сравнению с бушующей дискуссией о значении ограничения setAccessible . Похоже, многим этот шаг не понравился.

Я удаляю это из блокировщиков релизов. Исправление апстрима вряд ли появится в ближайшее время, а JDK9 еще не выпущен. Возможное исправление не должно повлиять на общедоступный API.

Я связался со списком рассылки jigsaw-dev по этому поводу. http://jigsaw-dev.1059479.n5.nabble.com/Invoking-default-methods-from-a-Proxy-s-InvocationHandler-in-JDK9-td5714878.html.

Посмотрим, что из этого получится.

Снова наткнулся на core-libs-dev.

Это должно быть решено для нас в последних сборках JDK9. По крайней мере теоретически.

По сути, они изменили проверки безопасности, чтобы каждый мог
unreflectSpecial в методе по умолчанию.

Когда JDK9 приземлится, нам придется динамически переключать подходы в зависимости от
версия Java, в которой работает JDBI.

1 марта 2017 г., 14:36, "Стивен Шланскер" [email protected]
написал:

Снова наткнулся на core-libs-dev.

-
Вы получаете это, потому что вы являетесь автором темы.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/jdbi/jdbi/issues/497#issuecomment-283478025 или отключить звук
нить
https://github.com/notifications/unsubscribe-auth/AACW5VBktrJYJatnsABFKay_-Ci5WD_Sks5rheTCgaJpZM4KCb6m
.

О да. Из core-libs-dev:

Вы можете использовать MethodHandles.privateLookupIn (новое в JDK 9) для замены взлома Constructor, чтобы получить объект Lookup с частным доступом для целевого класса.
Мэнди

Приятно слышать! По крайней мере, мы можем избавиться от этого беспорядка в JDK9.

Привет, я решил аналогичную проблему в моем проекте OWNER, который вызывает методы по умолчанию для интерфейсов, использующих JDK9, пожалуйста, взгляните на мой служебный класс, возможно, он может вам помочь.

Есть что-нибудь об этом? Когда я смогу использовать JDBI с JDK 9?

Мы очень заинтересованы в поддержке Java 9, но, честно говоря, я еще не начал ее изучать. В последний раз я смотрел, что экосистеме явно нужно время, чтобы приспособиться, но, возможно, пора изменить приоритетность этого вопроса.

Здесь есть что-нибудь новенькое? JDK 10 вышел через несколько дней ...

В jdk9 нет очевидных изменений, лучше сразу перейти к 10

Похоже, что нам, возможно, придется разветвлять код и использовать отражение, чтобы воспользоваться преимуществами новых методов, добавленных в JDK9, без нарушения совместимости для 8. Самый быстрый путь вперед здесь - отправить патч или, по крайней мере, немного потрудиться, чтобы выяснить минимальное изменение. необходимо :) в противном случае я постараюсь взглянуть на это где-нибудь на этой неделе.

И, надеюсь, большая часть работы по достижению 10 фактически будет связана с достижением 9 - я не думаю, что есть какие-то большие изменения в 10, которые, как мы ожидаем, сломают что-то, в то время как мы определенно знаем, что 9 сломали ...

У меня есть ветка по этому поводу, которая не требует двойной сборки, но сначала ее нужно исправить

Хорошо, тогда я не стану его взламывать.

Это должно поддерживаться в следующем выпуске Jdbi - вероятно, v3.2.0.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги