Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue when using Spring Security / AOP proxying with Quasar #108

Closed
imperatorx opened this issue Aug 8, 2015 · 14 comments
Closed

Issue when using Spring Security / AOP proxying with Quasar #108

imperatorx opened this issue Aug 8, 2015 · 14 comments
Assignees
Labels

Comments

@imperatorx
Copy link

I have tried to implement spring method security, I have used @Suspendable annotations in proxied methods, like the documentation says. When I remove the @PreAuthorize annotation (no proxy is created), I have no errors. When I add the @PreAuthorize annotation, a proxy is created but on fiber blocking, I get a null pointer exception. According to the warnings, the org.springframework.aop.framework.JdkDynamicAopProxy.invoke method is not instrumented, although I have added several methods -including this- to META-INF/suspendables.

The warning:

WARNING: Uninstrumented methods (marked '**') or call-sites (marked '!!') detected on the call stack: 
    at co.paralleluniverse.common.util.ExtendedStackTrace.here (ExtendedStackTrace.java:44 bci: 8)
    at co.paralleluniverse.fibers.Fiber.checkInstrumentation (Fiber.java:1613 bci: 0)
    at co.paralleluniverse.fibers.Fiber.verifySuspend (Fiber.java:1586 bci: 6)
    at co.paralleluniverse.fibers.Stack.popMethod (Stack.java:155 bci: 11)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (ReflectiveMethodInvocation.java:179 bci: 245)
--> at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(java.lang.Object,java.lang.reflect.Method,java.lang.Object[]) (JdkDynamicAopProxy.java:207 bci: 321) **
    at com.sun.proxy.$Proxy41.lol (Unknown Source bci: 16)
    at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62 bci: 100)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43 bci: 6)
    at java.lang.reflect.Method.invoke (Method.java:483 bci: 56)
    at foo.Handler$3.run (HAndler.java:272 bci: 639)
    at co.paralleluniverse.strands.SuspendableUtils$VoidSuspendableCallable.run (SuspendableUtils.java:44 bci: 4)
    at co.paralleluniverse.strands.SuspendableUtils$VoidSuspendableCallable.run (SuspendableUtils.java:32 bci: 1)
    at co.paralleluniverse.fibers.Fiber.run (Fiber.java:1019 bci: 11)
    at co.paralleluniverse.fibers.Fiber.run1 (Fiber.java:1014 bci: 1)

My suspendables file:

org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed
org.springframework.transaction.interceptor.TransactionInterceptor.invoke
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction
org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary
org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction
org.springframework.aop.framework.JdkDynamicAopProxy.invoke

The exception:

java.lang.reflect.InvocationTargetException: null
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at foo.Handler$3.run(Handler.java:272)
    at co.paralleluniverse.strands.SuspendableUtils$VoidSuspendableCallable.run(SuspendableUtils.java:44)
    at co.paralleluniverse.strands.SuspendableUtils$VoidSuspendableCallable.run(SuspendableUtils.java:32)
    at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1019)
    at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1014)
    at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:729)
    at co.paralleluniverse.fibers.FiberForkJoinScheduler$FiberForkJoinTask.exec1(FiberForkJoinScheduler.java:257)
    at co.paralleluniverse.concurrent.forkjoin.ParkableForkJoinTask.doExec(ParkableForkJoinTask.java:116)
    at co.paralleluniverse.concurrent.forkjoin.ParkableForkJoinTask.exec(ParkableForkJoinTask.java:73)
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:902)
    at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1689)
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1644)
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: java.lang.NullPointerException: null
    at co.paralleluniverse.strands.Strand.park(Strand.java:493)
    at co.paralleluniverse.strands.ConditionSynchronizer.await(ConditionSynchronizer.java:54)
    at co.paralleluniverse.strands.dataflow.Val.get(Val.java:154)
    at co.paralleluniverse.fibers.Fiber.get(Fiber.java:1302)
    at foo.Bean.lol(Bean.java:76)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:64)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy41.lol(Unknown Source)
    ... 18 common frames omitted

Did I miss something, or the instrumentation is not working and fails silently?

@circlespainter circlespainter self-assigned this Aug 9, 2015
@imperatorx
Copy link
Author

I've created a minimal example project to demonstrate: https://github.com/imperatorx/quasar-test

@circlespainter
Copy link
Member

Thanks a lot, looking into this shortly.

@circlespainter
Copy link
Member

Here's the reference fork of your example for the following discussion.

First of all, after adding Maven plugins for execution and running the app with mvn compile dependency:properties exec:exec, I got a different verification exception from yours:

WARNING: Uninstrumented methods (marked '**') or call-sites (marked '!!') detected on the call stack: 
    at co.paralleluniverse.common.util.ExtendedStackTrace.here (ExtendedStackTrace.java:44 bci: 8)
    at co.paralleluniverse.fibers.Fiber.checkInstrumentation (Fiber.java:1613 bci: 0)
    at co.paralleluniverse.fibers.Fiber.verifySuspend (Fiber.java:1586 bci: 6)
    at co.paralleluniverse.fibers.Fiber.verifySuspend (Fiber.java:1581 bci: 3)
    at co.paralleluniverse.fibers.Fiber.sleep (Fiber.java:634 bci: 0)
    at co.paralleluniverse.fibers.Fiber.sleep (Fiber.java:626 bci: 4)
    at foo.quasar.test.MyServiceImpl.foo (MyServiceImpl.java:18 bci: 89)
    at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62 bci: 100)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43 bci: 6)
    at java.lang.reflect.Method.invoke (Method.java:497 bci: 56)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection (AopUtils.java:317 bci: 167)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint (ReflectiveMethodInvocation.java:190 bci: 107)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (ReflectiveMethodInvocation.java:157 bci: 97)
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke (MethodSecurityInterceptor.java:64 bci: 7) (optimized) !! (instrumented suspendable calls at: [])
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (ReflectiveMethodInvocation.java:179 bci: 256) !! (instrumented suspendable calls at: [])
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke (JdkDynamicAopProxy.java:207 bci: 785) !! (instrumented suspendable calls at: [])
    at com.sun.proxy.$Proxy25.foo (Unknown Source bci: 16)
    at foo.quasar.test.App$1.run (App.java:52 bci: 169)
    at foo.quasar.test.App$1.run (App.java:39 bci: 1) (optimized)
    at co.paralleluniverse.fibers.Fiber.run1 (Fiber.java:1014 bci: 1)

After a couple of rounds of the above, after which I got every interface method that needed call-site instrumentation in suspendable-supers, I got another one:

Exception in Fiber "fiber-10000001" java.lang.reflect.UndeclaredThrowableException
    at com.sun.proxy.$Proxy25.foo(Unknown Source)
    at foo.quasar.test.App$1.run(App.java:52)
    at foo.quasar.test.App$1.run(App.java:39)
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.reflect.UndeclaredThrowableException
    at co.paralleluniverse.fibers.Fiber.get(Fiber.java:1304)
    at co.paralleluniverse.fibers.Fiber.join(Fiber.java:1279)
    at foo.quasar.test.App.test(App.java:57)
    at foo.quasar.test.App.main(App.java:29)
Caused by: java.lang.reflect.UndeclaredThrowableException
    at com.sun.proxy.$Proxy25.foo(Unknown Source)
    at foo.quasar.test.App$1.run(App.java:52)
    at foo.quasar.test.App$1.run(App.java:39)
    at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1014)
    at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:729)
    at co.paralleluniverse.fibers.FiberForkJoinScheduler$FiberForkJoinTask.exec1(FiberForkJoinScheduler.java:257)
    at co.paralleluniverse.concurrent.forkjoin.ParkableForkJoinTask.doExec(ParkableForkJoinTask.java:116)
    at co.paralleluniverse.concurrent.forkjoin.ParkableForkJoinTask.exec(ParkableForkJoinTask.java:73)
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1689)
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: co.paralleluniverse.fibers.SuspendExecution: Oops. Forgot to instrument a method. Run your program with -Dco.paralleluniverse.fibers.verifyInstrumentation=true to catch the culprit!
Exception in Fiber "fiber-10000001" java.lang.reflect.UndeclaredThrowableException
    at com.sun.proxy.$Proxy25.foo(Unknown Source)
    at foo.quasar.test.App$1.run(App.java:52)
    at foo.quasar.test.App$1.run(App.java:39)

[UPDATED]
This has something to do with handling of proxy invocations for which Quasar has specific support (in order to unroll UndeclaredThrowableException) but I'll need to look further into it.

You control the interface source code though, so an easy workaround is to use the throws SuspendExecution method instead of the @Suspendable one as I did in my fork, which seems to work ok.

@circlespainter circlespainter changed the title Instumentation does not work for Spring Security Issue when using Spring Security / AOP proxying with Quasar Aug 9, 2015
@imperatorx
Copy link
Author

Thank you, using your approach I was able to use spring security using the interface based proxies. After a lot of trial and error, I was able to create a suspendables and suspendable-supers file, that got spring @transactional annotations working also.

Unfortunately, I was only able to use the @transactional approach with manual jdbc queries, because using comsat-jooq resulted in weird NullPointerExceptions, but the instrumentation verifier did not warn me about missing anything. The comsat-jooq package was on the classpath, so JOOQ should have been instrumented. I can set up a minimal test project for demonstration int 2-3 days.

It seems, that the jooq call for preparedstatement throws this error. I am using a TransactionAwareDataSourceProxy (instrumented via manual config), which is wrapping a FiberDataSource. Manually aquiring a connection from the TransactionAwareDataSourceProxy and creating and running a standard jdbc prepared statement by hand produces no errors, and works as expected.

Caused by: java.lang.NullPointerException: null
    at co.paralleluniverse.fibers.FiberAsync.run(FiberAsync.java:121)
    at co.paralleluniverse.fibers.FiberAsync.runBlocking(FiberAsync.java:409)
    at co.paralleluniverse.fibers.jdbc.JDBCFiberAsync.exec(JDBCFiberAsync.java:29)
    at co.paralleluniverse.fibers.jdbc.FiberConnection.prepareStatement(FiberConnection.java:65)
    at co.paralleluniverse.fibers.jdbc.FiberConnection.prepareStatement(FiberConnection.java:41)
    at sun.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy$TransactionAwareInvocationHandler.invoke(TransactionAwareDataSourceProxy.java:240)
    at com.sun.proxy.$Proxy35.prepareStatement(Unknown Source)
    at org.jooq.impl.ProviderEnabledConnection.prepareStatement(ProviderEnabledConnection.java:112)
    at org.jooq.impl.SettingsEnabledConnection.prepareStatement(SettingsEnabledConnection.java:76)
    at org.jooq.impl.AbstractResultQuery.prepare(AbstractResultQuery.java:216)
    at org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:316)
    at org.jooq.impl.AbstractResultQuery.fetch(AbstractResultQuery.java:290)
    at org.jooq.impl.SelectImpl.fetch(SelectImpl.java:2316)
    at xxxxx.Foo.lol(Foo.java:105)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy40.lol(Unknown Source)
    ... 18 common frames omitted

@circlespainter
Copy link
Member

Thanks, would you mind opening a new distinct issue in Comsat about that?

@imperatorx
Copy link
Author

Sure, I will investigate further and create a new issue with full sample code about the comsat-jooq issue.

In the meantime I have found strange behaviour regarding non-interface based proxies. I have updated the repo https://github.com/imperatorx/quasar-test with another proxied bean, but this time the bean implements no interfaces, so instead of a jdk interface proxy, a cglib based class proxy gets created.

When I declare "throws Suspendexecution, InterruptedException", the instrumentation fails (because of the proxy catching these exceptions I think), but if I use @Suspendable, the program starts to run, but produces errors, and the instrumentation verifier lists the created cgi proxies' methods as uninstrumented methods.

The method org.springframework.cglib.proxy.MethodProxy.invoke (MethodProxy.java:204 bci: 19) ** is listed as uninstrumented, even though I added it to the suspendables file.

WARNING: Uninstrumented methods (marked '**') or call-sites (marked '!!') detected on the call stack: 
    at co.paralleluniverse.common.util.ExtendedStackTrace.here (ExtendedStackTrace.java:44 bci: 8)
    at co.paralleluniverse.fibers.Fiber.checkInstrumentation (Fiber.java:1613 bci: 0)
    at co.paralleluniverse.fibers.Fiber.verifySuspend (Fiber.java:1586 bci: 6)
    at co.paralleluniverse.fibers.Stack.popMethod (Stack.java:155 bci: 11)
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation (AbstractSecurityInterceptor.java:231 bci: 564)
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke (MethodSecurityInterceptor.java:60 bci: 122)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (ReflectiveMethodInvocation.java:179 bci: 381)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept (CglibAopProxy.java:653 bci: 585)
    at foo.quasar.test.MyNonInterfaceService$$EnhancerBySpringCGLIB$$c351c2af.foo(java.lang.String) (<generated> bci: 36) **
    at foo.quasar.test.App$2.run (App.java:75 bci: 132)
    at foo.quasar.test.App$2.run (App.java:62 bci: 1) (optimized)
    at co.paralleluniverse.fibers.Fiber.run1 (Fiber.java:1014 bci: 1)
WARNING: Uninstrumented methods (marked '**') or call-sites (marked '!!') detected on the call stack: 
    at co.paralleluniverse.common.util.ExtendedStackTrace.here (ExtendedStackTrace.java:44 bci: 8)
    at co.paralleluniverse.fibers.Fiber.checkInstrumentation (Fiber.java:1613 bci: 0)
    at co.paralleluniverse.fibers.Fiber.verifySuspend (Fiber.java:1586 bci: 6)
    at co.paralleluniverse.fibers.Fiber.verifySuspend (Fiber.java:1581 bci: 3)
    at co.paralleluniverse.fibers.Fiber.sleep (Fiber.java:634 bci: 0)
    at co.paralleluniverse.fibers.Fiber.sleep (Fiber.java:626 bci: 4)
    at foo.quasar.test.MyNonInterfaceService.foo (MyNonInterfaceService.java:17 bci: 89)
    at foo.quasar.test.MyNonInterfaceService$$FastClassBySpringCGLIB$$b23e4980.invoke(int,java.lang.Object,java.lang.Object[]) (<generated> bci: 66) **
    at org.springframework.cglib.proxy.MethodProxy.invoke (MethodProxy.java:204 bci: 19) **
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint (CglibAopProxy.java:717 bci: 118)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (ReflectiveMethodInvocation.java:157 bci: 105)
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke (MethodSecurityInterceptor.java:64 bci: 191)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (ReflectiveMethodInvocation.java:179 bci: 381)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept (CglibAopProxy.java:653 bci: 585)
    at foo.quasar.test.MyNonInterfaceService$$EnhancerBySpringCGLIB$$c351c2af.foo (<generated> bci: 36) **
    at foo.quasar.test.App$2.run (App.java:75 bci: 132)
    at foo.quasar.test.App$2.run (App.java:62 bci: 1) (optimized)
    at co.paralleluniverse.fibers.Fiber.run1 (Fiber.java:1014 bci: 1)

Is there a way to get non-interface based proxy creation working?

@circlespainter
Copy link
Member

You need to add their methods to suspendables and their abstract/interface base methods to suspendable-supers as you would do with any other class. I added the following to suspendables:

org.springframework.cglib.proxy.MethodProxy.invoke
org.springframework.cglib.reflect.FastClass.invoke

foo.quasar.test.MyNonInterfaceService$$EnhancerBySpringCGLIB$$bf964a66.foo
foo.quasar.test.MyNonInterfaceService$$EnhancerBySpringCGLIB$$dcb8983c.foo
foo.quasar.test.MyNonInterfaceService$$FastClassBySpringCGLIB$$b23e4980.invoke
foo.quasar.test.MyNonInterfaceService$$EnhancerBySpringCGLIB$$2e64fe86.foo
foo.quasar.test.MyNonInterfaceService$$EnhancerBySpringCGLIB$$93e1c07c.foo

And the following to suspendable-supers:

org.springframework.cglib.reflect.FastClass.invoke

FastClass has some concrete and some abstract overloads of invoke and it's the base class of the generated proxies (that's why it shows up in their class name) which implement the abstract ones.

Also keep in mind that a method marked for instrumentation but which contains no (detected) suspendable call sites won't be instrumented (this happened to me this time because I instrumented the proxies before figuring out they were implementing FastClass.invoke, which was the method actually referenced by a call site in MethodProxy.invoke). The =vdc flags for the agent can be very helpful in understanding what's going on exactly.

As an alternative to the simple suspendables and suspendable-supers files you can also write a full-blown program to decide what to instrument, in the form of a SuspendableClassifier implementation (and an SPI configuration file to enable it). You can have a look to jOOQ's in Comsat for example.

Mentioning artificial class names is not best but they should typically depend only on the extended class(es) names and on the usage point, so their names should be stable enough for each single use case. Anyway a better (but more time-consuming) integration approach would probably tap into Spring's proxy generation facilities (if possible) and generate the right ones with @Suspendable annotations (or throws SuspendExecution) already. Of course you can also let the SuspendableClassifier impl. figure out which are the Spring proxy classes, although it can be difficult to know which ones must be instrumented and which ones shouldn't. Instrumentation adds some overhead, so it should be avoided where it's not needed.

The reason why throws SuspendExecution didn't work for you in this case is probably the one you say (the proxy is catching SuspendExecution) although Quasar allows suspendable methods to catch it (it will instrument them in such a way that this won't happen for real) so it should be just a matter of letting Quasar know that they should be instrumented in one of the ways discussed above.

@imperatorx
Copy link
Author

Thanks, the classifier approach is definitely the way to go, since the class names are generated on the fly. I'm going to implement a classifier that checks for superclasses of proxies (I think if there are multiple aop pointcuts then multiple proxy classes are generated and they implement each other in the calling order) and looks for annotations. Hopefully superclasses are always passed to the classifier before subclasses.

@imperatorx
Copy link
Author

I have created a dynamic spring proxy classifier, the example is in this repo: https://github.com/imperatorx/quasar-test-3
The example program calls an interface proxy method once, then the class proxy 5 times.

The classifier works by scanning classed for a marker annotation. It distinguishes between EnhancerBySpringCGLIB and FastClassBySpringCGLIB types.

With this approach, the instrumented proxy gets created, and it works. One strange thing is that these warnings are shown, but only once, not on repeated executions:

[quasar] WARNING: Expected to find a NewValue on stack index 1: Lfoo/quasar/test/MyProxyService$$FastClassBySpringCGLIB$$3bcd9af0;ILjava/lang/Object;[Ljava/lang/Object; Ljava/lang/Boolean;Ljava/lang/Boolean;I
[quasar] WARNING: Expected to find a NewValue on stack index 1: Lfoo/quasar/test/MyProxyService$$FastClassBySpringCGLIB$$3bcd9af0;ILjava/lang/Object;[Ljava/lang/Object; Ljava/lang/Integer;Ljava/lang/Integer;I
[quasar] WARNING: Expected to find a NewValue on stack index 1: Lfoo/quasar/test/MyProxyService$$FastClassBySpringCGLIB$$3bcd9af0;ILjava/lang/Object;[Ljava/lang/Object; Ljava/lang/reflect/InvocationTargetException;Ljava/lang/reflect/InvocationTargetException;Ljava/lang/Throwable;
[quasar] WARNING: Expected to find a NewValue on stack index 1: Lfoo/quasar/test/MyProxyService$$FastClassBySpringCGLIB$$3bcd9af0;ILjava/lang/Object;[Ljava/lang/Object; Ljava/lang/reflect/UndeclaredThrowableException;Ljava/lang/reflect/UndeclaredThrowableException;Ljava/lang/Throwable;

Will these warnings cause problems, or are these safe to ignore?

@circlespainter
Copy link
Member

These are instrumentation warnings during constructor invocations analysis so they'll be triggered only once per class instrumentation (so typically per application run). If your code works ok they are safe to ignore but nevertheless it can be interesting to know why they are triggered.

I'm not very familiar with that instrumentation code portion though; I think @pron knows better.

@pron
Copy link
Contributor

pron commented Aug 17, 2015

This happens because the code is not generated by javac. You can safely ignore those messages.

@circlespainter
Copy link
Member

The solution to using class-based proxies to suspendable methods with Quasar is to declare throws SuspendExecution and tell Quasar they need to be instrumented through a SuspendableClassifier (suspendables didn't work for me as their class names seem not to be stable).

@Suspendable won't work for this kind of proxies because the UndeclaredThrowableException workaround is enabled only for "suspendable-super" call sites and I don't think it pays out to enable it for all call sites (because it adds bytecode that is never really needed except in some very specific circumstances, like this one).

throws SuspendExecution will work provided you instrument the proxies themselves as well: Quasar modifies the catching of SuspendExecution so that it doesn't interfere with fibers and so it allows to catch it, but of cource only for code that it instruments.

@circlespainter
Copy link
Member

You can find my changes to enable your app's class-based proxied calls here: https://github.com/circlespainter/comsat-jooq-test

@Jianfree
Copy link

Jianfree commented Dec 4, 2017

@circlespainter @imperatorx thank you guys , i was faced a spring aop problems, finally solved by add some suspendable method config in suspendables and suspendables-supers files after read https://github.com/circlespainter/comsat-jooq-test code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants