All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.progix.dropwizard.patch.JsonPath Maven / Gradle / Ivy

Go to download

An implementation of the HTTP method PATCH using RFC6902 for the Dropwizard framework.

The newest version!
/*
 * Copyright 2014 Tariq Bugrara
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.progix.dropwizard.patch;

import com.fasterxml.jackson.core.JsonPointer;
import io.progix.dropwizard.patch.exception.InvalidPatchPathException;

import java.util.ArrayList;
import java.util.List;

/**
 * Wrapper class for Jackson's {@link JsonPointer}
 * 

* Created to be more user-friendly for explicit patching. This class is used to determine what a String Json path as * defined in RFC6901 points to */ public class JsonPath { private List properties; private List elements; private String pathString; private JsonPointer jsonPointer; private int size; /** * Creates the path using a {@link JsonPointer} by iterating through the segments and creating {@link * JsonPathProperty} and {@link JsonPathElement} for each segment. *

* If a given segment does not match as a String property, an empty {@link JsonPathProperty} is created. *

* If a given segment does not match as a Integer index, an empty {@link JsonPathElement} is created. * * @param pointer * * @see com.fasterxml.jackson.core.JsonPointer */ public JsonPath(JsonPointer pointer) { this.jsonPointer = pointer; this.properties = new ArrayList<>(); this.elements = new ArrayList<>(); this.pathString = ""; while (pointer != null) { if (pointer.getMatchingProperty() != null && !pointer.getMatchingProperty().isEmpty()) { size++; } // Keep in mind, Jackson's implementation of JsonPointer allows all segments to be properties if (pointer.mayMatchProperty() && !pointer.mayMatchElement() && !pointer.getMatchingProperty() .isEmpty() && !pointer.getMatchingProperty().equals("-")) { properties.add(new JsonPathProperty(pointer.getMatchingProperty())); this.pathString += "/" + pointer.getMatchingProperty(); } else if (pointer.getMatchingProperty().equals("-")) { // This character represents the last element in an array elements.add(new JsonPathElement(true)); this.pathString += pointer.getMatchingProperty() + "/"; } else { properties.add(new JsonPathProperty()); } if (pointer.mayMatchElement()) { elements.add(new JsonPathElement(pointer.getMatchingIndex())); this.pathString += "/" + pointer.getMatchingIndex(); } else { elements.add(new JsonPathElement()); } pointer = pointer.tail(); } } /** * Convenience method to retrieve all {@link JsonPathProperty} for this path * * @return the list of {@link JsonPathProperty} */ public List getProperties() { return properties; } /** * Convenience method to retrieve all {@link JsonPathElement} for this path * * @return the list of {@link JsonPathElement} */ public List getElements() { return elements; } /** * @return the number of segments in this path */ public int size() { return size; } /** * Determines if this JsonPath is equivalent to the given String path. *

* Note that there should be no leading slash in the given path. *

* This method treats the string "#" as a special meaning to signify a numerical segment within the JsonPointer. If * you use the '#' character as a property name, use "~#" to properly treat that segment as a property and not an * array element. * * @param path String path to check * * @return true if the path is given is equivalent to this JsonPath, false otherwise. */ public boolean is(String path) { if (path.charAt(0) != '/') { throw new IllegalArgumentException("Paths must start with a '/'"); } // Remove first slash which is guaranteed path = path.substring(1, path.length()); String[] tokens = path.split("/"); if (!endsAt(tokens.length - 1)) { return false; } for (int i = 0; i < tokens.length; i++) { String token = tokens[i]; if (property(i).exists()) { // Can't be true because a property exists at i and path is checking for an element if (token.equals("#")) { return false; } // Convert special character to "#" if (token.equals("~#")) { token = "#"; } if (!token.equals(property(i).val())) { return false; } } else if (element(i).exists()) { if (token.equals("#") || (token.equals("-") && element(i).isEndOfArray()) || String .valueOf(element(i).val()).equals(token)) { return true; } } else { return false; } } return true; } /** * This method can be used to determine when an {@link InvalidPatchPathException} should be thrown. Uses this * exception and method provides useful information for the client when trying to patch a resource in a way the * server does not support *

* Ex. If the path is "/a/b/c", endsAt(2) will return true while endsAt(1) and endsAt(3) will return false * * @param index The index to test if this path ends * * @return true if the index provided is the last segment to contain data, false otherwise */ public boolean endsAt(int index) { int next = index + 1; return (property(index).exists() || element(index).exists()) && !property(next).exists() && !element(next) .exists(); } /** * This method will never return null. If trying to access a {@link JsonPathProperty} for a segment that is not a * String property, will return a special object who's {@link JsonPathProperty#exists()} will return false * * @param index the segment index to retrieve * * @return a {@link JsonPathProperty} for this index */ public JsonPathProperty property(int index) { if (index >= properties.size()) { return new JsonPathProperty(); } return properties.get(index); } /** * This method will never return null. If trying to access a {@link JsonPathElement} for a segment that is not an * Integer property, will return a special object who's {@link JsonPathElement#exists()} will return false * * @param index the segment index to retrieve * * @return a {@link JsonPathElement} for this index */ public JsonPathElement element(int index) { if (index >= elements.size()) { return new JsonPathElement(); } return elements.get(index); } @Override public String toString() { return pathString; } public JsonPointer getJsonPointer() { return jsonPointer; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy