Мы используем setAccessible(true)
для получения рефлексивного доступа к частному API в нескольких местах. Мы не можем рассчитывать на это после выхода JDK9.
В частности, DefaultMethodHandler
в объекте SQL использует setAccessible
для получения доступа к MethodHandle.Lookup
для частных членов, чтобы мы могли вызвать метод по умолчанию («супер»).
Видеть:
Я протестировал последний снимок состояния 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.
Самый полезный комментарий
Это должно поддерживаться в следующем выпуске Jdbi - вероятно, v3.2.0.