Jdbi: JDK9 irá bloquear setAccessible nos módulos

Criado em 21 set. 2016  ·  22Comentários  ·  Fonte: jdbi/jdbi

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:

bug

Comentários muito úteis

Isso deve ser suportado na próxima versão Jdbi - provavelmente v3.2.0

Todos 22 comentários

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

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

stevenschlansker picture stevenschlansker  ·  4Comentários

goxr3plus picture goxr3plus  ·  4Comentários

nonameplum picture nonameplum  ·  5Comentários

mcarabolante picture mcarabolante  ·  4Comentários

anjeyy picture anjeyy  ·  3Comentários