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
8264124: Update MXBean specification and implementation to extend mapping of CompositeType to records #3201
Conversation
…ping of CompositeType to records
👋 Welcome back dfuchs! A progress list of the required criteria for merging this PR into |
Webrevs
|
/csr needed |
@dfuch has indicated that a compatibility and specification (CSR) request is needed for this pull request. |
<p>If the class is a {@link Record} and the getter is a component | ||
accessor for a record component {@code name} of type <em>T</em>, | ||
then the item in the {@code CompositeType} has the same name | ||
than the record component, and has type <em>opentype(T)</em>.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The update to the MXBean spec looks good. Do you have a typo here, I assume it should say "as the record component".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, thanks. Qualifying it as "a typo" was too kind ;-)
I have updated the PR. I also moved the record
example after the from
example to respect the order of precedence.
…to respect the logical order of precedence.
Generally, I think that this is a good change. It nice to see that the semantics of record classes can be leverage to build the CompositeType in this way. And equally how that maps back to the canonical constructor. |
@@ -753,7 +753,9 @@ another proxy (like {@code ModuleMXBean.getProduct()} which | |||
{@code CompositeType} is determined by the <a href="#type-names"> | |||
type name rules</a> below.</p> | |||
|
|||
<p>The class is examined for getters using the conventions | |||
<p>If the class is a {@link Record}, its getters are the | |||
accessors for the record components. Otherwise, the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be good to add a link like {@linkplain RecordComponent record components}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You add record in "Mappings for other types". I think it deserves a separate section "Mappings for record classes" (maybe after primitive types). It's useful to add a row for record in the summary table above "Mappings for primitive types"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Link added. With respect to adding a section for records, it's a bit difficult to separate that from the "Mapping for other types" without a lot of duplication. I can add a row in the summary table, and then add a new section "Mapping for records" just before "Mapping for other types", that just gives a brief overview and refers to the mapping for other types below.
Something like this - what do you think?
<h3 id="records">Mappings for Records</h3>
<p>A {@linkplain Record record} <em>R</em> whose {@linkplain
Class#getRecordComponents() components} are
all convertible to open types, is itself convertible to a
{@link CompositeType} as follows.
The type name of this {@code CompositeType}
is determined by the same <a href="#type-names">type name rules</a>
defined by the <a href="#composite-map">Mapping for other types</a>
below. Its getters are the accessors for the {@linkplain
RecordComponent record components}, and the record is reconstructed
using its canonical constructor, without needing any annotation.</p>
<p>A record may also expose additional non-canonical constructors, which
can be used to reconstruct the record if the composite data does
not exactly contain all the components expected by the
canonical constructor. However, in order to be taken into account
by the MXBean framework, such non-canonical constructors
need to be annotated with either the {@link ConstructorParameters
@javax.management.ConstructorParameters} or
{@code @java.beans.ConstructorProperties} annotation.</p>
<p>The complete rules for the mapping are detailed as part
of the <a href="#composite-map">Mapping for other types</a>
below.</p>
<h3 id="composite-map">Mappings for other types</h3>
<p>Given a record, or a Java class or interface <em>J</em> that does not match the other
rules in the table above, the MXBean framework will attempt to map
it to a {@link CompositeType} as follows. [....]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Mandy, I have updated the PR with a revised version of the text above. Is that more in line what you had in mind?
best regards,
-- daniel
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks better. I like a separate mapping section for records since the mapping rules are straight-forward. The complexity comes if we want to support a record to implement CompositeDataView
that allows a type to support more flexible conversion to CompositeData
which is why you add records in the "Mappings for other types". I am wondering if we really want to support records to implement CompositeDataView
but we may want to avoid such a special case.
I suggest add subsections in "Mappings for other types": There are two mapping rules: (1) opentype(J) maps J
to CompositeType
(2) opendata(J) maps J
to CompositeData
. opentype(J) for record class does not need to refer to other types. The common cases for opendata(J) for record class is using the canonical constructors. The other less common cases like using non-canonical constructors and CompositeDataView
can state that it follows the same rules as specified for other types. "Mappings for other types" does not need any change for records.
"Reconstructing an instance of Java type J from a CompositeData" section should be renamed to "Reconstructing an instance of Java type or record class J from a CompositeData"
Here is a minor tweaking on "Mappings for Records"
A record is convertible to a CompositeType if and only if all its components are
convertible to open types. Otherwise, it is not convertible.
A record class is converted to a CompositeType with one item for every record component as follows.
- The type name of this CompositeType is determined by the type name rules detailed below.
- Each record component of type T, the item in the CompositeType has the same name
as the record component and of type opentype(T).
The mapping from an instance of a record class to a CompositeData corresponding to
the CompositeType is the same as specified as for other types (add a link).
A record is reconstructed from a CompositeData using its canonical constructor.
The canonical constructor doesn't require the presence of @javax.management.ConstructorParameters
or @java.beans.ConstructorProperties annotations. If these annotations are present on
the canonical constructor, they will be ignored.
If the CompositeData from which the record is reconstructed doesn't contain all the record components,
the MXBean framework will attempt to reconstruct the record in the same way as specified for
other types (add a link).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have updated the PR with those changes, plus a few minor adjustments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for making the change. The spec change looks good to me.
@mlchung @AlanBateman @ChrisHegarty would you formally approve the fix? The CSR has been approved. |
@dfuch This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 95 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks okay to me but I'm not that familiar with the existing implementation. The test case covers the important cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spec and implementation changes look good.
/integrate |
@dfuch Since your change was applied there have been 109 commits pushed to the
Your commit was automatically rebased without conflicts. Pushed as commit d84a7e5. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
This RFE proposes to extend the MXBean framework to define a mapping to records.
The MXBean framework already defines a mapping of
CompositeType
to plain java objects. Records are a natural representation of CompositeTypes. A record can be easily reconstructed from aCompositeData
through the record canonical constructor. A clear advantage of records over plain java objects is that the canonical constructor will not need to be annotated in order to map composite data property names to constructor parameter names.With this RFE, here is an example comparing coding a composite type
NamedNumber
that consists of anint
and aString
, using records and using a plain java class. In both case, theCompositeType
looks like this:The plain Java class needs a public constructor annotated with
@ConstructorParameters
annotation:And the equivalent with a record class:
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/3201/head:pull/3201
$ git checkout pull/3201
Update a local copy of the PR:
$ git checkout pull/3201
$ git pull https://git.openjdk.java.net/jdk pull/3201/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 3201
View PR using the GUI difftool:
$ git pr show -t 3201
Using diff file
Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/3201.diff