Closed darrikonn closed 5 years ago
So everything works until a hot reload occurs? And then only extended pages break? It almost 100% has to do with classloaders chaging and an instance is then seen as being of a different class. Classloader issue are a nightmare to troubleshoot.
The puzzing part is that it happens only for extended pages... No clue what makes them special.
Any chance you create a runnable example that I can poke with a debugger?
Yeah exactly! Everything that's extended breaks, i.e. extended pages and extended connections.
For the runnable example; running the following code from the relay tests breaks after hot reloading kicks in (https://github.com/leangen/graphql-spqr/blob/master/src/test/java/io/leangen/graphql/RelayTest.java)
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import graphql.relay.ConnectionCursor;
import graphql.relay.DefaultEdge;
import graphql.relay.Edge;
import graphql.relay.PageInfo;
import graphql.relay.Relay;
import io.leangen.graphql.annotations.GraphQLArgument;
import io.leangen.graphql.annotations.GraphQLId;
import io.leangen.graphql.annotations.GraphQLQuery;
import io.leangen.graphql.execution.relay.Connection;
import io.leangen.graphql.execution.relay.Page;
import io.leangen.graphql.execution.relay.generic.PageFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class TestQuery {
public static class Book {
private String title;
private String isbn;
@JsonCreator
Book(@JsonProperty("title") String title, @JsonProperty("id") String isbn) {
this.title = title;
this.isbn = isbn;
}
public String getTitle() {
return title;
}
@GraphQLQuery(name = "id")
public @GraphQLId(relayId = true) String getIsbn() {
return isbn;
}
}
public static class ExtendedEdge<T> extends DefaultEdge<T> {
private final COLOR color;
ExtendedEdge(T node, ConnectionCursor cursor, COLOR color) {
super(node, cursor);
this.color = color;
}
public COLOR getColor() {
return color;
}
public enum COLOR {
BLACK, WHITE
}
}
public static class ExtendedPage<N> implements Page<N> {
private final List<Edge<N>> edges;
private final PageInfo pageInfo;
private final long totalCount;
ExtendedPage(List<Edge<N>> edges, PageInfo pageInfo, long totalCount) {
this.edges = edges;
this.pageInfo = pageInfo;
this.totalCount = totalCount;
}
@Override
public List<Edge<N>> getEdges() {
return edges;
}
@Override
public PageInfo getPageInfo() {
return pageInfo;
}
public long getTotalCount() {
return totalCount;
}
}
public static class ExtendedConnection<E extends Edge> implements Connection<E> {
private final List<E> edges;
private final PageInfo pageInfo;
private final long totalCount;
ExtendedConnection(List<E> edges, PageInfo pageInfo, long count) {
this.edges = edges;
this.pageInfo = pageInfo;
this.totalCount = count;
}
@Override
public List<E> getEdges() {
return edges;
}
@Override
public PageInfo getPageInfo() {
return pageInfo;
}
public long getTotalCount() {
return totalCount;
}
}
@GraphQLQuery(name = "test1")
public ExtendedPage<Book> test1(@GraphQLArgument(name = "first") int first, @GraphQLArgument(name = "after") String after) {
List<Book> books = new ArrayList<>();
books.add(new Book("Tesseract", "x123"));
long count = 100L;
long offset = Long.parseLong(after);
return PageFactory.createOffsetBasedPage(books, count, offset, (edges, info) -> new ExtendedPage<>(edges, info, count));
}
@GraphQLQuery(name = "test2")
public ExtendedConnection<ExtendedEdge<Book>> test2(@GraphQLArgument(name = "first") int first, @GraphQLArgument(name = "after") String after) {
List<Book> books = new ArrayList<>();
books.add(new Book("Tesseract", "x123"));
long count = 100L;
long offset = Long.parseLong(after);
Iterator<ExtendedEdge.COLOR> colors = Arrays.asList(ExtendedEdge.COLOR.WHITE, ExtendedEdge.COLOR.BLACK).iterator();
return PageFactory.createOffsetBasedConnection(books, count, offset,
(node, cursor) -> new ExtendedEdge<>(node, cursor, colors.next()), (edges, info) -> new ExtendedConnection<>(edges, info, count));
}
}
And then I build the schema with
GraphQLSchema schema = new GraphQLSchemaGenerator()
.withResolverBuilders(
new AnnotatedResolverBuilder(),
new PublicResolverBuilder("gql"))
.withOperationsFromSingletons([new TestQuery()])
.withValueMapperFactory(new JacksonValueMapperFactory())
.generate();
GraphQL graphQL = schema.build();
// execute the input
String query = json.get("query").asText();
ExecutionInput executionInput = ExecutionInput.newExecutionInput().query(query).build();
ExecutionResult result = graphQL.execute(executionInput);
return ok(Json.toJson(result.toSpecification());
Any news on this?
My solution was to create my own relay page with the fields that I needed (same for edge/pageinfo if that were the case).
I extended the PageFactory
to use my custom Page instead of the extended/default one.
I'm gonna close this for now, since I'm fine with my solution. If anyone else encounters this problem, feel free to reopen 👍
Using the Java Play framework (sbt).
Keep getting the following error:
when extending
Page
orConnection
with Graphl-SPQR. This doesn't usually show up until after I've saved and hot reloading kicks in, so the first queries, that I make in the GraphiQL editor, are successful. This only happens after I save, that kicks in a hot reload (even if there are no changes). This does not happen if I use thePage
directly (without extending it).Has anyone encountered the same problem?
Code
I'm generating the schema with
and tried the example from RelayTests, both
public ExtendedConnection<ExtendedEdge<Book>> getExtended
andpublic ExtendedPage<Book> getExtended
Stacktrace