@@ -520,13 +520,15 @@ public DocumentField removeDocumentField(String field) {
520520 * @return a map of metadata fields for this hit
521521 */
522522 public Map <String , DocumentField > getMetadataFields () {
523+ assert hasReferences ();
523524 return Collections .unmodifiableMap (metaFields );
524525 }
525526
526527 /**
527528 * @return a map of non-metadata fields requested for this hit
528529 */
529530 public Map <String , DocumentField > getDocumentFields () {
531+ assert hasReferences ();
530532 return Collections .unmodifiableMap (documentFields );
531533 }
532534
@@ -535,6 +537,7 @@ public Map<String, DocumentField> getDocumentFields() {
535537 * were required to be loaded. Includes both document and metadata fields.
536538 */
537539 public Map <String , DocumentField > getFields () {
540+ assert hasReferences ();
538541 if (metaFields .size () > 0 || documentFields .size () > 0 ) {
539542 final Map <String , DocumentField > fields = new HashMap <>();
540543 fields .putAll (metaFields );
@@ -556,6 +559,7 @@ public boolean hasLookupFields() {
556559 * Resolve the lookup fields with the given results and merge them as regular fetch fields.
557560 */
558561 public void resolveLookupFields (Map <LookupField , List <Object >> lookupResults ) {
562+ assert hasReferences ();
559563 if (lookupResults .isEmpty ()) {
560564 return ;
561565 }
@@ -585,6 +589,7 @@ public void resolveLookupFields(Map<LookupField, List<Object>> lookupResults) {
585589 * A map of highlighted fields.
586590 */
587591 public Map <String , HighlightField > getHighlightFields () {
592+ assert hasReferences ();
588593 return highlightFields == null ? emptyMap () : highlightFields ;
589594 }
590595
@@ -724,6 +729,17 @@ private void deallocate() {
724729 r .decRef ();
725730 }
726731 SearchHit .this .source = null ;
732+ clearIfMutable (documentFields );
733+ clearIfMutable (metaFields );
734+ this .highlightFields = null ;
735+ }
736+
737+ private static void clearIfMutable (Map <String , DocumentField > fields ) {
738+ // check that we're dealing with a HashMap, instances read from the wire that are empty be of an immutable type
739+ assert fields instanceof HashMap <?, ?> || fields .isEmpty () : fields ;
740+ if (fields instanceof HashMap <?, ?> hm ) {
741+ hm .clear ();
742+ }
727743 }
728744
729745 @ Override
@@ -756,12 +772,16 @@ public SearchHit asUnpooled() {
756772 innerHits == null
757773 ? null
758774 : innerHits .entrySet ().stream ().collect (Collectors .toMap (Map .Entry ::getKey , e -> e .getValue ().asUnpooled ())),
759- documentFields ,
760- metaFields ,
775+ cloneIfHashMap ( documentFields ) ,
776+ cloneIfHashMap ( metaFields ) ,
761777 ALWAYS_REFERENCED
762778 );
763779 }
764780
781+ private Map <String , DocumentField > cloneIfHashMap (Map <String , DocumentField > map ) {
782+ return map instanceof HashMap <String , DocumentField > hashMap ? new HashMap <>(hashMap ) : map ;
783+ }
784+
765785 public boolean isPooled () {
766786 return refCounted != ALWAYS_REFERENCED ;
767787 }
0 commit comments