Apollo-android: generated classes not importing input types for array arguments

Created on 11 Jan 2019  路  13Comments  路  Source: apollographql/apollo-android

Using version (1.0.0-alpha4)

If the graphql mutation has an array argument, the associated type is not imported in the generated class.

Related details:

  1. schema.json
  2. The mutation is:
    gql mutation Some ($usersinput:[UsersInput]){ addUsers ( users: $usersinput ) { id name } }
  3. The generated class is:



    Click to expand

    ```java
    import com.apollographql.apollo.api.Input;
    import com.apollographql.apollo.api.InputFieldMarshaller;
    import com.apollographql.apollo.api.InputFieldWriter;
    import com.apollographql.apollo.api.Mutation;
    import com.apollographql.apollo.api.Operation;
    import com.apollographql.apollo.api.OperationName;
    import com.apollographql.apollo.api.ResponseField;
    import com.apollographql.apollo.api.ResponseFieldMapper;
    import com.apollographql.apollo.api.ResponseFieldMarshaller;
    import com.apollographql.apollo.api.ResponseReader;
    import com.apollographql.apollo.api.ResponseWriter;
    import com.apollographql.apollo.api.internal.UnmodifiableMapBuilder;
    import com.apollographql.apollo.api.internal.Utils;
    import java.io.IOException;
    import java.lang.Object;
    import java.lang.Override;
    import java.lang.String;
    import java.util.Collections;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    import javax.annotation.Generated;
    import org.jetbrains.annotations.NotNull;
    import org.jetbrains.annotations.Nullable;

    // UsersInput has not been imported (The type has been generated)
    // import type.UsersInput;

    @Generated("Apollo GraphQL")
    public final class SomeMutation implements Mutation {
    public static final String OPERATION_ID = "5e621ce2d6ad52ad8438102c751de59ddc58519d8acf3da2cf156e62fe783754";

    public static final String QUERY_DOCUMENT = "mutation Some($usersinput: [UsersInput]) {\n"
        + "  addUsers(users: $usersinput) {\n"
        + "    __typename\n"
        + "    id\n"
        + "    name\n"
        + "  }\n"
        + "}";
    
    public static final OperationName OPERATION_NAME = new OperationName() {
      @Override
      public String name() {
        return "Some";
      }
    };
    
    private final SomeMutation.Variables variables;
    
    public SomeMutation(@NotNull Input<List<type.UsersInput>> usersinput) {
      Utils.checkNotNull(usersinput, "usersinput == null");
      variables = new SomeMutation.Variables(usersinput);
    }
    
    @Override
    public String operationId() {
      return OPERATION_ID;
    }
    
    @Override
    public String queryDocument() {
      return QUERY_DOCUMENT;
    }
    
    @Override
    public SomeMutation.Data wrapData(SomeMutation.Data data) {
      return data;
    }
    
    @Override
    public SomeMutation.Variables variables() {
      return variables;
    }
    
    @Override
    public ResponseFieldMapper<SomeMutation.Data> responseFieldMapper() {
      return new Data.Mapper();
    }
    
    public static Builder builder() {
      return new Builder();
    }
    
    @Override
    public OperationName name() {
      return OPERATION_NAME;
    }
    
    public static final class Builder {
      private Input<List<type.UsersInput>> usersinput = Input.absent();
    
      Builder() {
      }
    
      public Builder usersinput(@Nullable List<type.UsersInput> usersinput) {
        this.usersinput = Input.fromNullable(usersinput);
        return this;
      }
    
      public Builder usersinputInput(@NotNull Input<List<type.UsersInput>> usersinput) {
        this.usersinput = Utils.checkNotNull(usersinput, "usersinput == null");
        return this;
      }
    
      public SomeMutation build() {
        return new SomeMutation(usersinput);
      }
    }
    
    public static final class Variables extends Operation.Variables {
      private final Input<List<type.UsersInput>> usersinput;
    
      private final transient Map<String, Object> valueMap = new LinkedHashMap<>();
    
      Variables(Input<List<type.UsersInput>> usersinput) {
        this.usersinput = usersinput;
        if (usersinput.defined) {
          this.valueMap.put("usersinput", usersinput.value);
        }
      }
    
      public Input<List<type.UsersInput>> usersinput() {
        return usersinput;
      }
    
      @Override
      public Map<String, Object> valueMap() {
        return Collections.unmodifiableMap(valueMap);
      }
    
      @Override
      public InputFieldMarshaller marshaller() {
        return new InputFieldMarshaller() {
          @Override
          public void marshal(InputFieldWriter writer) throws IOException {
            if (usersinput.defined) {
              writer.writeList("usersinput", usersinput.value != null ? new InputFieldWriter.ListWriter() {
                @Override
                public void write(InputFieldWriter.ListItemWriter listItemWriter) throws IOException {
                  for (final UsersInput $item : usersinput.value) {
                    listItemWriter.writeObject($item != null ? $item.marshaller() : null);
                  }
                }
              } : null);
            }
          }
        };
      }
    }
    
    public static class Data implements Operation.Data {
      static final ResponseField[] $responseFields = {
        ResponseField.forList("addUsers", "addUsers", new UnmodifiableMapBuilder<String, Object>(1)
        .put("users", new UnmodifiableMapBuilder<String, Object>(2)
          .put("kind", "Variable")
          .put("variableName", "usersinput")
          .build())
        .build(), true, Collections.<ResponseField.Condition>emptyList())
      };
    
      final @Nullable List<AddUser> addUsers;
    
      private transient volatile String $toString;
    
      private transient volatile int $hashCode;
    
      private transient volatile boolean $hashCodeMemoized;
    
      public Data(@Nullable List<AddUser> addUsers) {
        this.addUsers = addUsers;
      }
    
      public @Nullable List<AddUser> addUsers() {
        return this.addUsers;
      }
    
      public ResponseFieldMarshaller marshaller() {
        return new ResponseFieldMarshaller() {
          @Override
          public void marshal(ResponseWriter writer) {
            writer.writeList($responseFields[0], addUsers, new ResponseWriter.ListWriter() {
              @Override
              public void write(List items, ResponseWriter.ListItemWriter listItemWriter) {
                for (Object item : items) {
                  listItemWriter.writeObject(((AddUser) item).marshaller());
                }
              }
            });
          }
        };
      }
    
      @Override
      public String toString() {
        if ($toString == null) {
          $toString = "Data{"
            + "addUsers=" + addUsers
            + "}";
        }
        return $toString;
      }
    
      @Override
      public boolean equals(Object o) {
        if (o == this) {
          return true;
        }
        if (o instanceof Data) {
          Data that = (Data) o;
          return ((this.addUsers == null) ? (that.addUsers == null) : this.addUsers.equals(that.addUsers));
        }
        return false;
      }
    
      @Override
      public int hashCode() {
        if (!$hashCodeMemoized) {
          int h = 1;
          h *= 1000003;
          h ^= (addUsers == null) ? 0 : addUsers.hashCode();
          $hashCode = h;
          $hashCodeMemoized = true;
        }
        return $hashCode;
      }
    
      public static final class Mapper implements ResponseFieldMapper<Data> {
        final AddUser.Mapper addUserFieldMapper = new AddUser.Mapper();
    
        @Override
        public Data map(ResponseReader reader) {
          final List<AddUser> addUsers = reader.readList($responseFields[0], new ResponseReader.ListReader<AddUser>() {
            @Override
            public AddUser read(ResponseReader.ListItemReader listItemReader) {
              return listItemReader.readObject(new ResponseReader.ObjectReader<AddUser>() {
                @Override
                public AddUser read(ResponseReader reader) {
                  return addUserFieldMapper.map(reader);
                }
              });
            }
          });
          return new Data(addUsers);
        }
      }
    }
    
    public static class AddUser {
      static final ResponseField[] $responseFields = {
        ResponseField.forString("__typename", "__typename", null, false, Collections.<ResponseField.Condition>emptyList()),
        ResponseField.forInt("id", "id", null, false, Collections.<ResponseField.Condition>emptyList()),
        ResponseField.forString("name", "name", null, true, Collections.<ResponseField.Condition>emptyList())
      };
    
      final @NotNull String __typename;
    
      final int id;
    
      final @Nullable String name;
    
      private transient volatile String $toString;
    
      private transient volatile int $hashCode;
    
      private transient volatile boolean $hashCodeMemoized;
    
      public AddUser(@NotNull String __typename, int id, @Nullable String name) {
        this.__typename = Utils.checkNotNull(__typename, "__typename == null");
        this.id = id;
        this.name = name;
      }
    
      public @NotNull String __typename() {
        return this.__typename;
      }
    
      public int id() {
        return this.id;
      }
    
      public @Nullable String name() {
        return this.name;
      }
    
      public ResponseFieldMarshaller marshaller() {
        return new ResponseFieldMarshaller() {
          @Override
          public void marshal(ResponseWriter writer) {
            writer.writeString($responseFields[0], __typename);
            writer.writeInt($responseFields[1], id);
            writer.writeString($responseFields[2], name);
          }
        };
      }
    
      @Override
      public String toString() {
        if ($toString == null) {
          $toString = "AddUser{"
            + "__typename=" + __typename + ", "
            + "id=" + id + ", "
            + "name=" + name
            + "}";
        }
        return $toString;
      }
    
      @Override
      public boolean equals(Object o) {
        if (o == this) {
          return true;
        }
        if (o instanceof AddUser) {
          AddUser that = (AddUser) o;
          return this.__typename.equals(that.__typename)
           && this.id == that.id
           && ((this.name == null) ? (that.name == null) : this.name.equals(that.name));
        }
        return false;
      }
    
      @Override
      public int hashCode() {
        if (!$hashCodeMemoized) {
          int h = 1;
          h *= 1000003;
          h ^= __typename.hashCode();
          h *= 1000003;
          h ^= id;
          h *= 1000003;
          h ^= (name == null) ? 0 : name.hashCode();
          $hashCode = h;
          $hashCodeMemoized = true;
        }
        return $hashCode;
      }
    
      public static final class Mapper implements ResponseFieldMapper<AddUser> {
        @Override
        public AddUser map(ResponseReader reader) {
          final String __typename = reader.readString($responseFields[0]);
          final int id = reader.readInt($responseFields[1]);
          final String name = reader.readString($responseFields[2]);
          return new AddUser(__typename, id, name);
        }
      }
    }
    

    }
    ```

  4. Whenever I compile, I get this error:

    error: cannot find symbol class UsersInput
    

GraphQL server and android code to reproduce the issue : https://github.com/wawhal/test-apollo-android/

Edit

Workaround: Move the .graphql files and the schema.json to a subfolder like com/org/appname. The working example app is pushed to a branch called working in wawhal/test-apollo-android

Investigation

Most helpful comment

Thx will take a look today

All 13 comments

Try to put all graph files under some sub folders, not in root of /graphql folder. For example put them under /graphql/com/packagename/...

@sav007 that does not work. Same issue.

TBH not sure why you see this issue, just checked on the our tests, and it works fine.
So just to make sure:

  • you moved all your graphql files and schema under some folder structure (now models generated with package relative to /graphql folder)
  • you clean build

Hi i feel same isse. If need i can provide my project to test @sav007

I have the same issue with alpha4, my array type is an enum and it's a query not a mutation

query Play($id: String!, $context: String, $supported_actions: [PlayFlowActionEnum]!) {

Same issue with 1.0.1-SNAPSHOT

@worm69 that would be super helpful. If someone provides me a sample how to reproduce this issue, I will appreciate.

@sav007 my apologies. The solution that you mentioned seems to work:

Try to put all graphl files under some sub folders, not in root of /graphql folder. For example put them under /graphql/com/packagename/...

Any reason this placement in subfolders is enforced?
The docs say that placing the .graphql files inside main/graphql should work.

@sav007 thx i hope help find bug mobiletaiga-dev.zip

Thx will take a look today

Sorry for the delay just got some free time.
By quick looking into the code:
screen shot 2019-01-27 at 9 46 26 am

As I recommended try to put schema and graphql files under some subfolder:

screen shot 2019-01-27 at 9 48 54 am

@sav007 No Problem. Thx for help me on your free time 馃憣馃憦

Closing

Was this page helpful?
0 / 5 - 0 ratings