Browse Source

Added renameKey feature to rename a key value found in a map path to a new key value.

pull/81/head
Tamas Adam 10 years ago
parent
commit
f16ce7c2c6
  1. 11
      json-path/src/main/java/com/jayway/jsonpath/JsonPath.java
  2. 27
      json-path/src/main/java/com/jayway/jsonpath/WriteContext.java
  3. 17
      json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java
  4. 63
      json-path/src/main/java/com/jayway/jsonpath/internal/PathRef.java
  5. 39
      json-path/src/test/java/com/jayway/jsonpath/WriteTest.java

11
json-path/src/main/java/com/jayway/jsonpath/JsonPath.java

@ -276,6 +276,17 @@ public class JsonPath {
return resultByConfiguration(jsonObject, configuration, evaluationContext);
}
public <T> T renameKey(Object jsonObject, String oldKeyName, String newKeyName, Configuration configuration){
notNull(jsonObject, "json can not be null");
notEmpty(newKeyName, "newKeyName can not be null or empty");
notNull(configuration, "configuration can not be null");
EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration, true);
for (PathRef updateOperation : evaluationContext.updateOperations()) {
updateOperation.renameKey(oldKeyName, newKeyName, configuration);
}
return resultByConfiguration(jsonObject, configuration, evaluationContext);
}
/**
* Applies this JsonPath to the provided json string
*

27
json-path/src/main/java/com/jayway/jsonpath/WriteContext.java

@ -116,6 +116,7 @@ public interface WriteContext {
*/
DocumentContext put(String path, String key, Object value, Predicate... filters);
/**
* Add or update the key with a the given value at the given path
*
@ -126,4 +127,28 @@ public interface WriteContext {
*/
DocumentContext put(JsonPath path, String key, Object value);
}
/**
* Renames the last key element of a given path.
* @param path The path to the old key. Should be resolved to a map
* or an array including map items.
* @param oldKeyName The old key name.
* @param newKeyName The new key name.
* @param filters filters.
* @return a document content.
*/
DocumentContext renameKey(String path, String oldKeyName, String newKeyName, Predicate... filters);
/**
* Renames the last key element of a given path.
* @param path The path to the old key. Should be resolved to a map
* or an array including map items.
* @param oldKeyName The old key name.
* @param newKeyName The new key name.
* @return a document content.
*/
DocumentContext renameKey(JsonPath path, String oldKeyName, String newKeyName);
// DocumentContext replace(String path, String newKey, Predicate... filters);
// DocumentContext replace(JsonPath path, String newKey);
}

17
json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java

@ -231,6 +231,23 @@ public class JsonReader implements ParseContext, DocumentContext {
return put(compile(path, filters), key, value);
}
@Override
public DocumentContext renameKey(String path, String oldKeyName, String newKeyName, Predicate... filters) {
return renameKey(compile(path, filters), oldKeyName, newKeyName);
}
@Override
public DocumentContext renameKey(JsonPath path, String oldKeyName, String newKeyName) {
List<String> modified = path.renameKey(json, oldKeyName, newKeyName, configuration.addOptions(Option.AS_PATH_LIST));
if(logger.isDebugEnabled()){
for (String p : modified) {
logger.debug("Rename path {} new value {}", p, newKeyName);
}
}
return this;
}
@Override
public DocumentContext put(JsonPath path, String key, Object value){
List<String> modified = path.put(json, key, value, configuration.addOptions(Option.AS_PATH_LIST));

63
json-path/src/main/java/com/jayway/jsonpath/internal/PathRef.java

@ -2,6 +2,7 @@ package com.jayway.jsonpath.internal;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.InvalidModificationException;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.spi.json.JsonProvider;
import java.util.Collection;
@ -25,6 +26,10 @@ public abstract class PathRef implements Comparable<PathRef> {
@Override
public void put(String key, Object newVal, Configuration configuration) {}
@Override
public void renameKey(String oldKeyName, String newKeyName, Configuration configuration) {}
};
protected Object parent;
@ -44,6 +49,21 @@ public abstract class PathRef implements Comparable<PathRef> {
public abstract void put(String key, Object newVal, Configuration configuration);
public abstract void renameKey(String oldKey,String newKeyName, Configuration configuration);
protected void renameInMap(Object targetMap, String oldKeyName, String newKeyName, Configuration configuration){
if(configuration.jsonProvider().isMap(targetMap)){
configuration.jsonProvider().setProperty(targetMap, newKeyName, configuration.jsonProvider().getMapValue(targetMap, oldKeyName));
configuration.jsonProvider().removeProperty(targetMap, oldKeyName);
} else {
throw new InvalidModificationException("Can only rename properties in a map");
}
}
protected boolean targetInvalid(Object target){
return target == JsonProvider.UNDEFINED || target == null;
}
@Override
public int compareTo(PathRef o) {
return this.getAccessor().toString().compareTo(o.getAccessor().toString()) * -1;
@ -103,6 +123,16 @@ public abstract class PathRef implements Comparable<PathRef> {
throw new InvalidModificationException("Invalid put operation. $ is not a map");
}
}
@Override
public void renameKey(String oldKeyName, String newKeyName, Configuration configuration) {
Object target = parent;
if(targetInvalid(target)){
return;
}
renameInMap(target, oldKeyName, newKeyName, configuration);
}
}
private static class ArrayIndexPathRef extends PathRef {
@ -123,7 +153,7 @@ public abstract class PathRef implements Comparable<PathRef> {
public void add(Object value, Configuration configuration){
Object target = configuration.jsonProvider().getArrayIndex(parent, index);
if(target == JsonProvider.UNDEFINED || target == null){
if(targetInvalid(target)){
return;
}
if(configuration.jsonProvider().isArray(target)){
@ -135,7 +165,7 @@ public abstract class PathRef implements Comparable<PathRef> {
public void put(String key, Object value, Configuration configuration){
Object target = configuration.jsonProvider().getArrayIndex(parent, index);
if(target == JsonProvider.UNDEFINED || target == null){
if(targetInvalid(target)){
return;
}
if(configuration.jsonProvider().isMap(target)){
@ -145,6 +175,15 @@ public abstract class PathRef implements Comparable<PathRef> {
}
}
@Override
public void renameKey(String oldKeyName, String newKeyName, Configuration configuration) {
Object target = configuration.jsonProvider().getArrayIndex(parent, index);
if(targetInvalid(target)){
return;
}
renameInMap(target, oldKeyName, newKeyName, configuration);
}
@Override
public Object getAccessor() {
return index;
@ -172,7 +211,7 @@ public abstract class PathRef implements Comparable<PathRef> {
public void add(Object value, Configuration configuration){
Object target = configuration.jsonProvider().getMapValue(parent, property);
if(target == JsonProvider.UNDEFINED || target == null){
if(targetInvalid(target)){
return;
}
if(configuration.jsonProvider().isArray(target)){
@ -184,7 +223,7 @@ public abstract class PathRef implements Comparable<PathRef> {
public void put(String key, Object value, Configuration configuration){
Object target = configuration.jsonProvider().getMapValue(parent, property);
if(target == JsonProvider.UNDEFINED || target == null){
if(targetInvalid(target)){
return;
}
if(configuration.jsonProvider().isMap(target)){
@ -194,6 +233,15 @@ public abstract class PathRef implements Comparable<PathRef> {
}
}
@Override
public void renameKey(String oldKeyName, String newKeyName, Configuration configuration) {
Object target = configuration.jsonProvider().getMapValue(parent, property);
if(targetInvalid(target)){
return;
}
renameInMap(target, oldKeyName, newKeyName, configuration);
}
@Override
public Object getAccessor() {
return property;
@ -228,7 +276,12 @@ public abstract class PathRef implements Comparable<PathRef> {
@Override
public void put(String key, Object newVal, Configuration configuration) {
throw new InvalidModificationException("Add can not be performed to multiple properties");
throw new InvalidModificationException("Put can not be performed to multiple properties");
}
@Override
public void renameKey(String oldKeyName, String newKeyName, Configuration configuration) {
throw new InvalidModificationException("Rename can not be performed to multiple properties");
}
@Override

39
json-path/src/test/java/com/jayway/jsonpath/WriteTest.java

@ -2,10 +2,7 @@ package com.jayway.jsonpath;
import org.junit.Test;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.*;
import static com.jayway.jsonpath.JsonPath.parse;
import static java.util.Collections.emptyMap;
@ -214,6 +211,38 @@ public class WriteTest extends BaseTest {
parse(model).set("$[?(@.a == 'a-val')]", 1);
}
@Test
public void a_path_can_be_renamed(){
Object o = parse(JSON_DOCUMENT).renameKey("$.store", "book", "updated-book").json();
List<Object> result = parse(o).read("$.store.updated-book");
assertThat(result).isNotEmpty();
}
@Test
public void keys_in_root_containing_map_can_be_renamed(){
Object o = parse(JSON_DOCUMENT).renameKey("$", "store", "new-store").json();
List<Object> result = parse(o).read("$.new-store[*]");
assertThat(result).isNotEmpty();
}
@Test
public void map_array_items_can_be_renamed(){
Object o = parse(JSON_DOCUMENT).renameKey("$.store.book[*]", "category", "renamed-category").json();
List<Object> result = parse(o).read("$.store.book[*].renamed-category");
assertThat(result).isNotEmpty();
}
@Test(expected = InvalidModificationException.class)
public void non_map_array_items_cannot_be_renamed(){
List<Integer> model = new LinkedList<Integer>();
model.add(1);
model.add(2);
parse(model).renameKey("$[*]", "oldKey", "newKey");
}
}
@Test(expected = InvalidModificationException.class)
public void multiple_properties_cannot_be_renamed(){
parse(JSON_DOCUMENT).renameKey("$.store.book[*]['author', 'category']", "old-key", "new-key");
}
}
Loading…
Cancel
Save