Estamos usando setAccessible(true)
para obter acesso reflexivo à API privada em alguns lugares. Não podemos contar com isso após o lançamento do JDK9.
Em particular, DefaultMethodHandler
no objeto SQL está usando setAccessible
para obter acesso ao MethodHandle.Lookup
para membros privados, para que possamos invocar o método padrão ("super").
Ver:
Testei o instantâneo JDBI mais recente no JDK 9-ea + 136 e, infelizmente, os métodos padrão não funcionam.
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
Infelizmente, também não vejo uma solução alternativa para isso.
Isso é meio estranho, todas as pessoas na Internet que passam pelo mesmo problema acabam tendo esse hack como a única solução. Parece que foi um descuido da equipe JDK não prestar atenção ao caso de uso "métodos padrão em proxies".
Hm, comecei a trabalhar com:
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);
Não tenho ideia de por que isso funciona com JDK9.
Suspirar. Provavelmente deveríamos entrar em contato com os desenvolvedores do openjdk sobre isso mais cedo ou mais tarde ...
Eu tenho assistido o quebra-cabeças nos últimos dias. Houve alguma discussão sobre este caso de uso exato, mas pelo que posso dizer, foi mais uma nota de rodapé em relação a uma discussão violenta sobre o valor de restringir setAccessible
. Parece que muitas pessoas não estão felizes com essa mudança.
Estou removendo isso dos bloqueadores de liberação. Não parece provável que uma correção upstream apareça em breve, e o JDK9 ainda não foi lançado. A eventual correção não deve afetar a API pública.
Entrei em contato com a lista de discussão do Jigsaw-dev sobre isso. http://jigsaw-dev.1059479.n5.nabble.com/Invoking-default-methods-from-a-Proxy-s-InvocationHandler-in-JDK9-td5714878.html.
Vamos ver o que sai disso.
Coloquei no core-libs-dev novamente.
Isso deve ser resolvido para nós em compilações JDK9 recentes. Pelo menos em teoria.
Basicamente, eles mudaram as verificações de segurança para que qualquer pessoa possa
unreflectSpecial em um método padrão.
Quando o JDK9 aterrissar, teremos que mudar dinamicamente as abordagens dependendo do
a versão Java em que o JDBI está sendo executado.
Em 1º de março de 2017, 14h36, "Steven Schlansker" [email protected]
escreveu:
Coloquei no core-libs-dev novamente.
-
Você está recebendo isso porque é o autor do tópico.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/jdbi/jdbi/issues/497#issuecomment-283478025 ou mudo
o segmento
https://github.com/notifications/unsubscribe-auth/AACW5VBktrJYJatnsABFKay_-Ci5WD_Sks5rheTCgaJpZM4KCb6m
.
Ah sim. De core-libs-dev:
Você pode usar MethodHandles.privateLookupIn (novo no JDK 9) para substituir o hack do Construtor para obter um objeto Lookup com acesso privado para a classe de destino.
Mandy
É revigorante ouvir isso! Pelo menos podemos nos livrar dessa bagunça no JDK9.
Oi, eu resolvi um problema semelhante no meu projeto OWNER que chama métodos padrão em interfaces usando JDK9, por favor, dê uma olhada em minha classe de utilitário, talvez ela possa ajudá-lo.
Alguma palavra sobre isso? Quando poderei usar o JDBI com o JDK 9?
Estamos muito interessados no suporte ao Java 9, mas, francamente, ainda não comecei a pesquisar nele. Da última vez que olhei, o ecossistema claramente ainda precisava de tempo para se estabelecer, mas talvez seja hora de superar a prioridade disso.
Alguma novidade aqui? JDK 10 saiu há alguns dias ...
Não há nenhuma mudança óbvia no jdk9, é melhor ir direto para o 10
Parece que podemos ter que ramificar o código e usar reflexão para aproveitar as vantagens dos novos métodos adicionados no JDK9 sem quebrar a compatibilidade para 8. A maneira mais rápida de avançar aqui é enviar um patch ou pelo menos algum trabalho braçal para descobrir a mudança mínima necessário :) caso contrário, tentarei dar uma olhada nisso ainda esta semana.
E espero que a maior parte do trabalho para chegar a 10 seja realmente para chegar a 9 - não acho que haja grandes mudanças em 10 que esperamos quebrar as coisas, enquanto certamente sabemos que 9 coisas quebraram ...
Eu tenho um branch nisso que não precisa de uma compilação dupla, mas precisa de uma correção primeiro
OK, não vou começar a hackear então.
Isso deve ser suportado na próxima versão Jdbi - provavelmente v3.2.0
Comentários muito úteis
Isso deve ser suportado na próxima versão Jdbi - provavelmente v3.2.0