-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
JacksonJsonNodeJsonProvider disallows POJOs #364
Comments
Hi @ben-manes I would like to know what you actually expect as replacement for the exception. |
I'd have to retest, but at least previously the The API doesn't convey these restrictions and arbitrarily fail based on the providers, which is frustrating. This breaks many API design practices, e.g. principle of least astonishment. I'd be fine with a configuration on In your case it sounded like you didn't want to have the JsonNode copied on return. If a value is being written (potentially overwriting) then I don't think this is problematic as the subtree could be replaced. How would switching from throwing an exception to the previous behavior of tree-ifying the object break you? |
How would switching from throwing an exception to the previous behavior of tree-ifying the object break you? |
What about converting your POJO into a JsonNode just before calling this method? |
What about replacing the exception with this code:
|
Yes, I think we're in agreement. I use Jackson POJOs via jsonschema2pojo, so they are mapped. I still don't see why the In my case that would be significant boilerplate, as it is used in hundreds of places (and growing). I would instead use a custom provider if need be. |
Yes, that was my question as well. I think it would work beautifully. |
Sorry for breaking your use case. It was not my intention. I will suggest this change! |
Thanks! :) |
Could you explain what you mean with the UUID? I have no idea how to recognize a UUID within a Json document. |
Since I use json schema, the type information is provided there. Each of my entities include a section on the schemas that they implement. Then I can inspect the schema to know what data types are present (simple like Strings or complex like an Address). Based on this, hooks are attached to definitions or schemas. When an entity is POST'ed, the schemas are used to discover all hooks that must be called, constructs a DAG, executes them, and persists. Because a hook only can be called when the entity is of that type, it knows that it conforms to its schema and a field must be a UUID. So it can deserialize / serialize in a more ad hoc fashion since the preceding validation gave it confidence. In json schema a UUID would be represented as, {
"type":"object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
}
}
} You can see how that is translated into a POJO in the code generator. |
I have some difficulties to write a test case for your use case. Could you provide a test case? |
You might have forgotten to configure JsonPath, since that is normally done in a global location. Here is a test that prints out the json in public final class JsonPathTest {
@Test
public void writeObject() {
ObjectMapper mapper = new ObjectMapper();
Configuration.setDefaults(new Defaults() {
@Override public Set<Option> options() {
return Collections.singleton(Option.SUPPRESS_EXCEPTIONS);
}
@Override public JsonProvider jsonProvider() {
return new JacksonJsonNodeJsonProvider(mapper);
}
@Override public MappingProvider mappingProvider() {
return new JacksonMappingProvider(mapper);
}
});
DocumentContext context = JsonPath.parse("{}");
context.put("$", "data", new Data("[email protected]"));
System.out.println(context.jsonString());
}
public static final class Data {
@JsonProperty("email")
String email;
Data(String email) {
this.email = email;
}
}
} 2.2.0
2.3.0
|
Hi @ben-manes ;-) |
Thanks a lot. I will integrate your nice test case and provide you asap a branch. |
It looks like I can't reproduce my UUID / String error with the regular Jackson provider. It must have been bugs due to using DocumentContext context = JsonPath.parse("{}");
context.put("$", "uuid", UUID.randomUUID());
context.put("$", "id", UUID.randomUUID().toString());
System.out.println(context.jsonString());
Object uuid = context.read("$.uuid");
System.out.println("uuid: " + uuid.getClass() + " " + uuid);
Object id = context.read("$.id");
System.out.println("id: " + id.getClass() + " " + id);
Object uuidToString = context.read("$.uuid", String.class);
System.out.println("uuidToString: " + uuidToString.getClass());
Object idToUUID = context.read("$.id", UUID.class);
System.out.println("idToUUID: " + idToUUID.getClass());
For now I'm fine since I downgraded back to 2.2.0, so I'm in no rush. |
Oh, here's the test case that fails for me. The nested object isn't serialized to a tree so that a nested path can be evaluated with later. This test passes with the JsonNode provider, but fails with the Jackson object provider by returning null. It isn't clear if this is a bug or not, but is the reason I switched to @Test
public void writeObject() {
...
DocumentContext context = JsonPath.parse("{}");
context.put("$", "data", new Data(UUID.randomUUID()));
System.out.println(context.jsonString());
Object id = context.read("$.data.id");
System.out.println("id: " + id.getClass() + " " + id);
}
public static final class Data {
@JsonProperty("id")
UUID id;
@JsonCreator
Data(@JsonProperty("id") UUID id) {
this.id = id;
}
} JacksonJsonNodeJsonProvider
JacksonJsonProvider
|
Could you provide the full stack trace? |
At the moment the change cause an empty json node. Do I have to register a dedicated serializer? |
No dedicated serializer should be required. You might try with the previous version to better compare if the changes don't line up. The NPE was due to a test failure when printing because the value is null at the path. Just meant to show that limitation. |
In 2.2.0 the provider allowed Jackson POJOs to be used as values when setting a property. This is an useful feature that I very frequently. This is also a breaking change that was not documented.
In my case the entire application is built around json schema and metadata. The schemas have triggers associated to them so that when an entity written it is inspected, a processing pipeline constructed, and operated upon. JsonPath is used at each of these stages to read and write to the entity before it is finally stored in the database, etc. The JsonNode provider is used to force all writes to normalize back into a consistent format. At least previously the
JacksonJsonProvider
would retain the type of the written value that could cause surprises on the next read (e.g. insert a UUID, cast exception if reading back as a String).As of 2.3.0, using an unknown object results in an exception. It would be helpful if this restriction was reverted.
The text was updated successfully, but these errors were encountered: