-
Notifications
You must be signed in to change notification settings - Fork 83
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
Clarify meaning of default value for java annotation properties #356
Comments
I would suggest adding a note about how the defaulted values are to be represented in the internal model. That model and the representation of defaulted values is part of the contract with any code that consumes the model. The spec should require either that
I claim choice 1 makes more sense because, as Eric's write-up points out, the Java language provides no mechanism to assign a null to an annotation property -- by either default or explicit assignment. Background: Eric and I had been discussing some aspects of this in a private email thread earlier. What triggered our conversation was this: I had incorrectly set up how I ran the TCK with SmallRye. I ended up inadvertently using a filter from one set of tests in a second set of tests. In the second set was an endpoint with a The filter in question deferences the content's schema's description without checking for a null schema first. This seems OK to me, given that there's no way to specify a null value for an annotation property. Yet the SmallRye annotation processor did set the content's schema to null in the internal model. When passed that model element, the filter threw an NPE trying to dereference the content's null schema. Granted, I triggered the NPE by setting the TCK up incorrectly. But that just highlighted that the contract among MP OpenAPI, the annotation processor, and the filter (or any other code that consumes the internal model) is not clear on this point. It would be good if the spec nailed this down one way or the other. |
Thanks for the well explained summary @EricWittmann I think this pattern works well when the value is the equivalent of For example: a boolean property with default of I think where I am getting at is that perhaps we need to specify that the processor This way the processor can easily ignore unspecified attributes, with the exception of special cases, such as |
OK so while I understand Tim's position on this (he's advocating for his option 1 above) I disagree. If we implemented option 1 above, the generated OpenAPI documents would be a big mess. Take @Operation(
summary = "Get Example",
description = "This is the description of my operation."
) The result is that the generator will add both summary and description to the OpenAPI operation. Something like: "get" : {
"summary": "Get Example",
"description": "This is the description of my operation."
} If we require that the annotation processor never allow null values in the model, then instead we'll get this: "get" : {
"summary": "Get Example",
"description": "This is the description of my operation.",
"operationId": "",
"deprecated": false,
"hidden": false
} I have two problems with this specific example. First is that we've added properties that aren't needed and weren't set in the annotation by the user (the whole point of all this) and also that we've very likely added an invalid OK but maybe you're saying that's actually not that bad. We can probably address the If you look at another annotation, the problem gets WAY worse. Namely the IMO :) |
In response to @arthurdm - I agree that boolean is probably the most problematic, although some of the numeric values are also a bit wonky. I'm not sure about requiring a SmallRye style approach for the processor. That might be a bit of a tough requirement for some impls... |
Looks like I need to clarify. I heartily agree with the goal of a minimalist output document. I'm not advocating for showing values in the document that are defaulted. My main point is that the spec needs to be explicit about whether nulls can appear in the internal model because, in my view, that would be surprising given that annotation properties cannot be declared with null values, explicit or default. That internal model is populated by annotation processors and developer-provided model readers and consumed by developer-provided filters and the document writer. All parties need to know what the rules are, so the spec has to tell them. My secondary point is that I see the pros and cons of using nulls in the internal model to represent "not specified." Because there's no way to declare an annotation property to have a null value, I tend to think it's potentially astonishing to a filter developer, for example, to need to do null checks on the corresponding fields in the model. That said, it's certainly convenient in other places to use nulls this way. In truth, the second point is not a hill I'm willing to die on. The first point, though, I think is. The spec has to say whether nulls are OK and what that means. |
OK thanks for the clarification. I suspect we can agree that nulls in a data model is a pretty normal thing to see. However, your point (if I finally understand it fully) is that nulls in the data model produced by the annotation scanner seems bad because the properties in the java annotations cannot be null. Now, the latter is only true because Java is stupid about that - but it does remain true. It's worth pointing out that filtering is the final processing step, so it will be filtering a model that was produced through some combination of:
Even if we force non-nulls into the data model for the 3rd step, it seems to me that nulls are going to get in there for the first 2. So filtering needs to handle nulls. In any case, I understand your main point: the spec should be explicit about whether null values can be in the data model. I don't see why we couldn't add some text to the spec for that. I probably don't see it as a priority the way that you do, but I also don't have any objection. :) If you're interested in submitting a PR as a suggestion of this change, that'd be awesome. If not that's fine too - we'll discuss on the next call. |
Indeed, in general nulls in a data model are normal. We do have the data point that the filter in the TCK was not written to tolerate nulls. https://github.com/eclipse/microprofile-open-api/blob/2.0/tck/src/main/java/org/eclipse/microprofile/openapi/filter/AirlinesOASFilter.java#L132 Granted, it was probably designed to be fine-tuned to the specific endpoints it was expecting. But developers might well use TCK code as an example so that code should reflect the possibility of nulls. |
This has been a very interesting discussion, and also relates to the discussion about request bodies here: #349 We discussed this again during today's hangout and have reached some conclusions. The first is that after considering all the points that have been made, we still think that the current way annotation property defaults are treated is appropriate and the least evil of the options we have. So we're going to continue with the approach that default values for the MP+OAI annotation properties should be treated (by implementations) as though the property was not specified by the developer. This is not perfect but we think it's the best developer experience. However, we can (and will) make some changes to make things clearer for both implementer and users of the spec. Things we are going to change/add:
Now, typically the default values for annotation properties should match (as closely as possible) the default value for that property in the upstream OpenAPI specification. This should cut down on some confusion, but is not always possible and more confusingly is not always desirable. Because the annotation scanner in Microprofile+OpenAPI is targeting JAX-RS, we feel that default scanning behavior should accurately reflect the characteristics of JAX-RS rather than the default values of OpenAPI. So in some exceptional cases, the default value for certain annotation properties may differ from the upstream specification default so that the default behavior of the annotation scanner more closely models the actual behavior of the application. The current example of this is #349, where we will be changing the default value of
Hopefully this is a rational choice we are making, given the lack of completely ideal choices. If Java would only allow |
This may be a silly idea, but would it make sense to do something like this:
The generator should substitute For extra points, let a new OpenApi flag control whether to default substitution to empty string (as it happens today), or resource method name. This would allow generation of richer APIs without having to annotate all methods, as we have to do today. Which is a pain. |
Currently this specification includes a set of Java annotations that developers can use to further document their JAX-RS APIs directly in code. All of these annotations have properties (that typically correspond closely with OpenAPI properties) with default values. For example:
Every annotation property has a default value so that developers can pick and choose which properties they wish to include when they apply the operation in their code. For example, when applying the above
Operation
annotation, the developer can provide asummary
without being required to also provide adescription
andoperationId
:The Microprofile OpenAPI implementation's annotation scanner is responsible for turning all of these annotations into a generated OpenAPI document.
The default values for all properties in all MP+OAI annotations are meant to indicate to the annotation scanner that the developer did not include that property in their application of the annotation. The default values are NOT meant to indicate what value the property will have in the generated OpenAPI document.
For the example above, this is what the OpenAPI annotation scanner might generate:
Notice that no
operationId
is included, and nodescription
is included in the output, despite the@Operation
annotation being applied. That annotation has bothoperationId
anddescription
properties with default value of empty string. Nevertheless, the annotation processor did not generate those properties in the output document. Again, the reason for this is that the default values for annotation properties are intended to signal to the annotation processor that the developer did not include the property when they added the annotation to their code, so the annotation processor should do whatever is appropriate for that property. In most cases, the appropriate thing is to omit the property from the output.For some properties this behavior is sensible, but for others it is more confusing. However, because there is no way, in Java, to set the default value of an annotation property to null, it's the best we've got.
So to clarify the behavior of these annotations, we should consider updating the javadoc for at least the annotation properties with confusing default values. This is a rather subjective task, so I think we can start by enumerating which of the properties might be confusing by listing them in comments to this issue.
The text was updated successfully, but these errors were encountered: