Skip to content

​​Question:​​ Delegating a parser/generator like ParserMinimalBase or ParserBase #1428

@honhimW

Description

@honhimW

I'm currently trying to use jackson-dataformat-cbor:2.19.0 and want to parse custom tags. Since I couldn't find specific examples, I attempted to implement it with the following code.

public class CborParserDelegate extends JsonParserDelegate {

    protected final CBORParser delegate;

    public CborParserDelegate(CBORParser d) {
        super(d);
        this.delegate = d;
    }

    @Override
    public CBORParser delegate() {
        return (CBORParser) super.delegate();
    }

    public int getCurrentTag() {
        return delegate().getCurrentTag();
    }

    public CBORParser.TagList getCurrentTags() {
        return delegate().getCurrentTags();
    }

}
public class CustomTagsCborParser extends CborParserDelegate {

    public CustomTagsCborParser(CBORParser d) {
        super(d);
        try {
            this.method = ParserMinimalBase.class.getDeclaredMethod("_updateToken", JsonToken.class);
            this.method.setAccessible(true);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private final Method method;
    private Object customValue;

    @Override
    public JsonToken nextToken() throws IOException {
        JsonToken jsonToken = super.nextToken();
        int currentTag = delegate.getCurrentTag();
        if (currentTag != -1) {
            ObjectCodec codec = getCodec();
            this.customValue = mapValue(currentTag, codec.readTree(delegate));
            return Err.call(() -> (JsonToken) method.invoke(delegate, JsonToken.VALUE_EMBEDDED_OBJECT));
        }
        return jsonToken;
    }


    @Override
    public Object getEmbeddedObject() throws IOException {
        if (this.customValue != null) {
            Object v = this.customValue;
            this.customValue = null;
            return v;
        }
        return super.getEmbeddedObject();
    }

    private Object mapValue(int tag, TreeNode treeNode) {
        CustomTag customTag = CustomTag.of(tag);
        switch (customTag) {
            case TAG_12: {
                _assert(treeNode.isArray(), "TAG_12 should be an array with two items.");
                ArrayNode arrayNode = (ArrayNode) treeNode;
                long seconds = arrayNode.get(0).asLong(0);
                long nanoSeconds = arrayNode.get(1).asLong(0);
                return Instant.ofEpochSecond(seconds, nanoSeconds);
            }
            case TAG_14: {
                _assert(treeNode.isArray(), "TAG_14 should be an array with two items.");
                ArrayNode arrayNode = (ArrayNode) treeNode;
                long seconds = arrayNode.at("/0").asLong(0);
                long nanoSeconds = arrayNode.at("/1").asLong(0);
                return Duration.ofSeconds(seconds, nanoSeconds);
            }
            default:
                return treeNode;
        }
    }

    private void _assert(boolean state, String message) {
        if (!state) {
            throw new IllegalStateException(message);
        }
    }

}

However, since CborParser inherits from ParserMinimalBase, calling its _updateToken(JsonToken) method requires reflection, which I'd like to avoid.

So my questions are:

  1. Is my approach for custom tag parsing with dataformat-cbor correct (or aligned with your design)? If not, what should I do instead?
  2. Is there a way to avoid using reflection when updating tokens?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions