Skip to content

Commit e44c7d8

Browse files
authored
Merge pull request #375 from jimkyndemeyer/empty-fields-in-introspection-response
Fixed NPE in introspection request for empty fields (#349)
2 parents 5105bb3 + 7d98bc9 commit e44c7d8

File tree

8 files changed

+241
-178
lines changed

8 files changed

+241
-178
lines changed

resources/messages/GraphQLMessages.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,6 @@ graphql.introspection.errors=Introspection query returned errors: {0}
2020

2121
# Progress
2222
graphql.progress.executing.introspection.query=Executing GraphQL introspection query
23+
24+
# Editor
25+
graphql.line.marker.generate.schema.file=Generate GraphQL SDL schema file

src/main/com/intellij/lang/jsgraphql/ide/editor/GraphQLIntrospectionJsonToSDLLineMarkerProvider.java

Lines changed: 51 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,18 @@
1414
import com.intellij.json.psi.JsonArray;
1515
import com.intellij.json.psi.JsonObject;
1616
import com.intellij.json.psi.JsonProperty;
17+
import com.intellij.lang.jsgraphql.GraphQLBundle;
1718
import com.intellij.lang.jsgraphql.GraphQLSettings;
19+
import com.intellij.lang.jsgraphql.ide.notifications.GraphQLNotificationUtil;
1820
import com.intellij.notification.Notification;
19-
import com.intellij.notification.NotificationAction;
2021
import com.intellij.notification.NotificationType;
2122
import com.intellij.notification.Notifications;
22-
import com.intellij.openapi.actionSystem.AnActionEvent;
23-
import com.intellij.openapi.application.ApplicationManager;
2423
import com.intellij.openapi.editor.markup.GutterIconRenderer;
2524
import com.intellij.openapi.project.Project;
2625
import com.intellij.openapi.util.Ref;
2726
import com.intellij.openapi.vfs.VirtualFile;
2827
import com.intellij.psi.PsiElement;
2928
import com.intellij.psi.util.PsiTreeUtil;
30-
import graphql.GraphQLException;
3129
import org.jetbrains.annotations.NotNull;
3230
import org.jetbrains.annotations.Nullable;
3331

@@ -43,58 +41,59 @@ public LineMarkerInfo<?> getLineMarkerInfo(@NotNull PsiElement element) {
4341
// skip in-memory JSON files such as the query result viewer
4442
return null;
4543
}
46-
if (element instanceof JsonProperty) {
47-
final Project project = element.getProject();
48-
final JsonProperty parentProperty = PsiTreeUtil.getParentOfType(element, JsonProperty.class);
49-
if (parentProperty == null || "data".equals(parentProperty.getName())) {
50-
// top level property or inside data property
51-
final JsonProperty jsonProperty = (JsonProperty) element;
52-
final String propertyName = jsonProperty.getName();
53-
if ("__schema".equals(propertyName) && jsonProperty.getValue() instanceof JsonObject) {
54-
for (JsonProperty property : ((JsonObject) jsonProperty.getValue()).getPropertyList()) {
55-
if ("types".equals(property.getName()) && property.getValue() instanceof JsonArray) {
56-
// likely a GraphQL schema with a { __schema: { types: [] } }
57-
final GraphQLIntrospectionService graphQLIntrospectionService = GraphQLIntrospectionService.getInstance(project);
58-
final Ref<Runnable> generateAction = Ref.create();
59-
generateAction.set(() -> {
60-
try {
61-
final String introspectionJson = element.getContainingFile().getText();
62-
final String schemaAsSDL = graphQLIntrospectionService.printIntrospectionJsonAsGraphQL(introspectionJson);
44+
if (!(element instanceof JsonProperty)) {
45+
return null;
46+
}
47+
final Project project = element.getProject();
48+
final JsonProperty parentProperty = PsiTreeUtil.getParentOfType(element, JsonProperty.class);
49+
if (parentProperty != null && !"data".equals(parentProperty.getName())) {
50+
return null;
51+
}
6352

64-
final VirtualFile jsonFile = element.getContainingFile().getVirtualFile();
65-
final String outputFileName = jsonFile.getName() + ".graphql";
53+
// top level property or inside data property
54+
final JsonProperty jsonProperty = (JsonProperty) element;
55+
final String propertyName = jsonProperty.getName();
56+
if (!"__schema".equals(propertyName) || !(jsonProperty.getValue() instanceof JsonObject)) {
57+
return null;
58+
}
59+
60+
for (JsonProperty property : ((JsonObject) jsonProperty.getValue()).getPropertyList()) {
61+
if ("types".equals(property.getName()) && property.getValue() instanceof JsonArray) {
62+
// likely a GraphQL schema with a { __schema: { types: [] } }
63+
final GraphQLIntrospectionService graphQLIntrospectionService = GraphQLIntrospectionService.getInstance(project);
64+
final Ref<Runnable> generateAction = Ref.create();
65+
generateAction.set(() -> {
66+
try {
67+
final String introspectionJson = element.getContainingFile().getText();
68+
final String schemaAsSDL = graphQLIntrospectionService.printIntrospectionJsonAsGraphQL(introspectionJson);
6669

67-
graphQLIntrospectionService.createOrUpdateIntrospectionOutputFile(schemaAsSDL, GraphQLIntrospectionService.IntrospectionOutputFormat.SDL, jsonFile, outputFileName);
70+
final VirtualFile jsonFile = element.getContainingFile().getVirtualFile();
71+
final String outputFileName = jsonFile.getName() + ".graphql";
6872

69-
} catch (Exception e) {
70-
Notification notification = new Notification("GraphQL", "Unable to create GraphQL SDL", e.getMessage(), NotificationType.ERROR);
71-
if (e instanceof GraphQLException) {
72-
final String content = "A valid schema could not be built using the introspection result. The endpoint may not follow the GraphQL Specification. The error was:\n\"" + e.getMessage() + "\".";
73-
notification.setContent(content);
74-
if (GraphQLSettings.getSettings(project).isEnableIntrospectionDefaultValues()) {
75-
// suggest retrying without the default values as they're a common cause of spec compliance issues
76-
final NotificationAction retryWithoutDefaultValues = new NotificationAction("Retry (skip default values from now on)") {
77-
@Override
78-
public void actionPerformed(@NotNull AnActionEvent e, @NotNull Notification notification) {
79-
GraphQLSettings.getSettings(project).setEnableIntrospectionDefaultValues(false);
80-
ApplicationManager.getApplication().saveSettings();
81-
notification.expire();
82-
generateAction.get().run();
83-
}
84-
};
85-
notification.addAction(retryWithoutDefaultValues);
86-
}
87-
}
88-
graphQLIntrospectionService.addIntrospectionStackTraceAction(notification, e);
89-
Notifications.Bus.notify(notification.setImportant(true));
90-
}
91-
});
92-
return new LineMarkerInfo<>(jsonProperty, jsonProperty.getTextRange(), AllIcons.RunConfigurations.TestState.Run, Pass.UPDATE_ALL, o -> "Generate GraphQL SDL schema file", (evt, elt) -> {
93-
generateAction.get().run();
94-
}, GutterIconRenderer.Alignment.CENTER);
95-
}
73+
graphQLIntrospectionService.createOrUpdateIntrospectionOutputFile(schemaAsSDL, GraphQLIntrospectionService.IntrospectionOutputFormat.SDL, jsonFile, outputFileName);
74+
} catch (Exception e) {
75+
Notification notification = new Notification(
76+
GraphQLNotificationUtil.NOTIFICATION_GROUP_ID,
77+
GraphQLBundle.message("graphql.notification.introspection.error.title"),
78+
GraphQLNotificationUtil.formatExceptionMessage(e),
79+
NotificationType.ERROR
80+
);
81+
82+
GraphQLNotificationUtil.addRetryFailedSchemaIntrospectionAction(notification, GraphQLSettings.getSettings(project), e, generateAction.get());
83+
graphQLIntrospectionService.addIntrospectionStackTraceAction(notification, e);
84+
Notifications.Bus.notify(notification.setImportant(true));
9685
}
97-
}
86+
});
87+
88+
return new LineMarkerInfo<>(
89+
jsonProperty,
90+
jsonProperty.getTextRange(),
91+
AllIcons.RunConfigurations.TestState.Run,
92+
Pass.UPDATE_ALL,
93+
o -> GraphQLBundle.message("graphql.line.marker.generate.schema.file"),
94+
(evt, elt) -> generateAction.get().run(),
95+
GutterIconRenderer.Alignment.CENTER
96+
);
9897
}
9998
}
10099
return null;

0 commit comments

Comments
 (0)