TokenBufferReadContext.java

package tools.jackson.databind.util;

import tools.jackson.core.*;
import tools.jackson.core.io.ContentReference;
import tools.jackson.core.json.JsonReadContext;

/**
 * Implementation of {@link TokenStreamContext} used by {@link TokenBuffer}
 * to link back to the original context to try to keep location information
 * consistent between source location and buffered content when it's re-read
 * from the buffer.
 */
public class TokenBufferReadContext extends TokenStreamContext
{
    protected final TokenStreamContext _parent;

    protected final TokenStreamLocation _startLocation;

    // Benefit for reusing?
//    protected JsonReadContext _child;

    /*
    /**********************************************************************
    /* Location/state information (minus source reference)
    /**********************************************************************
     */

    protected String _currentName;

    protected Object _currentValue;

    protected TokenBufferReadContext(TokenStreamContext base, ContentReference contentRef)
    {
        super(base);
        _parent = base.getParent();
        _currentName = base.currentName();
        _currentValue = base.currentValue();
        if (base instanceof JsonReadContext rc) {
            _startLocation = rc.startLocation(contentRef);
        } else {
            _startLocation = TokenStreamLocation.NA;
        }
    }

    protected TokenBufferReadContext(TokenStreamContext base, TokenStreamLocation startLoc) {
        super(base);
        _parent = base.getParent();
        _currentName = base.currentName();
        _currentValue = base.currentValue();
        _startLocation = startLoc;
    }

    /**
     * Constructor for case where there is no real surrounding context: just create
     * virtual ROOT
     */
    protected TokenBufferReadContext() {
        super(TYPE_ROOT, -1);
        _parent = null;
        _startLocation = TokenStreamLocation.NA;
    }

    protected TokenBufferReadContext(TokenBufferReadContext parent, int type, int index) {
        super(type, index);
        _parent = parent;
        _startLocation = parent._startLocation;
    }

    @Override
    public Object currentValue() {
        return _currentValue;
    }

    @Override
    public void assignCurrentValue(Object v) {
        _currentValue = v;
    }

    /*
    /**********************************************************************
    /* Factory methods
    /**********************************************************************
     */

    public static TokenBufferReadContext createRootContext(TokenStreamContext origContext) {
        // First: possible to have no current context; if so, just create bogus ROOT context
        if (origContext == null) {
            return new TokenBufferReadContext();
        }
        return new TokenBufferReadContext(origContext, ContentReference.unknown());
    }

    public TokenBufferReadContext createChildArrayContext() {
        // For current context there will be one next Array value, first:
        ++_index;
        return new TokenBufferReadContext(this, TYPE_ARRAY, -1);
    }

    public TokenBufferReadContext createChildObjectContext() {
        // For current context there will be one next Object value, first:
        ++_index;
        return new TokenBufferReadContext(this, TYPE_OBJECT, -1);
    }

    /**
     * Helper method we need to handle discontinuity between "real" contexts buffer
     * creates, and ones from parent: problem being they are of different types.
     */
    public TokenBufferReadContext parentOrCopy() {
        // 30-Apr-2017, tatu: This is bit awkward since part on ancestor stack is of different
        //     type (usually `JsonReadContext`)... and so for unbalanced buffers (with extra
        //     END_OBJECT / END_ARRAY), we may need to create
        if (_parent instanceof TokenBufferReadContext tokenBufferReadContext) {
            return tokenBufferReadContext;
        }
        if (_parent == null) { // unlikely, but just in case let's support
            return new TokenBufferReadContext();
        }
        return new TokenBufferReadContext(_parent, _startLocation);
    }

    /*
    /**********************************************************************
    /* Abstract method implementation
    /**********************************************************************
     */

    @Override public String currentName() { return _currentName; }

    @Override public boolean hasCurrentName() { return _currentName != null; }

    @Override public TokenStreamContext getParent() { return _parent; }

    public void setCurrentName(String name) {
        _currentName = name;
    }

    /*
    /**********************************************************************
    /* Extended support for context updates
    /**********************************************************************
     */

    public void updateForValue() {
        ++_index;
    }
}