2323import java .util .function .Predicate ;
2424
2525import java .util .Arrays ;
26+ import java .util .Iterator ;
2627import java .util .List ;
2728import java .util .Map ;
2829import java .util .Map .Entry ;
4243 * An {@linkplain Attributed attributed} {@link Value} with a {@linkplain #name() name}, {@linkplain #values() named
4344 * values}, and {@linkplain #notes() non-normative named values}.
4445 *
45- * @param name a non-{@code null} name of this {@link Attributes}
46+ * @param name a non-{@code null} name of this {@link Attributes}; names that begin with the {@code $} character are
47+ * reserved for internal use
4648 *
47- * @param values a non-{@code null} {@link Map} of named {@linkplain Value values} associated with this {@link Attributes}
49+ * @param values a non-{@code null} {@link Map} of named {@linkplain Value values} associated with this {@link
50+ * Attributes}; keys in this {@link Map} that begin with the {@code $} character are reserved for internal use
4851 *
4952 * @param notes a non-{@code null} {@link Map} of non-normative named {@linkplain Value values} associated with this
50- * {@link Attributes}
53+ * {@link Attributes}; keys in this {@link Map} that begin with the {@code $} character are reserved for internal use
5154 *
52- * @param attributesMap a non-{@code null} {@link Map} of named metadata associated with this {@link Attributes}
55+ * @param attributesMap a non-{@code null} {@link Map} of named metadata associated with this {@link Attributes}; any
56+ * {@link List} stored under a key that is equal to the supplied {@code name} is considered to be a list of {@link
57+ * Attributes} pertaining to this {@link Attributes} itself; other keys are normally (but are not required to be) the
58+ * names of keys in the supplied {@code values} or {@code notes} {@link Map}s; keys that begin with the {@code $}
59+ * character are reserved for internal use
5360 *
5461 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
5562 */
@@ -64,12 +71,17 @@ public final record Attributes(String name,
6471 *
6572 * @param name a non-{@code null} name of this {@link Attributes}
6673 *
67- * @param values a non-{@code null} {@link Map} of named {@linkplain Value values} associated with this {@link Attributes}
74+ * @param values a non-{@code null} {@link Map} of named {@linkplain Value values} associated with this {@link
75+ * Attributes}; keys in this {@link Map} that begin with the {@code $} character are reserved for internal use
6876 *
6977 * @param notes a non-{@code null} {@link Map} of non-normative named {@linkplain Value values} associated with this
70- * {@link Attributes}
78+ * {@link Attributes}; keys in this {@link Map} that begin with the {@code $} character are reserved for internal use
7179 *
72- * @param attributesMap a non-{@code null} {@link Map} of named metadata associated with this {@link Attributes}
80+ * @param attributesMap a non-{@code null} {@link Map} of named metadata associated with this {@link Attributes}; any
81+ * {@link List} stored under a key that is equal to the supplied {@code name} is considered to be a list of {@link
82+ * Attributes} pertaining to this {@link Attributes} itself; other keys are normally (but are not required to be) the
83+ * names of keys in the supplied {@code values} or {@code notes} {@link Map}s; keys in this {@link Map} that begin
84+ * with the {@code $} character are reserved for internal use
7385 *
7486 * @exception NullPointerException if any argument is {@code null}
7587 */
@@ -234,6 +246,42 @@ public final int hashCode() {
234246 return hashCode ;
235247 }
236248
249+ @ Override // Record
250+ public final String toString () {
251+ final StringBuilder sb = new StringBuilder ();
252+ sb .append ("@" ).append (this .name ());
253+ final Map <String , Value <?>> values = this .values ();
254+ final Map <String , Value <?>> notes = this .notes ();
255+ if (values .isEmpty () && notes .isEmpty ()) {
256+ return sb .toString ();
257+ }
258+ sb .append ("(" );
259+ if (!values .isEmpty ()) {
260+ final Iterator <Entry <String , Value <?>>> i = values .entrySet ().iterator ();
261+ while (i .hasNext ()) {
262+ final Entry <String , Value <?>> e = i .next ();
263+ sb .append (e .getKey ()).append (" = " ).append (e .getValue ());
264+ if (i .hasNext ()) {
265+ sb .append (", " );
266+ }
267+ }
268+ }
269+ if (!notes .isEmpty ()) {
270+ sb .append (" (" );
271+ final Iterator <Entry <String , Value <?>>> i = notes .entrySet ().iterator ();
272+ while (i .hasNext ()) {
273+ final Entry <String , Value <?>> e = i .next ();
274+ sb .append (e .getKey ()).append (" = " ).append (e .getValue ());
275+ if (i .hasNext ()) {
276+ sb .append (", " );
277+ }
278+ }
279+ sb .append (")" );
280+ }
281+ sb .append (")" );
282+ return sb .toString ();
283+ }
284+
237285 /**
238286 * Returns a suitably-typed {@link Value} indexed under the supplied {@code name}, or {@code null} if no such {@link
239287 * Value} exists.
0 commit comments