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

com.zuunr.jsonpointer.JsonPointer Maven / Gradle / Ivy

/*
 * Copyright 2020 Zuunr AB
 *
 * 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 com.zuunr.jsonpointer;

import com.zuunr.json.JsonArray;
import com.zuunr.json.JsonArrayBuilder;
import com.zuunr.json.JsonValue;
import com.zuunr.json.JsonValueSupport;

/**
 * @author Niklas Eldberger
 */
public class JsonPointer {

    private static final JsonValue FRAGMENT_START = JsonValue.of("#");
    private static final JsonPointer JSON_DOCUMENT_ROOT = new JsonPointer("#",JsonArray.EMPTY);

    private String asString;
    private JsonArray asArray;

    public static JsonPointer of(String pointer) {
        JsonArrayBuilder builder = JsonArray.EMPTY.builder();
        JsonArray array = JsonArray.of(pointer.split("/"));
        if (pointer.endsWith("/")) {
            array = array.add("");
        }
        if (FRAGMENT_START.equals(array.head())) {
            array = array.tail();
        }
        for (JsonValue referenceTokenJsonValue : array) {

            Integer integer = integerOf(referenceTokenJsonValue.getString());
            if (integer == null) {
                JsonValue unescaped = unescape(referenceTokenJsonValue);
                builder.add(unescaped);
            } else {
                builder.add(integer);
            }
        }
        return new JsonPointer(pointer, builder.build());
    }

    public static JsonPointer of(JsonArray array) {
        if (array.isEmpty()) {
            return JSON_DOCUMENT_ROOT;
        }
        JsonArrayBuilder builder = JsonArray.EMPTY.builder();
        StringBuilder stringBuilder = null;
        for (JsonValue unescapedReferenceToken : array) {
            JsonValue escaped;
            if (unescapedReferenceToken.isString()) {
                escaped = escape(unescapedReferenceToken);
            } else if (unescapedReferenceToken.isInteger()) {
                escaped = unescapedReferenceToken;
            } else {
                throw new RuntimeException("Only Integer and String is supported");
            }

            if (stringBuilder == null) {
                stringBuilder = new StringBuilder();
            } else {
                stringBuilder.append("/");
            }
            builder.add(escaped);
            stringBuilder.append(escaped.isString() ? escaped.getString() : escaped.toString());
        }
        
        if (stringBuilder == null) {
            // FIXME Should stringBuilder be nullable?
            throw new IllegalStateException("Array was empty");
        }
        
        return new JsonPointer(stringBuilder.toString(), builder.build());
    }

    private JsonPointer(String pointer, JsonArray pointerArray) {
        this.asString = pointer;
        this.asArray = pointerArray;
    }

    private static JsonValue unescape(JsonValue referenceTokenJsonValue) {
        String unescaped = referenceTokenJsonValue.getString().replace("~1", "/");
        unescaped = unescaped.replace("~0", "~");
        unescaped = decodeHex(unescaped);
        return JsonValue.of(unescaped);
    }

    public static String decodeHex(String stringWithHex) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < stringWithHex.length(); i++) {
            char charToAppend;
            if (stringWithHex.charAt(i) == '%' && i < stringWithHex.length() - 2) {
                String hexValue = stringWithHex.substring(i + 1, i + 3);
                charToAppend = (char) Integer.parseInt(hexValue, 16);
                i = i + 2;
            } else {
                charToAppend = stringWithHex.charAt(i);
            }
            builder.append(charToAppend);
        }
        return builder.toString();
    }

    private static JsonValue escape(JsonValue unescaped) {
        String escaped = unescaped.getString().replace("~", "~0");
        escaped = escaped.replace("/", "~1");
        return JsonValue.of(escaped);
    }

    public JsonArray asJsonArray() {
        return asArray;
    }

    public String asString() {
        return asString;
    }

    @Override
    public String toString() {
        return asString();
    }

    private static Integer integerOf(String string) {
        try {
            return Integer.parseInt(string);
        } catch (Exception e) {
            return null;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy