Skip to content

Provide more information to TypeResolver to allow richer resolution logic#343

Closed
kaqqao wants to merge 5 commits into
graphql-java:masterfrom
kaqqao:#122TypeResolutionEnvironment
Closed

Provide more information to TypeResolver to allow richer resolution logic#343
kaqqao wants to merge 5 commits into
graphql-java:masterfrom
kaqqao:#122TypeResolutionEnvironment

Conversation

@kaqqao

@kaqqao kaqqao commented Mar 16, 2017

Copy link
Copy Markdown
Contributor

Closes #122

Gives TypeResolver access to most of the info available in DataFetchingEnvironment, to allow for complex type resolution logic.

I've updated the issue description to explain the rationale behind this PR and the investigation I've so far done on the benefits it would have on the wider ecosystem around this library.

The change is 100% backwards compatible due to the provided default implementation of the newly introduced GraphQLObjectType getType(TypeResolutionEnvironment env) method in TypeResolver. This obviously requires Java 8, but this should no longer be a problem as it seems the upgrade has been green-lit in #338

@bbakerman bbakerman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this breaks SPI compatibility anyway there is no need to call for Java 1.8 support

In order to unblock this change, decouple it from the 1.8 support. I think the changes are generally good but I would not require 1.8 support to get them in

public interface TypeResolver {


default GraphQLObjectType getType(TypeResolutionEnvironment env) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the fact is that because you changed the ExecutionStrategy above and hence this a breaking SPI change for people who extend execution strategy.

Hence the carefully crafted "default" here is backwards compatible but the whole PR is not

So I would remove the 1.8 requirement (which may come but you dont need to be dependent on it)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, and removed

return result;
}

protected GraphQLObjectType resolveType(GraphQLUnionType graphQLUnionType, Object value) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again technically a breaking changes for people who extend ExecutionEnvironment

But maybe we need to.

That or we move the "parameter objects" with builders so we can "optional" add new parameters more easily without breaking SPI.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I got your 2nd suggestion... But anything that allows easier non-breaking modifications sounds like a good idea.

@bbakerman bbakerman Mar 24, 2017

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameters pattern is simply taking N current parameters and moving them into an object with a builder so it takes only 1 parameters

eg:

resolveField(Field field, GraphQLInterfaceType graphQLInterfaceType,
                                         Object value, Map<String, Object> argumentValues, GraphQLSchema schema)

becomes

resolveField(ResolveFieldParameters parameters)

this is useful because you are able to "add" new parameters to the builder while preserving backwards compatibility. This is more useful for "API / SPI" of course

The following is for "constructors" from Effective Java

http://www.informit.com/articles/article.aspx?p=1216151&seqNum=2

But it would be for methods as well

Note this is not really your problem in terms of this PR. But because you needed to add yet more parameters you exasperated the existing problem.

A parameters object would also be a breaking change, although we might be able to do it via overloading and deprecation

@kaqqao kaqqao Mar 30, 2017

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reimplemented the changes to the ExecutionStrategy in the way you suggested and made overloads and deprecations for backward-compatibility. Please see when you get a chance what you think of this version.

Notes:

  • I've only introduced the ...Parameters classes where I needed them for this change, not everywhere where they should arguably go. Tell me If you want me refactor more places.
  • I made the ...Parameters constructors private to avoid implementors relying on them and ending up in this same situation. I wanted them package private so that they can be used internally, but BatchedExecutionStrategy is in a different package so there wasn't much point.
  • I added Javadoc to the @Deprecated methods only to link to the new options, but since this is not a full Javadoc, a lot of warnings are generated during the build. Would you rather have the incomplete docs removed or maybe provide the text you'd like in the Javadoc, or would you like me to add my own?

Now, the question comes back to the TypeResolver: do I re-introduce the Java 8 dependent default for backwards compatibility, or do I implement it in a different way?
One idea I have is to introduce a new interface, say TypeDecider, that would provide the new functionality: GraphQLObjectType getType(TypeResolutionEnvironment env), and then change the builders that accept TypeResolvers in a fashion similar to this:

//wrap the given TypeResolver in a simple TypeDecider that just delegates to it
public Builder typeResolver(TypeResolver typeResolver) {
    this.typeDecider = new SimpleTypeDecider(typeResolver);
    return this;
 }

//add new method that accepts TypeDecider directly
public Builder typeDecider(TypeDecider typeDecider) {
    this.typeDecider = typeDecider;
    return this;
 }

With both approaches, backwards-compatibility would be, I think, complete.

UPDATE: I've already implemented the TypeDecider approach, so if you like that option I can push it for review.

@kaqqao

kaqqao commented Mar 23, 2017

Copy link
Copy Markdown
Contributor Author

Yup, I somehow forgot the ExecutionStrategy is a part of SPI. I removed the need for Java 8 as it indeed makes no sense.
Can you maybe help me out a bit more on how you'd tackle the changes to ExecutionStrategy? Should I leave them as they are or would you like a different approach? Perhaps breaking SPI is needed now, but can be done in a more future-proof way...

@kaqqao

kaqqao commented Mar 30, 2017

Copy link
Copy Markdown
Contributor Author

Bah, the useful part of the conversation is now getting buried under the hidden "outdated" reviews. But I guess you'll see it anyway.
I reimplemented the changes to the ExecutionStrategy to be backwards compatible and am now seeking opinion on how to tackle the changes to TypeResolver.

@kaqqao kaqqao closed this Apr 9, 2017
@kaqqao kaqqao deleted the #122TypeResolutionEnvironment branch April 9, 2017 23:05
@kaqqao kaqqao restored the #122TypeResolutionEnvironment branch April 10, 2017 00:01
@kaqqao kaqqao deleted the #122TypeResolutionEnvironment branch April 10, 2017 00:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants