@@ -356,6 +356,15 @@ public JsonToken nextToken() throws JacksonException
356356 _streamReadContext = _streamReadContext .getParent ();
357357 return _updateToken (JsonToken .END_OBJECT );
358358 }
359+ // [dataformats-text#589]: complex (non-scalar) mapping keys
360+ if (evt .getEventId () == Event .ID .SequenceStart
361+ || evt .getEventId () == Event .ID .MappingStart ) {
362+ final String name = _decodeComplexPropertyName (evt );
363+ _streamReadConstraints .validateNameLength (name .length ());
364+ _currentName = name ;
365+ _streamReadContext .setCurrentName (name );
366+ return _updateToken (JsonToken .PROPERTY_NAME );
367+ }
359368 _reportError ("Expected a property name (Scalar value in YAML), got this instead: " +evt );
360369 }
361370
@@ -481,6 +490,119 @@ protected Event nextEvent() {
481490 return _yamlParser .next ();
482491 }
483492
493+ /**
494+ * Helper method called when a non-scalar event (Sequence or Mapping start) is encountered
495+ * where a property name is expected -- indicates a "complex key" in YAML terms.
496+ * Consumes the full key structure and converts to a canonical String representation
497+ * (flow-style) so that Jackson's scalar-only property name model can represent it.
498+ *
499+ * @since 3.2
500+ */
501+ protected String _decodeComplexPropertyName (Event evt ) throws JacksonException
502+ {
503+ StringBuilder sb = new StringBuilder (32 );
504+ _appendComplexKey (evt , sb , 0 );
505+ return sb .toString ();
506+ }
507+
508+ private void _appendComplexKey (Event evt , StringBuilder sb , int depth ) throws JacksonException
509+ {
510+ _streamReadConstraints .validateNestingDepth (depth );
511+ switch (evt .getEventId ()) {
512+ case Scalar :
513+ _appendComplexKeyScalar (((ScalarEvent ) evt ).getValue (), sb );
514+ return ;
515+ case SequenceStart :
516+ sb .append ('[' );
517+ _appendComplexKeySequenceContent (sb , depth + 1 );
518+ sb .append (']' );
519+ return ;
520+ case MappingStart :
521+ sb .append ('{' );
522+ _appendComplexKeyMappingContent (sb , depth + 1 );
523+ sb .append ('}' );
524+ return ;
525+ default :
526+ _reportError ("Unexpected YAML event for complex property name, expected Scalar, Sequence or Mapping start, got: " +evt );
527+ }
528+ }
529+
530+ private void _appendComplexKeySequenceContent (StringBuilder sb , int depth ) throws JacksonException
531+ {
532+ boolean first = true ;
533+ while (true ) {
534+ Event evt = nextEvent ();
535+ if (evt == null ) {
536+ _reportError ("Unexpected end-of-input in complex property name (sequence)" );
537+ }
538+ if (evt .getEventId () == Event .ID .SequenceEnd ) {
539+ return ;
540+ }
541+ if (!first ) {
542+ sb .append (", " );
543+ }
544+ first = false ;
545+ _appendComplexKey (evt , sb , depth );
546+ }
547+ }
548+
549+ private void _appendComplexKeyMappingContent (StringBuilder sb , int depth ) throws JacksonException
550+ {
551+ boolean first = true ;
552+ while (true ) {
553+ Event keyEvt = nextEvent ();
554+ if (keyEvt == null ) {
555+ _reportError ("Unexpected end-of-input in complex property name (mapping)" );
556+ }
557+ if (keyEvt .getEventId () == Event .ID .MappingEnd ) {
558+ return ;
559+ }
560+ if (!first ) {
561+ sb .append (", " );
562+ }
563+ first = false ;
564+ _appendComplexKey (keyEvt , sb , depth );
565+ sb .append (": " );
566+ Event valEvt = nextEvent ();
567+ if (valEvt == null ) {
568+ _reportError ("Unexpected end-of-input in complex property name (mapping value)" );
569+ }
570+ _appendComplexKey (valEvt , sb , depth );
571+ }
572+ }
573+
574+ private void _appendComplexKeyScalar (String value , StringBuilder sb )
575+ {
576+ if (_needsQuotesForComplexKey (value )) {
577+ sb .append ('"' );
578+ for (int i = 0 , len = value .length (); i < len ; ++i ) {
579+ char c = value .charAt (i );
580+ if (c == '"' || c == '\\' ) {
581+ sb .append ('\\' );
582+ }
583+ sb .append (c );
584+ }
585+ sb .append ('"' );
586+ } else {
587+ sb .append (value );
588+ }
589+ }
590+
591+ private boolean _needsQuotesForComplexKey (String value )
592+ {
593+ if (value .isEmpty ()) {
594+ return true ;
595+ }
596+ for (int i = 0 , len = value .length (); i < len ; ++i ) {
597+ char c = value .charAt (i );
598+ if (c == ':' || c == ',' || c == '[' || c == ']' || c == '{' || c == '}'
599+ || c == ' ' || c == '\t' || c == '\n' || c == '\r' ) {
600+ return true ;
601+ }
602+ }
603+ return false ;
604+ }
605+
484606 protected JsonToken _decodeScalar (ScalarEvent scalar ) throws JacksonException
485607 {
486608 String value = scalar .getValue ();
0 commit comments