Skip to content
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

Issue setting values from / to JSON Objects? #432

Open
michelbetancourt opened this issue Jan 25, 2018 · 6 comments
Open

Issue setting values from / to JSON Objects? #432

michelbetancourt opened this issue Jan 25, 2018 · 6 comments

Comments

@michelbetancourt
Copy link

michelbetancourt commented Jan 25, 2018

Hello, it seems that this implementation of JsonPath works pretty well when setting the first level of keys of an object (from existing to new instance).. eg

if we set values this way (with the specific options set in "jsonConfig" below):

where data is defined as a Map<String,Object> "json object"
Configuration jsonConfig = Configuration.builder()
           .options(DEFAULT_PATH_LEAF_TO_NULL, SUPPRESS_EXCEPTIONS)
           .build();
Map<String, Object> newObject = new LinkedHashMap<>();
DocumentContext reader = JsonPath.parse(data, jsonConfig);
DocumentContext writer = JsonPath.parse(newObject, jsonConfig);

JsonPath fromPath = ..
JsonPath toPath = ..
value = reader.read(fromPath);           
writer.set(toPath, value);

then this works for all first level keys.. eg

$.key1 => $.key
$.car => $.plane
$.house => $.boat
.. and so on

The above, causes newObject to be filled in with the desired new keys on the right using the data that had been previously set from the source "data" set.

But if I'm trying to convert to nested paths such as these, it does not work and the newObject map above is not filled in:

$.key1 => $.nested.key
$.car => $.nested.plane
$.house => $.nested.boat
.. and so on

Is there a better way of doing that that I am overlooking? Or can this be a bug?

@jlolling
Copy link
Contributor

jlolling commented Jan 25, 2018

It should work. Could you please provide a test case to illustrate this problem?
I am not sure what do you mean with "nested".

@michelbetancourt
Copy link
Author

michelbetancourt commented Jan 25, 2018

Regardless of version (2.2.0 or 2.3.0) this is the result I get with the following test:

@Test
    public void testPathSetting() {
        Map<String, Object> data = Maps.newLinkedHashMap();
        data.put("key1", LocalDate.now());
        data.put("key3", "hello");

        Configuration jsonConfig = Configuration.builder()
                .options(Option.DEFAULT_PATH_LEAF_TO_NULL, Option.SUPPRESS_EXCEPTIONS)
                .build();
     Map<String, Object> newObject = new LinkedHashMap<>();
     DocumentContext reader = JsonPath.parse(data, jsonConfig);
     DocumentContext writer = JsonPath.parse(newObject, jsonConfig);

     Object value;
     Map<JsonPath, JsonPath> conversionPaths = new LinkedHashMap<>();
     conversionPaths.put(JsonPath.compile("$.key1"), JsonPath.compile("$.key"));
     conversionPaths.put(JsonPath.compile("$.key2"), JsonPath.compile("$.ok"));
     conversionPaths.put(JsonPath.compile("$.key3"), JsonPath.compile("$.nested.key3"));
     for(Map.Entry<JsonPath, JsonPath> path : conversionPaths.entrySet()) {
         JsonPath fromPath = path.getKey();
         JsonPath toPath = path.getValue();
         value = reader.read(fromPath);           
         writer.set(toPath, value);    
     }
     
     assertThat(newObject, hasEntry("key", data.get("key1")));
     assertThat(newObject, hasEntry("ok", data.get("key2")));
     assertThat(newObject, hasKey("nested"));
     Object valOldPath = JsonPath.read(data, "$.key3");
     Object valNewPath = JsonPath.read(newObject, "$.nested.key3");
     assertThat(valNewPath, is(valOldPath));
    }

Obtained result:

java.lang.AssertionError: 
Expected: map containing ["nested"->ANYTHING]
     but: map was [<key=2018-01-25>, <ok=null>]
	at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
	at org.junit.Assert.assertThat(Assert.java:956)
	at org.junit.Assert.assertThat(Assert.java:923)
	at com.wdpr.cap.accounting.jsonpath.converter.ObjectConverterTest.testPathSetting(ObjectConverterTest.java:86)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)

Expected:

JUnit test passes.

@michelbetancourt
Copy link
Author

michelbetancourt commented Jan 25, 2018

Note, if I remove the following option:

Option.DEFAULT_PATH_LEAF_TO_NULL, 

Then the result I get is this from that same test:

java.lang.AssertionError: 
Expected: map containing ["key"-><2018-01-25>]
     but: map was []
	at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
	at org.junit.Assert.assertThat(Assert.java:956)
	at org.junit.Assert.assertThat(Assert.java:923)
	at com.wdpr.cap.accounting.jsonpath.converter.ObjectConverterTest.testPathSetting(ObjectConverterTest.java:88)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)

Expected:

I would of thought that this option would not have direct impact to the test. But rather than having key2 as null (which is translated to "ok" key in the new object), then both of these keys should just not be present, is my thought.

@unjeru
Copy link

unjeru commented Mar 26, 2018

If we trying to add something to empty json ("{}") by Json Path like "$.nonexistent.node" we can see an exception

com.jayway.jsonpath.PathNotFoundException: Missing property in path $['nonexistent']

It was cool, if we have some option to create an absent part of json path if it is expected

@ChrisLeeBare
Copy link

ChrisLeeBare commented May 16, 2018

The option to create absents parts in a json by calling the set Method would be very appreciated.
If so, you could build very cool InputJson to OutputJson Mapping Functions.
Combined with deserialization from Gson this would be a nice way to use a easy and understandable way to map Java classes.

eg.:

	@RequestMapping(path = "/test", method = RequestMethod.POST)
	ResponseEntity<?> mapPerson(@RequestBody PersonPojo1 input) {
		
		Map<String, String> mappingMap = new HashMap<>();
		
		mappingMap.put("$.orderList[0].order[0].firstName", "$.businessPartners.businessPartner.firstName");
		mappingMap.put("$.orderList[0].order[0].lastName", "$.businessPartners.businessPartner.surName");
		
		Gson gsonObject = new GsonBuilder().create();
		
		String inputJson = gsonObject.toJson(input);
		
		PersonPojo2 output = new PersonPojo2();
		
		String outputJson = gsonObject.toJson(output);
		
		for(Entry<String, String> keyPair : mappingMap.entrySet()) {
			JsonPath.parse(outputJson).set(keyPair.getValue(), JsonPath.read(inputJson, keyPair.getKey()));
		}
		
		output = gsonObject.fromJson(outputJson, PersonPojo2.class);
		
		URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("").buildAndExpand(output).toUri();
		
		return ResponseEntity.created(location).body(output);
		
		
	}

@akanshSirohi
Copy link

@ChrisLeeBare Any solution for this issue...?
#982 (comment)

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

No branches or pull requests

5 participants