Skip to content

Conversation

dpolysiou
Copy link
Contributor

Extend support for JSON scalars, to include not only JSON objects, but also any other JSON value, like strings, numbers and arrays.

@phillip-kruger
Copy link
Member

Would it not be better to map the individual values ? So Array to Array, String to String etc ? @jmartisk ??

@dpolysiou dpolysiou force-pushed the 2284-json-scalar-jsonvalue branch from 6b91978 to 7bc36b2 Compare May 4, 2025 13:04
@dpolysiou
Copy link
Contributor Author

I uploaded a sample project with a few test cases, and I amended my commit to include separate mappings for the JsonValue subtypes.

There are a couple of points that are unclear to me:

  1. When used as an input, this scalar expects the json to be passed as a JSON-encoded string. I don't know if it would be possible to pass raw JSON instead.
  2. For the JsonNumber mapping, I used
populateScalar("jakarta.json.JsonNumber", JSON, String.class.getName());

which seems to work, but I don't know if it is correct.

populateScalar("jakarta.json.JsonObject", "JSON", Object.class.getName());
populateScalar("jakarta.json.JsonValue", JSON, Object.class.getName());
populateScalar("jakarta.json.JsonString", JSON, String.class.getName());
populateScalar("jakarta.json.JsonNumber", JSON, String.class.getName());
Copy link
Member

Choose a reason for hiding this comment

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

Should number not map to a java Number ? and Array to Array ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried

        populateScalar("jakarta.json.JsonNumber", JSON, Number.class.getName());
        populateScalar("jakarta.json.JsonArray", JSON, Object[].class.getName());

and got no errors (also, I saw no difference in the query response).

To be honest, I'm having a hard time tracking where this third argument is actually used.

I see it used in io.smallrye.graphql.execution.Classes.isNumberLikeType, but that method will return false for Number. Maybe we should use BigDecimal instead?

I also see it used for io.smallrye.graphql.execution.datafetcher.helper.AbstractHelper.shouldTransform, but that method will return true for any value other than jakarta.json.JsonNumber itself.

Copy link
Member

Choose a reason for hiding this comment

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

Lets wait for @jmartisk to comment

Copy link
Member

Choose a reason for hiding this comment

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

TBH I don't see much value in separately registering JsonString, JsonNumber, etc. How about simply supporting JsonValue and JsonObject? If one wanted to have a string field, they would simply use String, not JsonString IMO.

Copy link
Member

Choose a reason for hiding this comment

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

To be honest, I'm having a hard time tracking where this third argument is actually used.

Same here TBH, this was written a long time ago and not by me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TBH I don't see much value in separately registering JsonString, JsonNumber, etc. How about simply supporting JsonValue and JsonObject?

That's understandable. JsonValue pretty much covers everything, and keeping JsonObject would avoid any breaking changes. Should I remove the rest?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed most of the added registrations and kept only the addition of JsonValue.

Extend support for JSON scalars, to include not only JSON objects, but also any other JSON value, like strings, numbers and arrays.
@dpolysiou dpolysiou force-pushed the 2284-json-scalar-jsonvalue branch from 2319f37 to 1d46a8e Compare May 9, 2025 12:17
@phillip-kruger
Copy link
Member

@jmartisk Any reason the wildfly feature pack build fails ?

@jmartisk
Copy link
Member

Sorry for the delay, looking into it again today.

@jmartisk
Copy link
Member

I can get JsonValue working as an output type, but were you able to make it work as an input to an operation? I think that may be quite tricky. And anyway, I don't see much value in attempting it. If one wants to accept a (scalar) value instead of a full json object, just make the operation accept a String or Integer.

@dpolysiou
Copy link
Contributor Author

dpolysiou commented May 14, 2025

JsonValue works as an input type, in the same way that JsonObject does, i.e. it is parsed as a JSON-encoded string.

E.g. if you want to pass an array of strings, you can use

input : "[\"foo\",\"bar\"]"

rather than

input: [ "foo", "bar" ]

That's a little inconvenient, and it's not as shown in the graphql-java-extended-scalars readme.

A simple workaround I tried is mapping the java.lang.Object class to a JSON scalar. That works, although the java method then takes an Object instead of a JsonValue.

@jmartisk
Copy link
Member

Ah, I was trying to use a value like "x" and [], that doesn't work, even though these are valid json values (and these do work as output types, when the query for example returns JsonValue.EMPTY_JSON_ARRAY). When you use an object for input, it indeed works.

Generally, it seems that passing a JSON array doesn't work as input (but this can be worked around by making the operation accept List<JsonValue>

I'm not sure what exactly we would have to do to accept these values as JsonValue inputs (it would probably be a big mess), but I guess it's not that important.

@dpolysiou
Copy link
Contributor Author

Perhaps we could add a special transformation that constructs a jakarta.json.JsonValue out of java.lang.Object, using instanceOf checks and recursion?

@dpolysiou
Copy link
Contributor Author

Ah, I was trying to use a value like "x" and [], that doesn't work, even though these are valid json values (and these do work as output types, when the query for example returns JsonValue.EMPTY_JSON_ARRAY). When you use an object for input, it indeed works.

Generally, it seems that passing a JSON array doesn't work as input (but this can be worked around by making the operation accept List<JsonValue>

I'm not sure I understand the distinction you draw between the handling of JSON objects and arrays. Unless I'm mistaken, neither really "work" as inputs.

For objects, I would expect to be able to pass:

input: { key : "value" }

which doesn't work. The following works, but it isn't quite right:

input: "{"\key\" : "\value\"}"

@jmartisk
Copy link
Member

I'm not sure I understand the distinction you draw between the handling of JSON objects and arrays. Unless I'm mistaken, neither really "work" as inputs.

A json array is a valid JsonValue, so I would expect to be able to pass x: [{a:3}] to a query that is declared with a JsonValue x parameter, and that doesn't work right now. But I don't think this is something we can solve in a straightforward way (unless you have some insight that I don't)

Perhaps we could add a special transformation that constructs a jakarta.json.JsonValue out of java.lang.Object, using instanceOf checks and recursion?

Let's not get into that hole please :D

@t1
Copy link
Collaborator

t1 commented May 15, 2025

input: { key : "value" }

I suppose that you mean: input: { "key": "value" }... sorry for nitpicking 🤓

Copy link
Member

@jmartisk jmartisk left a comment

Choose a reason for hiding this comment

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

Let's merge this, it's definitely a good start, even though it has a few shortcomings. Thanks!

@jmartisk jmartisk merged commit 7715de6 into smallrye:main May 15, 2025
4 of 5 checks passed
@github-actions github-actions bot added this to the 2.12.3 milestone May 15, 2025
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.

4 participants