palantir / palantir/conjure-java

Add more helper methods for dealing with union types

Open
#373 1 comment 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
39
Forks
49
Avg merge
8h 22m
Merged PRs (30d)
32

Description

What happened?

We have a lot of data structures that are unions with many possible value types (sometimes over a dozen). Working with these can be very difficult since code needs to implement a visitor for all possible types, even if the code wants to ignore most of those types, or in the cases of tests assert that the object has a specific type (in tests it isn't very obvious how you would even construct a Matcher for these without implementing a visitor that defines every single method -- even the ones you don't want to match against). Using just object equals in tests is often not an option since the test might only want to assert on parts of the value, or some fields might be things like timestamps that change (in the case of integration tests etc). The current workaround is often for testing purposes to define a visitor that throws in every method, and then in tests extend that base visitor and @Override the one (or several) methods you want to handle in the test.

What did you want to happen?

Consider adding generated methods to union types that allow you to easily test if a union object has a specific type, and retrieve the value from it. These would work by allowing the user to create a java.util.function.Consumer that accepts that type.

As a concrete example, consider this (partial) conjure object definition:

MyData:
  union:
    foo: FooType
    # ... many other subtypes follow

Methods like this could be generated on MyData:

public void ifFoo(Consumer<FooType> consumer) {
    if (value instanceof FooWrapper) {
        consumer.accept((FooWrapper) value).value);
    }
}

Similarly we could generate a method like this to throw if the object does not have that type:

public void requireFoo(Consumer<FooType> consumer) {
    if (value instanceof FooWrapper) {
        consumer.accept((FooWrapper) value).value);
    } else {
        throw new IllegalStateException(...);
    }
}

Another alternative is to auto generate an abstract visitor that throws in every method, so that you can extend that and @Override the specific methods you want.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating the union-type generation entry point in conjure-java and compare the proposed ifFoo/requireFoo Consumer methods with the alternative abstract visitor. Use the MyData/FooType example to define the generated API and verify behavior for matching and non-matching union values.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.