Skip to content

SPR-8190: Added support for Byte Buddy AOP proxies and bean subclassing instantiation strategy. #1283

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

Closed
wants to merge 1 commit into from

Conversation

raphw
Copy link

@raphw raphw commented Jan 2, 2017

The suggested proxy makers are working but this is still work in progress. I require input for any further steps:

There is still no mechanism to specify a specific another byte code provider. Also, there is potential of sharing code for the cglib and Byte Buddy proxy classes unit tests but for this PR, i tried to not change any existing code. There are no explicit tests for the cglib bean proxy maker which could serve as a specimen which is why this call is untested.

@pivotal-issuemaster
Copy link

@raphw Please sign the Contributor License Agreement!

Click here to manually synchronize the status of this Pull Request.

See the FAQ for frequently asked questions.

@pivotal-issuemaster
Copy link

@raphw Thank you for signing the Contributor License Agreement!

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jan 24, 2019
@danieljipa
Copy link

Is this PR going to be merged any time soon ? Hibernate now uses ByteBuddy and Spring data jpa project has difficulties with this: https://stackoverflow.com/questions/62538768/error-deleting-entitiy-with-spring-data-jpa

@raphw
Copy link
Author

raphw commented Jun 26, 2020

I'd love this obviously, but someone would need to have a look. I just updated the branch to have it in sync with the current master to reduce the barrier for this.

@raphw raphw force-pushed the master branch 6 times, most recently from a7858fb to 7c14965 Compare June 27, 2020 20:23
@jhoeller
Copy link
Contributor

@raphw Thanks for updating the PR, this indeed brings it to our attention again :-)

A couple of comments from a first glance:

  • Is the removal of "-Werror" intentional? Please rather use @SuppressWarnings wherever necessary.
  • ClassUtils does not seem to be able to do anything general with ByteBuddy proxies, so the ByteBuddy constant seems out of place there. Let's put this within the ByteBuddy AOP implementation which actually uses that specific class naming pattern.
  • As far as I can see, the PR doesn't cover configuration class processing at all. While we could keep using CGLIB for that purpose, it seems strange not to apply ByteBuddy there as well.

@danieljipa To the best of my understanding, this PR is not directly related to the Spring Data JPA issue. The problem there is detecting Hibernate's specific naming pattern for ByteBuddy-generated classes, a problem appearing now because our general CGLIB-capable utility methods (e.g. ClassUtils.getUserClass) were able to handle CGLIB-generated Hibernate entity classes as well since they happened to use the same common CGLIB naming pattern... whereas ByteBuddy leaves class naming completely up to the user, so we'd have to hard-code Hibernate's specific naming pattern or use some Hibernate-specific API to detect it.

@raphw
Copy link
Author

raphw commented Jun 30, 2020

Hello Juergen, thanks for your promt reaction! I will look into the configuration class processing. It must have slipped my eye when I originally implemented this PR. I added the infix to the ClassUtil to correlate it with cglib. For the final PR, I'd suggest to create some form of abstract base abstraction used by both cglib and Byte Buddy anyways since I had to duplicate a bunch of code. I'd be happy to do it but wanted to avoid touching a lot of existing code and I was not sure if you preferred the duplication anyways.

As for the Hibernate proxies: this is correct. I'd recommend you to use the internal utilities. Depending on using the build-plugin, classes might be subclassed or instrumented where in the latter case, no names are changed, of course. When detecting cglib names, you might also discover any class that is created by cglib but that is not meant to be a proxy. Also, the $$ use in names has increased also for use of other synthetic classes. Hibernate uses a marker interface what seems more reliable. You could just check if this interface is implemented which it is not if it is not even found on the class loader.

@raphw raphw force-pushed the master branch 11 times, most recently from e0fd91d to d532833 Compare July 2, 2020 16:33
@raphw
Copy link
Author

raphw commented Jul 2, 2020

@jhoeller I chased the last bugs and now the entire project builds with all tests if using Byte-Buddy instead of cglib. I hope the size of the change set is not too daunting. The PR offers a Byte-Buddy-based proxy engine for all seven generation sites within spring-framework in a way that would even allow to remove cglib altogether. This also required some light refactorization of several unit tests that tested for the presence of a cglib proxy. I changed these tests to rather check for the presence of a class-based proxy independent of the proxy engine's implementation. As a consequence, no unit test within Spring framework assumes a particular proxy engine being used. This also renders a nice prove upon Spring not depending on a particular implementation since you now can build the entire project without using cglib.

The amount of additional code can easily be reduced by refactoring the related Cglib... and ByteBuddy... implementations of proxy generators to share a common base that implements the now duplicated code. I have kept the two implementation separate so far to keep the change set simpler to follow. Also, I was not sure if you'd prefer this approach.

Yesterday I still had a single test failure which I figured out today and I suspect a potential bug in spring-context as the cause. The failing test was testValueInjectionWithProviderFields in AutowiredConfigurationTests. Byte Buddy follows the JLS for it's subclasses; since the proxied ValueConfigWithProviderFields is package-private and is extended by a public class, it is required to override the unproxied setName2 method with a visibility bridge. cglib does not generate bridge methods which is why the setName2 method is overridden by Byte Buddy but not cglib. As a consequence, Spring gets confused about its own resolution and throws an exception. To avoid this failure, I disabled bridge class generation in ByteBuddyConfigurationClassEnhancer to make the test pass. Ideally, the proxy should be transparent, however, but I avoided a fix attempt to avoid further increasing this change set.

Please let me know if you see a chance to move this change forward and if you'd like me to refactor the Cglib... and ByteBuddy... implementations to share more common code in an abstract base parent. I'm happy to invest the time if the PR has a chance of getting merged.

@danieljipa
Copy link

Any news on this PR ? Thanks

@raphw
Copy link
Author

raphw commented Dec 17, 2020

I just rebased this onto master to resolve the merge conflicts. Maybe, with the Java 16 restrictions coming up, this would be a good way to revisit this PR?

@raphw
Copy link
Author

raphw commented Mar 27, 2021

It's soon gone two years. I understand if this is not considered, I am of course personally biased in wanting to include it, I just wonder if there's a point in keeping this PR open and rebase it, even improve it, or if I should simply close it. Thanks for any feedback.

@andrei-ivanov
Copy link

the silence on this PR from the team members is very weird 😕

@jhoeller
Copy link
Contributor

jhoeller commented Apr 9, 2021

@andrei-ivanov sorry for the silence, it's been a while indeed...

We are in the process of evaluating our options for Spring Framework 6 here, taking AOT generation of proxy classes into account (for native executables but also for regular JVM scenarios), and researching custom special-purpose class generation versus building on ByteBuddy's general facilities. All in all, we are planning towards a major overhaul of our legacy CGLIB usage, but only one such overhaul as a central theme in 6, and we can't quite commit to a specific arrangement yet. It's not even clear whether we'll keep CGLIB as a backwards compatibility option at all; we might replace it with a single new mechanism in 6.

@raphw I know it's painful to keep updating the PR for the time being. Feel free to let it sit for a while, it's fine inspiration for us in any case, and the detailed analysis you've been providing is very useful already. We do appreciate your efforts there but we're certainly not expecting you to spend extra cycles on the PR until we sorted out our overall class definition strategy for 6.

@raphw
Copy link
Author

raphw commented Apr 9, 2021

Thanks for the overview, I think that's a good issue to adress. I'm looking into a generic way of preprocessing proxy classes for Byte Buddy (which has a build plugin which could also be used for this very same purpose by you), maybe to give another incentive. Keep up the good work and let me know if you wonder about something related to code generation.

@rstoyanchev rstoyanchev added the in: core Issues in core modules (aop, beans, core, context, expression) label Nov 10, 2021
@jhoeller
Copy link
Contributor

jhoeller commented Aug 6, 2023

Since we eventually went with a full CGLIB fork for Spring Framework 6.0, including AOT support for capturing generated classes etc, I do not see us proceeding with ByteBuddy any time soon, not least of it all in order to keep our maintenance efforts at a manageable level. From that perspective, it seems appropriate to close this PR. Thanks @raphw for all your efforts there so far!

@jhoeller jhoeller closed this Aug 6, 2023
@snicoll snicoll added status: declined A suggestion or change that we don't feel we should currently apply and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Aug 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: declined A suggestion or change that we don't feel we should currently apply
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants