Skip to content

Commit 1f84b1c

Browse files
author
wesleyjellis
authored
Merge pull request #28 from Shopify/add_optional_null_to_input
Allow setting optional fields on input objects to explicit null
2 parents 119255a + 3960bdd commit 1f84b1c

File tree

8 files changed

+196
-14
lines changed

8 files changed

+196
-14
lines changed

Rakefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ task :generate do
2525
deserialize_expr: ->(expr) { "LocalDateTime.parse(jsonAsString(#{expr}, key))" },
2626
imports: ['java.time.LocalDateTime'],
2727
)
28+
],
29+
custom_annotations: [
30+
GraphQLJavaGen::Annotation.new(
31+
'Nullable',
32+
imports: ['com.shopify.graphql.support.Nullable']
33+
) { |field| !field.type.non_null? },
2834
]
2935
).save('support/src/test/java/com/shopify/graphql/support/Generated.java')
3036

codegen/lib/graphql_java_gen.rb

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,10 +253,17 @@ def java_implements(type)
253253
"implements #{interfaces.to_a.join(', ')} "
254254
end
255255

256-
def java_annotations(field)
257-
@annotations.map do |annotation|
256+
def java_annotations(field, in_argument: false)
257+
annotations = @annotations.map do |annotation|
258258
"@#{annotation.name}" if annotation.annotate?(field)
259-
end.compact.join("\n")
259+
end.compact
260+
return "" unless annotations.any?
261+
262+
if in_argument
263+
annotations.join(" ") + " "
264+
else
265+
annotations.join("\n")
266+
end
260267
end
261268

262269
def type_names_set

codegen/lib/graphql_java_gen/templates/APISchema.java.erb

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ public class <%= schema_name %> {
237237

238238
<% fields.each do |field| %>
239239
<%= java_doc(field) %>
240-
<%= java_annotations(field) -%>
240+
<%= java_annotations(field) %>
241241
public <%= java_output_type(field.type) %> get<%= field.classify_name %>() {
242242
return (<%= java_output_type(field.type) %>) get("<%= field.name %>");
243243
}
@@ -265,6 +265,7 @@ public class <%= schema_name %> {
265265
<% end %>
266266
<% type.optional_input_fields.each do |field| %>
267267
private <%= java_input_type(field.type) %> <%= escape_reserved_word(field.camelize_name) %>;
268+
private boolean <%= field.camelize_name %>Seen = false;
268269
<% end %>
269270

270271
<% unless type.required_input_fields.empty? %>
@@ -276,22 +277,25 @@ public class <%= schema_name %> {
276277
<% end %>
277278

278279
<% type.required_input_fields.each do |field| %>
280+
<%= java_annotations(field) %>
279281
public <%= java_input_type(field.type) %> get<%= field.classify_name %>() {
280282
return <%= escape_reserved_word(field.camelize_name) %>;
281283
}
282284

283-
public <%= type.name %> set<%= field.classify_name %>(<%= java_input_type(field.type) %> <%= escape_reserved_word(field.camelize_name) %>) {
285+
public <%= type.name %> set<%= field.classify_name %>(<%= java_annotations(field, in_argument: true) %><%= java_input_type(field.type) %> <%= escape_reserved_word(field.camelize_name) %>) {
284286
this.<%= escape_reserved_word(field.camelize_name) %> = <%= escape_reserved_word(field.camelize_name) %>;
285287
return this;
286288
}
287289
<% end %>
288290
<% type.optional_input_fields.each do |field| %>
291+
<%= java_annotations(field) %>
289292
public <%= java_input_type(field.type) %> get<%= field.classify_name %>() {
290293
return <%= escape_reserved_word(field.camelize_name) %>;
291294
}
292295

293-
public <%= type.name %> set<%= field.classify_name %>(<%= java_input_type(field.type) %> <%= escape_reserved_word(field.camelize_name) %>) {
296+
public <%= type.name %> set<%= field.classify_name %>(<%= java_annotations(field, in_argument: true) %><%= java_input_type(field.type) %> <%= escape_reserved_word(field.camelize_name) %>) {
294297
this.<%= escape_reserved_word(field.camelize_name) %> = <%= escape_reserved_word(field.camelize_name) %>;
298+
this.<%= field.camelize_name %>Seen = true;
295299
return this;
296300
}
297301
<% end %>
@@ -306,11 +310,15 @@ public class <%= schema_name %> {
306310
<%= generate_build_input_code(escape_reserved_word(field.camelize_name), field.type) %>
307311
<% end %>
308312
<% type.optional_input_fields.each do |field| %>
309-
if (<%= escape_reserved_word(field.camelize_name) %> != null) {
313+
if (this.<%= field.camelize_name %>Seen) {
310314
_queryBuilder.append(separator);
311315
separator = ",";
312316
_queryBuilder.append("<%= field.name %>:");
313-
<%= generate_build_input_code(escape_reserved_word(field.camelize_name), field.type) %>
317+
if (<%= escape_reserved_word(field.camelize_name) %> != null) {
318+
<%= generate_build_input_code(escape_reserved_word(field.camelize_name), field.type) %>
319+
} else {
320+
_queryBuilder.append("null");
321+
}
314322
}
315323
<% end %>
316324
_queryBuilder.append('}');

codegen/test/support/schema.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ module Schema
9191
argument :value, !types.Int
9292
argument :ttl, TimeType
9393
argument :negate, types.Boolean, default_value: false
94+
argument :api_client, types.String
9495
end
9596

9697
MutationType = GraphQL::ObjectType.define do
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (C) 2013 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.shopify.graphql.support;
17+
18+
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
19+
import static java.lang.annotation.ElementType.FIELD;
20+
import static java.lang.annotation.ElementType.METHOD;
21+
import static java.lang.annotation.ElementType.PACKAGE;
22+
import static java.lang.annotation.ElementType.PARAMETER;
23+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
24+
25+
import java.lang.annotation.Documented;
26+
import java.lang.annotation.Retention;
27+
import java.lang.annotation.Target;
28+
29+
/**
30+
* Denotes that a parameter, field or method return value can be null.
31+
* <p>
32+
* When decorating a method call parameter, this denotes that the parameter can
33+
* legitimately be null and the method will gracefully deal with it. Typically
34+
* used on optional parameters.
35+
* <p>
36+
* When decorating a method, this denotes the method might legitimately return
37+
* null.
38+
* <p>
39+
* This is a marker annotation and it has no specific attributes.
40+
*/
41+
@Documented
42+
@Retention(RUNTIME)
43+
@Target({METHOD, PARAMETER, FIELD, ANNOTATION_TYPE, PACKAGE})
44+
public @interface Nullable {
45+
}
46+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.shopify.graphql.support;
2+
3+
import org.junit.Test;
4+
5+
import java.lang.annotation.Annotation;
6+
import java.lang.reflect.Method;
7+
8+
import static junit.framework.Assert.assertEquals;
9+
import static org.junit.Assert.assertTrue;
10+
11+
import com.shopify.graphql.support.Generated;
12+
13+
public class AnnotationTest {
14+
@Test
15+
public void testAppliesAnnotation() throws Exception {
16+
Class<Generated> obj = Generated.class;
17+
boolean foundNullable = false;
18+
for (Class klass: obj.getDeclaredClasses()) {
19+
for (Method method : klass.getDeclaredMethods()) {
20+
if (method.isAnnotationPresent(Nullable.class)) {
21+
foundNullable = true;
22+
break;
23+
}
24+
}
25+
}
26+
assertTrue("Should have found a class with @Nullable annotation in Generated.java", foundNullable);
27+
}
28+
}

0 commit comments

Comments
 (0)