-
Notifications
You must be signed in to change notification settings - Fork 115
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
Is there a way to avoid ClassCastException without using @type fields on a JSON object? #150
Comments
If you turn of the @type, then it is best to read the JSON into JsonReader using the API that returns a "Map of Maps" which will prevent any ClassCastExceptions. Here is an example in Groovy:
|
Is there a challenge or a reason not to create functionality to serialize into a typed object (not a map of maps) without storing type info in the JSON (if you are given the class information as a parameter of the method)? |
Yes, there is a challenge to using JSON to store/retrieve to a set of Java
classes without placing type information in the JSON. Simple example, I
have a field in JSON that has an object type next to it:
```
{
"field1": { "name": "John", "lastname": "DeRegnaucourt"}
"field2": true
}
```
Now the Java object you want to read it into looks like this (two examples)
Class A
{
Map field1;
Boolean field2;
}
Class B
{
Person field1;
Boolean field2;
}
Class C
{
Object field1;
Boolean field2;
}
In this example, which class should be instantiated to hold the result? It
is completely ambiguous. The JSON reader code has a Map when it finishes
reading the { "name": ...} portion of the JSON. Now the field it must
assign this too and it's enclosing class, how does it work? That { "name"
...} portion will work for any of these three classes. So the reader does
not know which one to instantiate.
This is why I said if you want to work without @types, then use Map of Map
structures and the Map reader version of json-io. "Hard" Data Transfer
Objects (DTOs) are a thing of the past in my humble opinion. You can write
rules that generically walk "Map of Map" graphs and validate their values,
transform their values, etc. Why bother building explicit Java classes
that look the same as Maps, with hard-coded fields and getter/setters on
them?
This spills into a more advanced technique where you can create "DTO"
classes that are derived (extend) LinkedHashMap. Think about these data
transfer type classes - why do you need to declare fields on them? Just
declare API on them - getters/setters and have those methods uses the Map's
put/get to store the values. These serialize out correctly for Jackson or
json-io. If you are interested in this technique, I will publish one of
those DTO classes that derives from LinkedHashMap here as an example.
…On Tue, Oct 27, 2020 at 8:51 AM bmbanker ***@***.***> wrote:
Is there a challenge or a reason not to create functionality to serialized
into a typed object without storing type info in the JSON (if you are given
the class information as a parameter of the method)?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#150 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABI76TXOHVTQ7ABHZI7MU63SM266NANCNFSM4S7M6HHQ>
.
|
I can see how this would be an issue. However, I'm trying to basically skip using a "DTO" entirely. I've built a front end that knows how to interact with unflattened objects, and that's why I'm using your library (because it can handle nested objects with circular dependencies.). In the scenario provided above, it looks like you are not giving a class parameter to your deserialization function. If you had the same given JSON string, but instead had the below class definitions:
A function And if instead the definition of class B looked like this:
You could either throw an exception (which is what I would recommend), or fill a plan Object with your best guess as to what the types of the children should be (which I definitely wouldn't recommend). |
This issue is very similar to issue #122 |
I think that is reasonable. We could add an api to provide a hint for the type on the root object and use that to build to build the structure. Whatever type you are typecasting to would be the one we use as your model object at the root level. Everything below that would be matched to field types from that object.
|
That is very similar to how Jackson works. This is worth having as a 2nd
toObjects() API, imho. Then we will make sure that type makes it in the
JsonObject.type field. Then, we can eliminate types at the root layer on
writer.
…On Thu, Nov 9, 2023 at 11:09 AM Ken Partlow ***@***.***> wrote:
I think that is reasonable. We could add an api to provide a hint for the
type on the root object and use that to build to build the structure.
Whatever type you are typecasting to would be the one we use as your model
object at the root level. Everything below that would be matched to field
types from that object.
public static <T> T toObjects(InputStream input, ReadOptions options,
Class<T> hint)
—
Reply to this email directly, view it on GitHub
<#150 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABI76TV2ZHGPCVENKHW6TTLYDT5Z3AVCNFSM4S7M6HH2U5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCOBQGQYTEMJYGQZQ>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
Root type was added to json-io a while back. That does eliminate the @type at the root level. And again, for all cases where it can be inferred, it is not emitted (that is the default option). Only when the type is ambiguous, is @type emitted. Also, you have the option to not include @type at all, in which case, you will get Map instances. Closing the issue as fixed (supported) now. |
If I attempt to deserialize JSON that was serialized with the default JsonWriter type settings, I can cast it to a typed object successfully. However, if I attempt to deserialize JSON that was serialized with JsonWriter.TYPE = false, I receive a ClassCastException.
Is there any way to avoid this without needing to rely on the
@type
parameters? The reason I'm asking is because the objects I use are quite complex, and there's a lot of@type
data being sent. Not serializing@type
parameters can help me save ~3kB per request on smaller objects in my system (~6kB per round-trip).Perhaps a solution would be new implementation of method
JsonReader.readObject(Class)
that would make a best attempt at deserialization without any@type
parameters? Using generics, theoretically it could recursively walk the JsonObject structure and attempt to match the value up with the values of declared Fields on the Class object given, and you could avoid infinite recursion by using the already inbuilt@ref
and@id
tags. These are just my first thoughts on a solution, maybe you have something more elegant in mind.Below is the deserialization code, and the full exception stack trace.
The text was updated successfully, but these errors were encountered: