-
Notifications
You must be signed in to change notification settings - Fork 305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support more options to create target objects in @Argument
binding
#521
Comments
Have you tried registering a |
Thanks for pointing out the general direction. Currently, I have this skeleton:
I hope I've done the wiring right... Anyway, I'm struggling to figure out what the converter source type should be. I've tried both |
There is some detail missing from the description, so if you want us to take a closer look and give you specific advice, please provide a small sample. |
Hi. I've created a sample app that demonstrates the problem: https://github.com/david-kubecka/graphql-custom-converter/tree/main. I believe I just didn't get how the custom converter should be wired into GraphQlConfig and/or what should be the source type of the Thank you for looking into this! |
Thanks for the sample. This case requires use of a static factory method to create the target type, and that's not supported. Currently, we support using a single, public, constructor with arguments, or a default constructor and then binding via properties. The One option is to expand use of the Another option is to check for static factory methods, but there may be several of them and it could get tricky to select the right one with overloaded methods and/or nested input. Furthermore, such factory methods might not even be on the target type, like the case here where Whatever mechanism we choose could also be useful for selecting among multiple data constructors. |
@Argument
binding process@Argument
binding
@Argument
binding@Argument
binding
As for a workaround, if you have flexibility to change the target class, you could create a class with a data constructor that matches the input. That target class would take that as its input, and then convert internally. For example in this case: data class MoneyValue(val amount: Float, val currency: String)
class Transaction(val value: MoneyValue, val transactionType: TransactionType) {
val monetaryAmount: MonetaryAmount
init {
monetaryAmount = Money.of(value.amount, value.currency)
}
} This could work if the target class is specifically for GraphQL input, and not a domain entity class, |
That's what I would envision to be a good general solution. The concerns you mention (nested types or scalars conversion) are valid but IMO if one resorts to a custom conversion he might not expect that the generic conversion mechanism would plug in automagically. (OTOH it would certainly be good if it was possible to hook onto the generic mechanism explicitly! I.e. in my example I might want to define a custom converter for
Does this mean that the
I could use that but it suffers from the same issues I mentioned in my original post, i.e. I would need to employ this little bit cumbersome strategy whenever I need the Money type. Moreover, in my actual code I don't use
With your suggestion, I would somehow need to acquire Additionally, I don't think it would be a good idea to support static factory methods (for similar reasons you mentioned). Instead, I would rather like to be able to convert from a |
Thanks for the additional feedback. A So, while using a Originally, we did use Jackson for GraphQL argument binding, but moved away from it because it can interfere with custom scalar values, see #122. We now have One option is for us to provide a way for the application to suggest how to create a specific object, e.g. by pointing to a static factory method. We can do the rest of the work from there, matching and converting map values, creating nested objects, etc. Another option would be to allow use of Jackson, or another object mapper, for specific parts of the input map, but this would be a little contradictory with the changes in #122, and I'd like to understand the use case very well. You mentioned that you need to use Jackson, but I'm wondering if that's really necessary? |
After a team discussion, we've decided this. We'll continue to enhance If none of this works, we could provide a hook as a final fallback to convert from a We may also combine these concepts into one, dedicated contract that gives a range of options, from selecting a static factory method or a data constructor among several, to a function to take over the conversion of a The goal is to make it feasible to leave as much as possible to |
@Argument
binding@Argument
binding
@Argument
binding@Argument
binding
Thank you for the detailed explanation. It's much appreciated! Now I understand why you originally steered more toward the static factory methods support and it seems to make sense. One additional question: Theoretically, one could do whatever they want in the factory method, including using an object mapper. So perhaps natively supporting conversion from |
Good point, will keep that in mind. |
Another related question: Is |
I have reformulated that ^ to a separate issue #569. |
After reading the source code, I wonder whether a simple first step for this couldn't be to allow extending the list of argumentResolvers. It wouldn't probably solve my original problem but it would solve another situation I also encounter quite often when my input type class doesn't have a suitable constructor. Currently, I have this repeating pattern
That could easily be abstracted away to a custom resolver, i.e. based on a custom argument annotation. I can file a separate issue if this makes sense to you. |
Hmm, thinking about it more I wonder why spring-graphql itself doesn't use this approach. The |
Hi. I've read this thread and it still is not clear for me. for example, i have several entites based on one:
and i have a mutation mutation { for WebMVC and jackson i had described annotation-based contract witj @JsonTypeInfo and @JsonSubTypes. And it worked perfectly. But now i got error
because there is not used jackson. Is there correct way to map all of my classed? |
I would like to be able to customize how Spring for GraphQL instantiates objects from query/mutation arguments. Example schema:
I have the corresponding controller methods which follow the standard naming convention and whose arguments are classes
Parent1
andParent2
, respectively. These parent classes' structure is the same as the input types butChild
class has a different structure than the corresponding input type (e.g. inputprop1
is used as an argument to a function that populates targetprop3
). I would like to be able to define a custom deserializer of theChild
class from the internal argument submap.Currently, I'm achieving this manually, i.e. my controller method looks like this:
This works but must be repeated for each mutation/parent combination.
Is there a better way how to achieve my use case? I've initially also explored a way to define an input object directive but I couldn't figure out whether/how an input data transformer can be set there.
The text was updated successfully, but these errors were encountered: