-
Notifications
You must be signed in to change notification settings - Fork 38.3k
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
Consider alternative RuntimeHints API #28977
Comments
Regarding "Introspect vs Invoke methods" and "Read vs Write" the empty customizer being different than the method that takes no customizer is an oversight and can easily be fixed.
Can you expand what you mean by "a lot"?
It's outdated as we're not supposed to do method lookups manually. The intention of the API is to provide a way to specify a method handle that was retrieved as part of some processing.
That's a good point.
That is a bug that I am aware of and kept forgetting to report. |
Perhaps the wrong phrase. More than none. (edit: Here's a good example)
True, but I found method lookup also used in quite a few tests. |
I've pushed an experimental alternative API to https://github.com/philwebb/spring-framework/tree/gh-28977 for review. The main difference is that there's now a fluent style API that can be used rather than the builder. There are two commits on that branch, the first changes the API and the second adapts the existing code to use it. |
It's in the same ballpark as the rest of the feedback IMO. The current API is missing a
OK. I don't understand what the problem is with that. |
I was trying to list interesting things I'd found in case we didn't want to take on a new API and instead wanted to make a few tweaks to the existing one.
There's not a problem, but it it's easy to support method lookup in the API then it might be worth doing for the tests, even if it's not used much in FileNativeConfigurationWriterTests is a good example. Another one that isn't in test code is SchedulerFactoryBeanRuntimeHints |
Based on the feedback in #28977 an easy way to create a list of type references based on a vararg of classes is helpful when registering the same hints for several types.
This is directly related to #28781. See discussions in comment section for details. |
Thanks for link @sbrannen, I'd forgotten about that discussion. For the experimental API I consistently added Here's an example where you can call I was a little worried about the String variants because there are some rules that the javadoc on |
I think there is a lot of added value in the various examples listed in the description, and this is very useful inputs for improving the API. For example, I agree there are some places where we should probably provide some I guess it is a matter of taste, but I think I am in favor of doing a few improvements here and there on current API rather than changing most of it for the fluent one of https://github.com/philwebb/spring-framework/tree/gh-28977. Also keep in mind that the underlying GraalVM capabilities will evolve outside of our control, and we will likely need to adapt our APIs to follow. In that context, I have the feeling that the builder one is more future proof. |
To get another data point: I really like the API from Phil - especially the consistent |
Do we have any example of changes that have been made in the past? I'd be curious to know they types of changes we might face and in which ways the builder API is more resilient to them. |
They added conditions with reachable types (more conditions could come) and method querying in addition to invocation. More recently lambda serialization, see spring-attic/spring-native#1670. |
After a lot of consideration, Stephane and I have taken several suggestions from here into #29011 - within the current API design style. It turns out that a few overloaded methods, e.g. taking the execution mode enum directly, bring a lot of value and make usage arguably as convenient as with a fluent variant - without breaking backwards compatibility, and with an API style that remains closer to the typical style in other core Spring mechanisms. With quite minimal changes, this takes us to a scenario where most use cases are covered by direct method calls without a builder, turning the builder into an advanced-only facility. While there is certainly still room for further improvement, e.g. explicitly named methods for stronger semantic guidance, there are also benefits with the current style. Not least of it all, the typical/common need is first-class with direct registration methods at the hints API level, whereas advanced options - that most people don't need to care about - are separated into the builder. Having spent quite a bit of time with the API design today, I rather strongly prefer the direct registration methods in terms of naming and argument ordering. With so few arguments commonly needed, a fluent API style cannot really show its strengths much, at the expense of nested calls and readability that is sometimes a bit backwards (e.g. With respect to the "JDK proxy" versus "Java serialization" naming, that was actually quite intentional since those are the common terms that we use for those mechanisms in other places. A "JDK dynamic proxy" as opposed to a CGLIB proxy is what we use for interface-based proxying (provided by the JDK itself as opposed to Java classes generated by us), and "Java serialization" is the Java language mechanism for serialization. From that perspective, I'd rather keep those distinct terms. In any case, the list of inconsistencies and inconveniences above has turned out to be very valuable. I'll keep this issue open for a few remaining points, in particular the resource pattern processing. However, from where we stand right now, we are likely to incorporate remaining suggestions into the current API design, with as little backwards compatibility impact as possible. As for the further evolution of this facility, I find that hard to predict. Whether a particular style of API is better suited for long-term evolution along with GraalVM, that's hard to say. Since the builder style is at least not worse than a fluent API in that respect, I don't see this as a reason to switch to a different API style from where we are. Also, this API level is primarily for integrators, so pragmatically I see it from a "good enough" perspective in terms of usage guidance and maintainability. |
I've created issues for the two remaining items so I am going to close this now. |
The
RuntimeHints
API now has quite a bit of use across the portfolio and a few common patterns are starting to emerge. We might be able to refactor the registration API to make a few of these common patterns easier.Here are some of the common calls that we're seeing:
Introspect vs Invoke methods
Calling
registerMethod
allows introspection and invocation hints to be added. The following calls are quite common but it's not always obvious what they will do:We're quite often seeing the hint builder lambda being pulled into a
static final
to aid readability:Additionally, the
ExecutableHint
class uses aList
ofExecutableMode
values, but sinceINVOKE
also impliesINTROSPECT
this should not be necessary.Read vs Write
Similar to above, the
registerField
method doesn't immediately indicate if reading or writing is allowed:TypeReference.of()
Often the API expects a
TypeReference
parameter but the user has either aClass<?>
or aString
. This results in a lot of calls toTypeReference.of
in the caller code:Applying the same hints to multiple types
It's appears that often the same hints need to be applied to multiple types. For example in MessagingAnnotationsRuntimeHints and JacksonRuntimeHints.
Often the caller uses a
Stream
to do this:Reflective method lookups
Slightly less common, but still used now and again is calling
ReflectionUtils
to lookup aMethod
so that it can be passed to the API. A (now outdated) example can be found in CloudFoundryWebEndpointServletHandlerMapping.Similarly,
withMethod
calls often need to create aList
for the parameter types. SometimesCollections.emptyList()
is used, sometimes aStream
is used with a mapping function to convert to aTypeReference
.See InstrumentedMethodTests for some examples.
Naming consistency
As the API has been expanded some naming inconsistencies have crept in. For example,
ProxyHints
refers to "JDK proxies", where asSerializationHints
refers to "Java serialization". TheReflectionHints
class provides atypeHints()
Stream, where as most of the other APIs don't end withhint
(e.g.SerializationHints.javaSerialization()
.Resource include/excludes
The
ResourcePatternHints
is a container forincludes
andexcludes
and multipleResourcePatternHints
can be registered. It's possible that callers may expect that these includes and excludes are related, however, when the JSON is written all excludes and all includes are included together. See ResourceHintsPredicates.AggregatedResourcePatternHints for an example of the flattening that needs to occur when using the pattern hints.The text was updated successfully, but these errors were encountered: