conjure-java icon indicating copy to clipboard operation
conjure-java copied to clipboard

Foo.Of method makes all arguments mandatory, including optionals

Open bshaibu opened this issue 6 years ago • 5 comments

What happened?

Adding an optional field to an object definition in yml causes the generated object to require the field in its of method. This technically makes any optional field addition breaking.

e.g. going from

      DuplicateRequest:
        fields:
          parentFolderId: optional<string>

to

      DuplicateRequest:
        fields:
          parentFolderId: optional<string>
          foo: optional<string>

generates

@JsonDeserialize(builder = DuplicateRequest.Builder.class)
@Generated("com.palantir.conjure.java.types.BeanGenerator")
public final class DuplicateRequest {
 ...
    public static DuplicateRequest of(String parentFolderId, String foo) {
        return builder().parentFolderId(Optional.of(parentFolderId)).foo(Optional.of(foo)).build();
    }
}

A few things seem off wrong here:

  • of shouldn't require optional fields - they should be optional or hidden via overloading
  • adding an optional field should preserve the previous of methods in case consumers were already using them - removing them

What did you want to happen?

Some combination of:

  • The of method should require optionals for optional fields.
  • The of method should be overloaded for all possible argument combinations given optional arguments
  • The of method only takes required fields, ignoring optional ones so there's no chance of breaks
  • No of method in the first place

I'm making the assumption that the method signature change here is a (small) break.

bshaibu avatar Nov 05 '18 17:11 bshaibu

We've hotly debated this a couple of times, I think what I'd propose is:

  1. we eliminate of method generation from the -api projects
  2. (low confidence) we consider offering a -utils project that includes of methods and other convenience classes

markelliot avatar Nov 05 '18 18:11 markelliot

To be clear, adding an optional field is not a wire format break. Your issue is describing a compilation break that users of the .of fields might encounter.

I like the sound of making the .of factory take only required fields though, because if you're willing to add a new required field (i.e. impose a wire-break) then it's fine to impose a compilation break?

Note that this still doesn't give us 100% wire format compatibility though, as users are free to rename conjure types (e.g. DuplicateRequest -> DuplicateItemRequest) which is wire-format compatible but would obviously result in a compilation break.

iamdanfox avatar Nov 05 '18 18:11 iamdanfox

Another point in favor of removing the of method is that it breaks backward compatibility of the produced jars, since the signature of the of method can change due to a backward compatible change in a object definition. This can result in MethodNotFound errors at runtime (even when using things like gradle-consistent-versions) because dependencies may have been compiled against an older version of an API whose of method has a different signature.

pkoenig10 avatar Apr 11 '19 17:04 pkoenig10

This has just bitten us again on an internal project (PDS-399497). Is a potential path forward here with making a change to of methods behind a config flag?

I'd propose something like this option:

conjure {
    java {
        omitOptionalFieldsFromOfMethods = true
    }
}

Where now an object like this:

      MyObject:
        fields:
          myRequiredField: string
          myOptionalField: optional<string>

would have its generated of method have a parameter for myRequiredField but not for myOptionalField.

ash211 avatar Aug 16 '23 21:08 ash211

After speaking with @carterkozak, we'd prefer omitGeneratedOfMethods = true to remove the of factory methods entirely, instead of a half-measure that changed the method structure.

Code change is potentially around here: https://github.com/palantir/conjure-java/blob/771a824da8320881509d80da929ba87d37bf3d15/conjure-java-core/src/main/java/com/palantir/conjure/java/types/BeanGenerator.java#L129

ash211 avatar Aug 16 '23 21:08 ash211