Wildward does not work on Pojo
Closed this issue · 8 comments
When using jsonpath on objects having arrays or list, wildcard exception does not work. The following exception is thrown :
java.lang.UnsupportedOperationException: Not supported
at org.jsfr.json.path.PathOperator.resolve(PathOperator.java:48)
at org.jsfr.json.path.JsonPath.resolve(JsonPath.java:177)
package test;
import java.util.Arrays;
import java.util.List;
import org.jsfr.json.compiler.JsonPathCompiler;
import org.jsfr.json.path.JsonPath;
import org.jsfr.json.resolver.PoJoResolver;
import org.junit.jupiter.api.Test;
public class JsonSurferTest {
class B {
private boolean c = true;
}
class A {
private List<B> b = Arrays.asList(new B[] { new B(), new B()});
private B[] b2 = new B[] { new B(), new B()};
}
@Test
public void testList() {
A a = new A();
JsonPath compiledPath = JsonPathCompiler.compile("$.b[*].c");
compiledPath.resolve(a, new PoJoResolver());
}
@Test
public void testArray() {
A a = new A();
JsonPath compiledPath = JsonPathCompiler.compile("$.b2[*].c");
compiledPath.resolve(a, new PoJoResolver());
}
}
Sorry! As it is said, Resolver API does not support wildcard.
I think it would be nice to write something in the readme about this. It limit the usage of JSurfer for Pojo.
Do you plan to support whole features for Pojo or not ? How can I help ? Do you have something in mind on how Resolver API need to be modified ?
I think you'd better try the new feature "binary format". Please follow the example in unit test:
https://github.com/jsurfer/JsonSurfer/blob/master/jsurfer-all/src/test/java/org/jsfr/json/JacksonParserTest.java#L108
Just turn Pojo into binary and then surfer on it.
Resolver API can be considered as a helper utility and was not designed for complicated JsonPath. Moreover, It does not process json in "Surfing" style, i.e. streaming. So I don't think it's a good idea to spend too much effort on enhancing Resolver API to support full JsonPath feature.
Thanks so much for the advice. I will update readme and provide detailed example on surfing on POJO soon.
It works fine with simple classes (simple types, arrays, lists) but I have encountered an issue on Jackson protobuff schema generator with date field : FasterXML/jackson-dataformats-binary#140 . It could miss something in loop detection during object tree visit.
After making some test, I'm not sure using protobuf is the best way. It means converting the whole object to protobuff format and then converting the result to the final object. For instance the result of tatgeting an OffestDateTime is a double that you need to convert into OffsetDateTime. Regarding performance, it's too bad to convert object twice. It could just a tree walking without any conversion
Well, it depends on your use case. If you just need to deal with POJO, I think https://github.com/json-path/JsonPath would be better choice. JsonSurfer is good at streaming processing which means that you can use JsonPath against raw payload, e.g. String or InputStream without deserializing them into POJO
After some tries and tricks it works well with JsonPath. Thank you!
I'm not sure it's the place to write code for other frmawork, but I do not like issue where guys says that it works now but do not give the solution :)
package test.test_jsurfer;
import java.time.OffsetDateTime;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.TextNode;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
public final class JsonPathTest {
public static final Configuration JACKSON_JSON_NODE_CONFIGURATION;
static {
;
ObjectMapper om = new ObjectMapper();
om = om.enable(SerializationFeature.WRITE_DATES_WITH_ZONE_ID);
om = om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
om = om.registerModule(new JavaTimeModule());
JACKSON_JSON_NODE_CONFIGURATION = Configuration.defaultConfiguration().addOptions(Option.SUPPRESS_EXCEPTIONS)
.mappingProvider(new JacksonMappingProvider(om)).jsonProvider(new JacksonJsonNodeJsonProvider(om));
}
@Test
public void writeObject() {
DocumentContext context = JsonPath.using(JACKSON_JSON_NODE_CONFIGURATION).parse("{}");
context.put("$", "data", new A());
Object id = context.read("$.data.b2[*].d");
System.out.println("id:" + id);
id = context.read("$.data.b2[?(@.c==false)]");
System.out.println("id:" + id);
id = context.read("$.data.b2[*]");
System.out.println("id:" + id);
id = OffsetDateTime.parse(((TextNode) context.read("$.data.date")).asText());
System.out.println("id:" + id);
System.out.println("ctx:" + context.json());
}
}
It's OK