├── .gitignore ├── .travis.yml ├── AUTHORS ├── CHANGELOG.md ├── LICENSE ├── NOTICE ├── README.md ├── checkstyle.xml ├── joy-classic-tests ├── pom.xml └── src │ ├── main │ └── resources │ │ └── dummy.txt │ └── test │ └── java │ └── org │ └── leadpony │ └── joy │ └── classic │ └── tests │ └── JsonGeneratorPrettyPrintTest.java ├── joy-classic ├── pom.xml └── src │ └── main │ ├── java │ ├── module-info.java │ └── org │ │ └── leadpony │ │ └── joy │ │ └── classic │ │ ├── ClassicJsonProvider.java │ │ └── package-info.java │ ├── javadoc │ ├── jakarta.json │ │ └── package-list │ └── java.base │ │ └── package-list │ └── resources │ └── META-INF │ ├── LICENSE │ ├── NOTICE │ └── services │ └── jakarta.json.spi.JsonProvider ├── joy-core ├── pom.xml └── src │ └── main │ ├── java │ ├── module-info.java │ └── org │ │ └── leadpony │ │ └── joy │ │ ├── api │ │ ├── JsonGenerator.java │ │ └── package-info.java │ │ └── core │ │ ├── AbstractJsonParser.java │ │ ├── AbstractJsonParserFactory.java │ │ ├── AbstractJsonProvider.java │ │ ├── BasicJsonLocation.java │ │ ├── BasicJsonParser.java │ │ ├── BigDecimalJsonNumber.java │ │ ├── BigIntegerJsonNumber.java │ │ ├── CharBufferFactory.java │ │ ├── CompactJsonGenerator.java │ │ ├── ConfigurableFactory.java │ │ ├── ExtendedJsonPointer.java │ │ ├── IntJsonNumber.java │ │ ├── JsonArrayBuilderImpl.java │ │ ├── JsonArrayImpl.java │ │ ├── JsonBuilderFactoryImpl.java │ │ ├── JsonChar.java │ │ ├── JsonDiffPatchBuilder.java │ │ ├── JsonGeneratorFactoryImpl.java │ │ ├── JsonMergePatchImpl.java │ │ ├── JsonNumberImpl.java │ │ ├── JsonObjectBuilderImpl.java │ │ ├── JsonObjectImpl.java │ │ ├── JsonParserFactoryImpl.java │ │ ├── JsonPatchBuilderImpl.java │ │ ├── JsonPatchImpl.java │ │ ├── JsonPointerImpl.java │ │ ├── JsonReaderFactoryImpl.java │ │ ├── JsonReaderImpl.java │ │ ├── JsonStreams.java │ │ ├── JsonStringBuilder.java │ │ ├── JsonStringImpl.java │ │ ├── JsonValueParser.java │ │ ├── JsonValues.java │ │ ├── JsonWriterFactoryImpl.java │ │ ├── JsonWriterImpl.java │ │ ├── LongJsonNumber.java │ │ ├── Message.java │ │ ├── ParserEventSet.java │ │ ├── PatchOperation.java │ │ ├── PooledCharBufferFactory.java │ │ ├── Preconditions.java │ │ ├── PrettyJsonGenerator.java │ │ ├── SimpleJsonGenerator.java │ │ ├── StreamReaders.java │ │ └── package-info.java │ ├── javadoc │ ├── jakarta.json │ │ └── package-list │ └── java.base │ │ └── package-list │ └── resources │ ├── META_INF │ ├── LICENSE │ └── NOTICE │ └── org │ └── leadpony │ └── joy │ └── core │ └── messages.properties ├── joy-yaml-tests ├── pom.xml └── src │ └── test │ ├── java │ └── org │ │ └── leadpony │ │ └── joy │ │ └── yaml │ │ └── tests │ │ ├── IllFormedYamlTestCase.java │ │ ├── JsonParserFactoryTest.java │ │ ├── JsonParserTest.java │ │ ├── JsonReaderFactoryTest.java │ │ ├── JsonReaderTest.java │ │ ├── SimpleYamlTestCase.java │ │ ├── YamlResource.java │ │ └── package-info.java │ └── resources │ └── org │ ├── json-schema │ ├── person.schema.json │ └── person.schema.yaml │ ├── leadpony │ └── joy │ │ └── yaml │ │ └── tests │ │ ├── null-key.json │ │ └── null-key.yaml │ ├── openapis │ ├── README.md │ ├── petstore.json │ └── petstore.yaml │ └── yaml │ ├── README.md │ ├── invoice.json │ ├── invoice.yaml │ ├── two-documents.json │ └── two-documents.yaml ├── joy-yaml ├── pom.xml └── src │ └── main │ ├── java │ ├── module-info.java │ └── org │ │ └── leadpony │ │ └── joy │ │ └── yaml │ │ ├── EventType.java │ │ ├── JsonLocations.java │ │ ├── LocalMessage.java │ │ ├── ParserContext.java │ │ ├── ParserState.java │ │ ├── YamlParser.java │ │ ├── YamlParserFactory.java │ │ ├── YamlProvider.java │ │ └── package-info.java │ ├── javadoc │ ├── jakarta.json │ │ └── package-list │ └── java.base │ │ └── package-list │ └── resources │ ├── META-INF │ └── services │ │ └── jakarta.json.spi.JsonProvider │ └── org │ └── leadpony │ └── joy │ └── yaml │ └── messages.properties ├── pom.xml └── tck └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .settings/ 3 | .classpath 4 | .project 5 | .checkstyle 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - openjdk14 4 | script: 5 | - mvn install 6 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | leadpony 2 | Davide Angelocola 3 | Todd O'Bryan 4 | Thiago Henrique Hüpner 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## 2.1.0 - 2021-01-24 8 | ### Changed 9 | - `JsonPointer.add()` now can replace the value at root location with given array/object, regardless of the original type. This is a requirement from the TCK. 10 | 11 | ### Fixed 12 | - `JsonObject.getBoolean()` and `JsonObject.isNull()` now correctly throws NPE if there exists no property for the specified key. (PR #12, #13 both are authored by @Thihup) 13 | - `JsonParserFactory.createParser(InputStream)` now correctly throws `JsonException` if character encoding cannot be determined automatically. (Issue #10 reported by @Thihup) 14 | - Fixed a bug that was causing JSON Patch move operation on nonexistent value not to throw `JsonException`, if the source path is the same as the target path. (Issue #11 reported by @Thihup) 15 | 16 | ## 2.0.0 - 2020-10-29 17 | ### Changed 18 | - Updated the Jakarta API to 2.0.0. 19 | 20 | ## 2.0.0-RC2 - 2020-04-26 21 | ### Added 22 | - Added a new JSON-P provider `joy-yaml` which can parse YAML documents with the help of [snakeyaml-engine](https://bitbucket.org/asomov/snakeyaml-engine). This artifact can be used as a substitute for the basic provider `joy-classic`. `JsonParser` and `JsonReader` provided by the new provider 23 | can process YAML documents. 24 | 25 | ### Changed 26 | - The artifact ID of the original Joy is now changed to `joy-classic`. 27 | - Improved `JsonNumber.numberValue()` which now may return an instance of `Integer` or `Long` if applicable. 28 | 29 | ### Fixed 30 | - Fixed the error message emitted when an array in the JSON document is not closed correctly. 31 | 32 | ## 2.0.0-RC1 - 2020-04-05 33 | ### Changed 34 | - The API package was renamed from `javax.json` to `jakarta.json`. 35 | - Update the version of Jakarta JSON Processing API to 2.0.0-RC2. 36 | 37 | ## 1.3.0 - 2020-02-01 38 | ### Changed 39 | - Collections and maps passed to `JsonBuilderFactory` now can contain instances of `JsonArrayBuilder` or `JsonObjectBuilder` as their values. (PR #3 contributed by [@toddobryan](https://github.com/toddobryan)) 40 | 41 | ## 1.2.0 - 2019-09-29 42 | ### Changed 43 | - Update the JSON Processing API to version 1.1.6. 44 | 45 | ### Fixed 46 | - A bug which was causing `JsonParser.skipArray()` and `JsonParser.skipObject()` to throw an `IllegalStateException` wrongly when the current state is not the start of the array/object. 47 | 48 | ## 1.1.0 - 2019-08-04 49 | ### Added 50 | - New configuration properties `INDENTATION_SIZE` and `TAB_INDENTATION` were added to the extended interface `JsonGenerator`. 51 | (Issue #1 originally proposed by @hohwille) 52 | 53 | ## 1.0.1 - 2019-07-28 54 | ### Fixed 55 | - `getConfigInUse()` methods now return only properties recognized by the factory. 56 | 57 | ## 1.0.0 - 2019-07-23 58 | ### Added 59 | - First release to the Maven Central Repository. 60 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | # Joy 2 | Copyright 2019-2021 the original author or authors. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this product except in compliance with the License. 6 | You may obtain a copy of the License at 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Joy 2 | 3 | [![Apache 2.0 License](https://img.shields.io/:license-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0) 4 | [![Maven Central](https://img.shields.io/maven-central/v/org.leadpony.joy/joy-classic.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22org.leadpony.joy%22%20AND%20a:%22joy-classic%22) 5 | [![Javadocs](https://www.javadoc.io/badge/jakarta.json/jakarta.json-api.svg)](https://www.javadoc.io/doc/jakarta.json/jakarta.json-api/1.1.6/index.html) 6 | [![Build Status](https://travis-ci.org/leadpony/joy.svg?branch=master)](https://travis-ci.org/leadpony/joy) 7 | 8 | Joy is yet another implementation of [Jakarta JSON Processing API] (JSON-P). 9 | 10 | ## Key Features 11 | 12 | * Fully compliant with the latest specification of [Jakarta JSON Processing API]. 13 | * Passes more than 2,000 tests provided by [JSON-P Test Suite]. 14 | * Works perfect with [Jakarta JSON Binding API] (JSON-B). 15 | * Supports YAML parsing and reading with the help of [snakeyaml-engine]. 16 | * Supports Java 8 and higher. 17 | * Can be used as a modular jar in Java 9 and higher. 18 | 19 | ## Getting Started 20 | 21 | ### Joy version 2 22 | 23 | Joy version 2 is an implementation of [Jakarta JSON Processing API] version 2.x, which is now defined in the `jakarta.json` package instead of `javax.json` package. 24 | 25 | For using this version, the following 2 dependencies neeed to be added in your `pom.xml` as an API and its implementation, respectively. 26 | 27 | ```xml 28 | 29 | jakarta.json 30 | jakarta.json-api 31 | 2.0.0 32 | 33 | 34 | 35 | org.leadpony.joy 36 | joy-classic 37 | 2.1.0 38 | runtime 39 | 40 | ``` 41 | 42 | ### Joy version 1 43 | 44 | Joy version 1 is an implementation of [Jakarta JSON Processing API] version 1, which was defined in `javax.json` package. For using this version, the following 2 dependencies neeed to be added in your `pom.xml` as an API and its implementation, respectively. 45 | 46 | ```xml 47 | 48 | jakarta.json 49 | jakarta.json-api 50 | 1.1.6 51 | 52 | 53 | 54 | org.leadpony.joy 55 | joy 56 | 1.3.0 57 | runtime 58 | 59 | ``` 60 | 61 | ## Beyond the Standard API 62 | 63 | For using the provider-specific API shown below, `scope` element of `dependency` must be changed from `runtime` to `compile` or be removed entirely. 64 | 65 | The provider-specific API is available in `org.leadpony.joy.api` package. 66 | 67 | ### JsonGenerator 68 | 69 | The following configuration properties are added. 70 | 71 | * INDENTATION_SIZE 72 | 73 | Specifies the number of spaces to be used as an 74 | indentation. The value of the property must be an integer. By default the 75 | number is 4. 76 | 77 | * TAB_INDENTATION 78 | 79 | Uses a tab for indentation instead of spaces. The 80 | value of the property could be anything. 81 | 82 | ## YAML Support 83 | 84 | All you need to do for parsing/reading YAML documents is switching the implementation from `joy-classic` to `joy-yaml` as shown below: 85 | 86 | ```xml 87 | 88 | org.leadpony.joy 89 | joy-yaml 90 | 2.1.0 91 | runtime 92 | 93 | ``` 94 | 95 | Please note that there are some restrictions in the current implementation of `joy-yaml`. 96 | * Aliases are not supported and cause the parser/reader to throw an exception. 97 | * Anchors are silently ignored. 98 | * Multiple documents are not supported. 99 | * Both generating and writing YAML documents are not supported yet. 100 | 101 | ## Additional Resources 102 | * [Jakarta JSON Processing API Reference in Javadoc](https://www.javadoc.io/doc/jakarta.json/jakarta.json-api) 103 | * [Joy API Reference in Javadoc](https://javadoc.io/doc/org.leadpony.joy/joy-core) 104 | * [Changelog](CHANGELOG.md) 105 | 106 | ## Building from Source 107 | 108 | JDK 14 and [Maven] are the tools required to build this software. The following command builds and install it into your local Maven repository. 109 | 110 | ```bash 111 | mvn clean install -P release 112 | ``` 113 | 114 | ## Other Solutions 115 | 116 | There are other implementations compatible with this software. 117 | 118 | * [Jakarta JSON Processing] (Reference Implementation) 119 | * [Apache Johnzon] 120 | 121 | ## Copyright Notice 122 | Copyright 2019-2021 the original author or authors. All rights reserved. 123 | 124 | Licensed under the Apache License, Version 2.0 (the "License"); 125 | you may not use this product except in compliance with the License. 126 | You may obtain a copy of the License at 127 | 128 | 129 | [Apache 2.0 License]: https://www.apache.org/licenses/LICENSE-2.0 130 | [Apache Johnzon]: https://johnzon.apache.org/ 131 | [Jakarta JSON Binding API]: http://json-b.net/ 132 | [Jakarta JSON Processing]: https://eclipse-ee4j.github.io/jsonp/ 133 | [Jakarta JSON Processing API]: https://eclipse-ee4j.github.io/jsonp/ 134 | [JSON-P Test Suite]: https://github.com/leadpony/jsonp-test-suite 135 | [Maven]: https://maven.apache.org/ 136 | [snakeyaml-engine]: https://bitbucket.org/asomov/snakeyaml-engine -------------------------------------------------------------------------------- /checkstyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /joy-classic-tests/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | 8 | 9 | org.leadpony.joy 10 | joy-parent 11 | 2.1.0 12 | 13 | 14 | joy-classic-tests 15 | jar 16 | org.leadpony.joy.classic.tests 17 | 18 | 19 | 14 20 | 21 | 22 | 23 | 24 | org.junit.jupiter 25 | junit-jupiter-engine 26 | test 27 | 28 | 29 | org.junit.jupiter 30 | junit-jupiter-params 31 | test 32 | 33 | 34 | org.assertj 35 | assertj-core 36 | test 37 | 38 | 39 | ${project.groupId} 40 | joy-classic 41 | ${project.version} 42 | test 43 | 44 | 45 | org.leadpony 46 | jsonp-test-suite 47 | test 48 | 49 | 50 | 51 | 52 | 53 | 54 | org.apache.maven.plugins 55 | maven-checkstyle-plugin 56 | 57 | 58 | org.apache.maven.plugins 59 | maven-surefire-plugin 60 | 61 | 62 | org.leadpony:jsonp-test-suite 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | release 72 | 73 | 74 | 75 | org.apache.maven.plugins 76 | maven-javadoc-plugin 77 | 78 | 79 | org.apache.maven.plugins 80 | maven-source-plugin 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /joy-classic-tests/src/main/resources/dummy.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leadpony/joy/d9e4303b664a5382cfea438a7a9afb1bedf60e54/joy-classic-tests/src/main/resources/dummy.txt -------------------------------------------------------------------------------- /joy-classic-tests/src/test/java/org/leadpony/joy/classic/tests/JsonGeneratorPrettyPrintTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.classic.tests; 17 | 18 | import static org.assertj.core.api.Assertions.assertThat; 19 | 20 | import java.io.StringWriter; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | import java.util.stream.Stream; 24 | 25 | import jakarta.json.Json; 26 | import jakarta.json.JsonReader; 27 | import jakarta.json.JsonValue; 28 | import jakarta.json.stream.JsonGeneratorFactory; 29 | 30 | import org.junit.jupiter.params.ParameterizedTest; 31 | import org.junit.jupiter.params.provider.Arguments; 32 | import org.junit.jupiter.params.provider.EnumSource; 33 | import org.junit.jupiter.params.provider.MethodSource; 34 | import org.leadpony.joy.api.JsonGenerator; 35 | import org.leadpony.jsonp.testsuite.tests.JsonResource; 36 | 37 | /** 38 | * @author leadpony 39 | */ 40 | public class JsonGeneratorPrettyPrintTest { 41 | 42 | public static Stream provideArguments() { 43 | return Stream.of(1, 2, 4, 8) 44 | .flatMap(indentSize -> { 45 | return Stream.of(JsonResource.values()) 46 | .map(resource -> Arguments.of(indentSize, resource)); 47 | }); 48 | } 49 | 50 | @ParameterizedTest 51 | @MethodSource("provideArguments") 52 | public void writeShouldGenerateJsonIndentedWithSpaces(int indentSize, JsonResource resource) { 53 | JsonValue json = readJsonFrom(resource); 54 | 55 | Map config = new HashMap<>(); 56 | config.put(JsonGenerator.PRETTY_PRINTING, Boolean.TRUE); 57 | config.put(JsonGenerator.INDENTATION_SIZE, indentSize); 58 | 59 | String actual = generateJson(json, config); 60 | String expected = resource.getJsonIndentedWithSpacesAsString(indentSize); 61 | 62 | assertThat(actual).isEqualTo(expected); 63 | } 64 | 65 | @ParameterizedTest 66 | @EnumSource(JsonResource.class) 67 | public void writeShouldGenerateJsonIndentedWithTab(JsonResource resource) { 68 | JsonValue json = readJsonFrom(resource); 69 | 70 | Map config = new HashMap<>(); 71 | config.put(JsonGenerator.PRETTY_PRINTING, Boolean.TRUE); 72 | config.put(JsonGenerator.TAB_INDENTATION, Boolean.TRUE); 73 | 74 | String actual = generateJson(json, config); 75 | String expected = resource.getJsonIndentedWithTabAsString(); 76 | 77 | assertThat(actual).isEqualTo(expected); 78 | } 79 | 80 | private static JsonValue readJsonFrom(JsonResource resource) { 81 | try (JsonReader reader = Json.createReader(resource.createReader())) { 82 | return reader.readValue(); 83 | } 84 | } 85 | 86 | private static String generateJson(JsonValue json, Map config) { 87 | JsonGeneratorFactory factory = Json.createGeneratorFactory(config); 88 | StringWriter writer = new StringWriter(); 89 | try (JsonGenerator generator = (JsonGenerator) factory.createGenerator(writer)) { 90 | generator.write(json); 91 | } 92 | return writer.toString(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /joy-classic/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | 8 | 9 | org.leadpony.joy 10 | joy-parent 11 | 2.1.0 12 | 13 | 14 | joy-classic 15 | jar 16 | org.leadpony.joy.classic 17 | 18 | 19 | 20 | ${project.groupId} 21 | joy-core 22 | ${project.version} 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | org.apache.maven.plugins 31 | maven-javadoc-plugin 32 | 3.1.0 33 | 34 | false 35 | 36 | 37 | https://docs.oracle.com/en/java/javase/11/docs/api/ 38 | ${basedir}/src/main/javadoc/java.base/ 39 | 40 | 41 | 42 | https://static.javadoc.io/jakarta.json/jakarta.json-api/2.0.0-RC1 43 | ${basedir}/src/main/javadoc/jakarta.json/ 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | org.apache.maven.plugins 53 | maven-checkstyle-plugin 54 | 55 | 56 | org.apache.maven.plugins 57 | maven-jar-plugin 58 | 59 | 60 | 61 | org.leadpony.joy.classic 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | release 72 | 73 | 74 | 75 | org.apache.maven.plugins 76 | maven-compiler-plugin 77 | 78 | 79 | default-compile 80 | 81 | compile 82 | 83 | 84 | 9 85 | 86 | 87 | 88 | base-compile 89 | 90 | compile 91 | 92 | 93 | 94 | module-info.java 95 | 96 | 97 | 98 | 99 | 100 | 101 | org.apache.maven.plugins 102 | maven-javadoc-plugin 103 | 104 | 105 | org.apache.maven.plugins 106 | maven-source-plugin 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /joy-classic/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | /** 17 | * Defines the provider of Jakarta JSON Processing API (JSON-P). 18 | */ 19 | module org.leadpony.joy.classic { 20 | requires org.leadpony.joy.core; 21 | 22 | provides jakarta.json.spi.JsonProvider 23 | with org.leadpony.joy.classic.ClassicJsonProvider; 24 | } 25 | -------------------------------------------------------------------------------- /joy-classic/src/main/java/org/leadpony/joy/classic/ClassicJsonProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.classic; 18 | 19 | import org.leadpony.joy.core.AbstractJsonProvider; 20 | import jakarta.json.spi.JsonProvider; 21 | 22 | /** 23 | * A {@link JsonProvider} for producing JSON parsers and generators. 24 | * 25 | * @author leadpony 26 | */ 27 | public final class ClassicJsonProvider extends AbstractJsonProvider { 28 | 29 | /** 30 | * Constructs this provider. 31 | */ 32 | public ClassicJsonProvider() { 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /joy-classic/src/main/java/org/leadpony/joy/classic/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Provides a basic JSON service provider. 19 | * 20 | * @author leadpony 21 | */ 22 | package org.leadpony.joy.classic; 23 | -------------------------------------------------------------------------------- /joy-classic/src/main/javadoc/jakarta.json/package-list: -------------------------------------------------------------------------------- 1 | module:jakarta.json 2 | jakarta.json 3 | jakarta.json.spi 4 | jakarta.json.stream 5 | -------------------------------------------------------------------------------- /joy-classic/src/main/javadoc/java.base/package-list: -------------------------------------------------------------------------------- 1 | module:java.base 2 | java.io 3 | java.lang 4 | java.math 5 | java.net 6 | java.nio.charset 7 | java.nio.file 8 | java.util 9 | java.util.function 10 | java.util.stream -------------------------------------------------------------------------------- /joy-classic/src/main/resources/META-INF/NOTICE: -------------------------------------------------------------------------------- 1 | # Joy 2 | Copyright 2019-2020 the original author or authors. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this product except in compliance with the License. 6 | You may obtain a copy of the License at 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /joy-classic/src/main/resources/META-INF/services/jakarta.json.spi.JsonProvider: -------------------------------------------------------------------------------- 1 | org.leadpony.joy.classic.ClassicJsonProvider -------------------------------------------------------------------------------- /joy-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | 8 | 9 | org.leadpony.joy 10 | joy-parent 11 | 2.1.0 12 | 13 | 14 | joy-core 15 | jar 16 | org.leadpony.joy.core 17 | 18 | 19 | 20 | jakarta.json 21 | jakarta.json-api 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | org.apache.maven.plugins 30 | maven-javadoc-plugin 31 | 3.1.0 32 | 33 | false 34 | 35 | 36 | https://docs.oracle.com/en/java/javase/11/docs/api/ 37 | ${basedir}/src/main/javadoc/java.base/ 38 | 39 | 40 | 41 | https://static.javadoc.io/jakarta.json/jakarta.json-api/2.0.0-RC1 42 | ${basedir}/src/main/javadoc/jakarta.json/ 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-checkstyle-plugin 53 | 54 | 55 | org.apache.maven.plugins 56 | maven-jar-plugin 57 | 58 | 59 | 60 | org.leadpony.joy.core 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | release 71 | 72 | 73 | 74 | org.apache.maven.plugins 75 | maven-compiler-plugin 76 | 77 | 78 | default-compile 79 | 80 | compile 81 | 82 | 83 | 9 84 | 85 | 86 | 87 | base-compile 88 | 89 | compile 90 | 91 | 92 | 93 | module-info.java 94 | 95 | 96 | 97 | 98 | 99 | 100 | org.apache.maven.plugins 101 | maven-javadoc-plugin 102 | 103 | 104 | org.apache.maven.plugins 105 | maven-source-plugin 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /joy-core/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | /** 17 | * Defines the groundwork for implementations of Jakarta JSON Processing API (JSON-P). 18 | */ 19 | module org.leadpony.joy.core { 20 | requires transitive jakarta.json; 21 | exports org.leadpony.joy.api; 22 | exports org.leadpony.joy.core; 23 | } 24 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/api/JsonGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.api; 17 | 18 | /** 19 | * An extended {@link JsonGenerator}. 20 | * 21 | * @author leadpony 22 | */ 23 | public interface JsonGenerator extends jakarta.json.stream.JsonGenerator { 24 | 25 | /** 26 | * Configuration property to specify the number of spaces to be used as an 27 | * indentation. The value of the property must be an integer. By default the 28 | * number is 4. 29 | * 30 | *
31 |      * 
32 |      * Map<String, Object> config = new HashMap<>();
33 |      * config.put(JsonGenerator.PRETTY_PRINTING, Boolean.TRUE);
34 |      * config.put(JsonGenerator.INDENTATION_SIZE, 2);
35 |      * 
36 |      * 
37 | * 38 | * @since 1.1 39 | */ 40 | String INDENTATION_SIZE = "org.leadpony.joy.api.JsonGenerator.indentationSize"; 41 | 42 | /** 43 | * Configuration property to use a tab for indentation instead of spaces. The 44 | * value of the property could be anything. 45 | *
46 |      * 
47 |      * Map<String, Object> config = new HashMap<>();
48 |      * config.put(JsonGenerator.PRETTY_PRINTING, Boolean.TRUE);
49 |      * config.put(JsonGenerator.TAB_INDENTATION, Boolean.TRUE);
50 |      * 
51 |      * 
52 | * 53 | * @since 1.1 54 | */ 55 | String TAB_INDENTATION = "org.leadpony.joy.api.JsonGenerator.tabIndentation"; 56 | } 57 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/api/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | /** 17 | * Provides the extension of JSON Processing API. 18 | * 19 | * @author leadpony 20 | */ 21 | package org.leadpony.joy.api; 22 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/AbstractJsonParserFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.core; 18 | 19 | import static org.leadpony.joy.core.Preconditions.requireNonNull; 20 | 21 | import java.io.InputStream; 22 | import java.io.Reader; 23 | import java.util.Map; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | import jakarta.json.stream.JsonParser; 28 | import jakarta.json.stream.JsonParserFactory; 29 | 30 | /** 31 | * A skeletal implementation of {@link JsonParserFactory}. 32 | * 33 | * @author leadpony 34 | */ 35 | public abstract class AbstractJsonParserFactory extends ConfigurableFactory implements JsonParserFactory { 36 | 37 | protected AbstractJsonParserFactory(Map properties) { 38 | this(properties, NO_SUPPORTED_PROPERTIES); 39 | } 40 | 41 | protected AbstractJsonParserFactory(Map properties, String[] supported) { 42 | super(properties, supported); 43 | } 44 | 45 | @Override 46 | public JsonParser createParser(JsonObject obj) { 47 | requireNonNull(obj, "obj"); 48 | return new JsonValueParser(obj); 49 | } 50 | 51 | @Override 52 | public JsonParser createParser(JsonArray array) { 53 | requireNonNull(array, "array"); 54 | return new JsonValueParser(array); 55 | } 56 | 57 | protected Reader createStreamReader(InputStream in) { 58 | return StreamReaders.createStreamReader(in); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/BasicJsonLocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import jakarta.json.stream.JsonLocation; 19 | 20 | /** 21 | * A basic implementation of {@link JsonLocation}. 22 | * 23 | * @author leadpony 24 | */ 25 | public class BasicJsonLocation implements JsonLocation { 26 | 27 | /** 28 | * Initial location. 29 | */ 30 | public static final JsonLocation INITIAL = new BasicJsonLocation(1, 1, 0); 31 | /** 32 | * Unknown location. 33 | */ 34 | public static final JsonLocation UNKNOWN = new BasicJsonLocation(-1, -1, -1); 35 | 36 | private final long lineNumber; 37 | private final long columnNumber; 38 | private final long streamOffset; 39 | 40 | public BasicJsonLocation(long streamOffset) { 41 | this.lineNumber = -1; 42 | this.columnNumber = -1; 43 | this.streamOffset = streamOffset; 44 | } 45 | 46 | public BasicJsonLocation(long lineNumber, long columnNumber, long streamOffset) { 47 | this.lineNumber = lineNumber; 48 | this.columnNumber = columnNumber; 49 | this.streamOffset = streamOffset; 50 | } 51 | 52 | @Override 53 | public long getLineNumber() { 54 | return lineNumber; 55 | } 56 | 57 | @Override 58 | public long getColumnNumber() { 59 | return columnNumber; 60 | } 61 | 62 | @Override 63 | public long getStreamOffset() { 64 | return streamOffset; 65 | } 66 | 67 | @Override 68 | public String toString() { 69 | StringBuilder b = new StringBuilder("["); 70 | b.append("line=").append(getLineNumber()) 71 | .append(",column=").append(getColumnNumber()) 72 | .append(",offset=").append(getStreamOffset()); 73 | return b.append("]").toString(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/BigDecimalJsonNumber.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.math.BigDecimal; 19 | 20 | /** 21 | * A JSON number holding {@code BigDecimal}. 22 | * 23 | * @author leadpony 24 | */ 25 | class BigDecimalJsonNumber extends JsonNumberImpl { 26 | 27 | private final BigDecimal value; 28 | 29 | BigDecimalJsonNumber(BigDecimal value) { 30 | this.value = value; 31 | } 32 | 33 | @Override 34 | public BigDecimal bigDecimalValue() { 35 | return value; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/BigIntegerJsonNumber.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.math.BigDecimal; 19 | import java.math.BigInteger; 20 | 21 | /** 22 | * A JSON number holding {@code BigInteger}. 23 | * 24 | * @author leadpony 25 | */ 26 | class BigIntegerJsonNumber extends BigDecimalJsonNumber { 27 | 28 | BigIntegerJsonNumber(BigInteger value) { 29 | super(new BigDecimal(value)); 30 | } 31 | 32 | @Override 33 | public boolean isIntegral() { 34 | return true; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/CharBufferFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | /** 19 | * A factory of character buffers. 20 | * 21 | * @author leadpony 22 | */ 23 | interface CharBufferFactory { 24 | 25 | /** 26 | * Creates a character buffer. 27 | * 28 | * @return created character buffer. 29 | */ 30 | char[] createBuffer(); 31 | 32 | /** 33 | * Releases a character buffer. 34 | * 35 | * @param buffer the buffer to release. 36 | */ 37 | default void releaseBuffer(char[] buffer) { 38 | } 39 | 40 | CharBufferFactory DEFAULT = new CharBufferFactory() { 41 | @Override 42 | public char[] createBuffer() { 43 | return new char[4096]; 44 | } 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/CompactJsonGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.io.BufferedWriter; 19 | import java.io.IOException; 20 | import java.io.StringWriter; 21 | import java.io.Writer; 22 | 23 | /** 24 | * @author leadpony 25 | */ 26 | class CompactJsonGenerator extends SimpleJsonGenerator { 27 | 28 | private final Writer writer; 29 | private final CharBufferFactory bufferFactory; 30 | private boolean alreadyClosed; 31 | 32 | CompactJsonGenerator(Writer writer, CharBufferFactory bufferFactory) { 33 | super(bufferFactory.createBuffer()); 34 | this.writer = decorateWriter(writer); 35 | this.bufferFactory = bufferFactory; 36 | } 37 | 38 | @Override 39 | public void close() { 40 | if (alreadyClosed) { 41 | return; 42 | } 43 | 44 | super.close(); 45 | 46 | try { 47 | flush(); 48 | writer.close(); 49 | bufferFactory.releaseBuffer(writeBuffer); 50 | } catch (IOException e) { 51 | throw newJsonException(Message.thatIOErrorOccurredWhileGeneratorWasClosing(), e); 52 | } finally { 53 | alreadyClosed = true; 54 | } 55 | } 56 | 57 | @Override 58 | public void flush() { 59 | try { 60 | flushBuffer(); 61 | writer.flush(); 62 | } catch (IOException e) { 63 | throw newJsonException(Message.thatIOErrorOccurredWhileGeneratorWasWriting(), e); 64 | } 65 | } 66 | 67 | @Override 68 | protected void refreshBuffer(int pos) { 69 | try { 70 | writer.write(writeBuffer, 0, pos); 71 | writePos = 0; 72 | } catch (IOException e) { 73 | throw newJsonException(Message.thatIOErrorOccurredWhileGeneratorWasWriting(), e); 74 | } 75 | } 76 | 77 | private void flushBuffer() throws IOException { 78 | if (writePos > 0) { 79 | writer.write(writeBuffer, 0, writePos); 80 | writePos = 0; 81 | } 82 | } 83 | 84 | private static Writer decorateWriter(Writer writer) { 85 | if (writer instanceof StringWriter) { 86 | return writer; 87 | } else { 88 | return new BufferedWriter(writer); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/ConfigurableFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.util.Collections; 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | 22 | /** 23 | * A factory with configuration properties. 24 | * 25 | * @author leadpony 26 | */ 27 | class ConfigurableFactory { 28 | 29 | public static final String[] NO_SUPPORTED_PROPERTIES = {}; 30 | 31 | private final Map properties; 32 | 33 | /** 34 | * Constructs this factory. 35 | * 36 | * @param properties all of the configuration properties. 37 | * @param supported the keys of configuration properties which this factory supports. 38 | */ 39 | protected ConfigurableFactory(Map properties, String... supported) { 40 | if (supported.length == 0) { 41 | this.properties = Collections.emptyMap(); 42 | } else { 43 | Map newMap = new HashMap<>(); 44 | for (String key : supported) { 45 | if (properties.containsKey(key)) { 46 | newMap.put(key, properties.get(key)); 47 | } 48 | } 49 | this.properties = Collections.unmodifiableMap(newMap); 50 | } 51 | } 52 | 53 | public final Map getConfigInUse() { 54 | return properties; 55 | } 56 | 57 | public final boolean containsProperty(String key) { 58 | return properties.containsKey(key); 59 | } 60 | 61 | @SuppressWarnings("unchecked") 62 | public final T getPropertyValue(String key, T defaultValue) { 63 | Object value = properties.get(key); 64 | if (defaultValue.getClass().isInstance(value)) { 65 | return (T) value; 66 | } else { 67 | return defaultValue; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/ExtendedJsonPointer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import jakarta.json.JsonPointer; 19 | 20 | /** 21 | * The extended interface of {@link javax.json.JsonPointer}. 22 | * 23 | * @author leadpony 24 | */ 25 | interface ExtendedJsonPointer extends JsonPointer { 26 | 27 | /** 28 | * Checks if this pointer is empty or not. 29 | * 30 | * @return {@code true} if this pointer is empty, otherwise {@code false}. 31 | */ 32 | boolean isEmpty(); 33 | 34 | /** 35 | * Checks if this pointer starts with the same reference tokens as the given 36 | * pointer. If the given pointer has more reference tokens than this pointer 37 | * then {@code false} will be returned. 38 | * 39 | * @param other the other JSON Pointer. 40 | * @return {@code true} if this pointer starts with the given path, otherwise 41 | * {@code false}. 42 | * @throws NullPointerException if {@code other} is {@code null}. 43 | */ 44 | boolean startsWith(ExtendedJsonPointer other); 45 | } 46 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/IntJsonNumber.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.math.BigDecimal; 19 | 20 | import jakarta.json.JsonNumber; 21 | 22 | /** 23 | * A JSON number which holds an integer. 24 | * 25 | * @author leadpony 26 | */ 27 | class IntJsonNumber extends JsonNumberImpl { 28 | 29 | private final int value; 30 | 31 | IntJsonNumber(int value) { 32 | this.value = value; 33 | } 34 | 35 | @Override 36 | public boolean isIntegral() { 37 | return true; 38 | } 39 | 40 | @Override 41 | public int intValue() { 42 | return value; 43 | } 44 | 45 | @Override 46 | public int intValueExact() { 47 | return value; 48 | } 49 | 50 | @Override 51 | public long longValue() { 52 | return value; 53 | } 54 | 55 | @Override 56 | public long longValueExact() { 57 | return value; 58 | } 59 | 60 | @Override 61 | public double doubleValue() { 62 | return value; 63 | } 64 | 65 | @Override 66 | public BigDecimal bigDecimalValue() { 67 | return BigDecimal.valueOf(value); 68 | } 69 | 70 | @Override 71 | public Number numberValue() { 72 | return value; 73 | } 74 | 75 | @Override 76 | public String toString() { 77 | return Integer.toString(value); 78 | } 79 | 80 | static final JsonNumber ZERO = new JsonNumberImpl() { 81 | 82 | @Override 83 | public BigDecimal bigDecimalValue() { 84 | return BigDecimal.ZERO; 85 | } 86 | 87 | @Override 88 | public boolean isIntegral() { 89 | return true; 90 | } 91 | 92 | @Override 93 | public int intValue() { 94 | return 0; 95 | } 96 | 97 | @Override 98 | public int intValueExact() { 99 | return 0; 100 | } 101 | 102 | @Override 103 | public long longValue() { 104 | return 0; 105 | } 106 | 107 | @Override 108 | public long longValueExact() { 109 | return 0; 110 | } 111 | 112 | @Override 113 | public double doubleValue() { 114 | return 0.0; 115 | } 116 | 117 | @Override 118 | public String toString() { 119 | return "0"; 120 | } 121 | }; 122 | 123 | static final JsonNumber ONE = new JsonNumberImpl() { 124 | 125 | @Override 126 | public BigDecimal bigDecimalValue() { 127 | return BigDecimal.ONE; 128 | } 129 | 130 | @Override 131 | public boolean isIntegral() { 132 | return true; 133 | } 134 | 135 | @Override 136 | public int intValue() { 137 | return 1; 138 | } 139 | 140 | @Override 141 | public int intValueExact() { 142 | return 1; 143 | } 144 | 145 | @Override 146 | public long longValue() { 147 | return 1; 148 | } 149 | 150 | @Override 151 | public long longValueExact() { 152 | return 1; 153 | } 154 | 155 | @Override 156 | public double doubleValue() { 157 | return 1.0; 158 | } 159 | 160 | @Override 161 | public String toString() { 162 | return "1"; 163 | } 164 | }; 165 | } 166 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonArrayImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import static org.leadpony.joy.core.Preconditions.requireNonNull; 19 | 20 | import java.util.AbstractList; 21 | import java.util.List; 22 | 23 | import jakarta.json.JsonArray; 24 | import jakarta.json.JsonNumber; 25 | import jakarta.json.JsonObject; 26 | import jakarta.json.JsonString; 27 | import jakarta.json.JsonValue; 28 | 29 | /** 30 | * An implementation of {@link JsonArray}. 31 | * 32 | * @author leadpony 33 | */ 34 | class JsonArrayImpl extends AbstractList implements JsonArray { 35 | 36 | private final List items; 37 | 38 | JsonArrayImpl(List items) { 39 | this.items = items; 40 | } 41 | 42 | /* As a JsonValue */ 43 | 44 | @Override 45 | public ValueType getValueType() { 46 | return ValueType.ARRAY; 47 | } 48 | 49 | @Override 50 | public JsonArray asJsonArray() { 51 | return this; 52 | } 53 | 54 | /* As a JsonStructure */ 55 | 56 | @Override 57 | public JsonValue getValue(String jsonPointer) { 58 | requireNonNull(jsonPointer, "jsonPointer"); 59 | return JsonPointerImpl.parse(jsonPointer).getValue(this); 60 | } 61 | 62 | /* As a JsonArray */ 63 | 64 | @Override 65 | public JsonObject getJsonObject(int index) { 66 | return (JsonObject) get(index); 67 | } 68 | 69 | @Override 70 | public JsonArray getJsonArray(int index) { 71 | return (JsonArray) get(index); 72 | } 73 | 74 | @Override 75 | public JsonNumber getJsonNumber(int index) { 76 | return (JsonNumber) get(index); 77 | } 78 | 79 | @Override 80 | public JsonString getJsonString(int index) { 81 | return (JsonString) get(index); 82 | } 83 | 84 | @SuppressWarnings("unchecked") 85 | @Override 86 | public List getValuesAs(Class clazz) { 87 | return (List) items; 88 | } 89 | 90 | @Override 91 | public String getString(int index) { 92 | return getJsonString(index).getString(); 93 | } 94 | 95 | @Override 96 | public String getString(int index, String defaultValue) { 97 | JsonValue value = get(index); 98 | if (value.getValueType() == ValueType.STRING) { 99 | return ((JsonString) value).getString(); 100 | } else { 101 | return defaultValue; 102 | } 103 | } 104 | 105 | @Override 106 | public int getInt(int index) { 107 | return getJsonNumber(index).intValue(); 108 | } 109 | 110 | @Override 111 | public int getInt(int index, int defaultValue) { 112 | JsonValue value = get(index); 113 | if (value.getValueType() == ValueType.NUMBER) { 114 | return ((JsonNumber) value).intValue(); 115 | } else { 116 | return defaultValue; 117 | } 118 | } 119 | 120 | @Override 121 | public boolean getBoolean(int index) { 122 | JsonValue value = get(index); 123 | if (value == JsonValue.TRUE) { 124 | return true; 125 | } else if (value == JsonValue.FALSE) { 126 | return false; 127 | } 128 | throw new ClassCastException(); 129 | } 130 | 131 | @Override 132 | public boolean getBoolean(int index, boolean defaultValue) { 133 | JsonValue value = get(index); 134 | if (value == JsonValue.TRUE) { 135 | return true; 136 | } else if (value == JsonValue.FALSE) { 137 | return false; 138 | } 139 | return defaultValue; 140 | } 141 | 142 | @Override 143 | public boolean isNull(int index) { 144 | return get(index) == JsonValue.NULL; 145 | } 146 | 147 | /* As a List */ 148 | 149 | @Override 150 | public JsonValue get(int index) { 151 | return items.get(index); 152 | } 153 | 154 | @Override 155 | public int size() { 156 | return items.size(); 157 | } 158 | 159 | @Override 160 | public String toString() { 161 | try (SimpleJsonGenerator g = new SimpleJsonGenerator()) { 162 | g.write(this); 163 | return g.toString(); 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonBuilderFactoryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import static org.leadpony.joy.core.Preconditions.requireNonNull; 19 | 20 | import java.util.Collection; 21 | import java.util.Map; 22 | 23 | import jakarta.json.JsonArray; 24 | import jakarta.json.JsonArrayBuilder; 25 | import jakarta.json.JsonBuilderFactory; 26 | import jakarta.json.JsonObject; 27 | import jakarta.json.JsonObjectBuilder; 28 | 29 | /** 30 | * @author leadpony 31 | */ 32 | class JsonBuilderFactoryImpl extends ConfigurableFactory implements JsonBuilderFactory { 33 | 34 | JsonBuilderFactoryImpl(Map config) { 35 | super(config, NO_SUPPORTED_PROPERTIES); 36 | } 37 | 38 | @Override 39 | public JsonObjectBuilder createObjectBuilder() { 40 | return new JsonObjectBuilderImpl(); 41 | } 42 | 43 | @Override 44 | public JsonObjectBuilder createObjectBuilder(JsonObject object) { 45 | requireNonNull(object, "object"); 46 | return new JsonObjectBuilderImpl(object); 47 | } 48 | 49 | @Override 50 | public JsonObjectBuilder createObjectBuilder(Map object) { 51 | requireNonNull(object, "object"); 52 | return new JsonObjectBuilderImpl(object); 53 | } 54 | 55 | @Override 56 | public JsonArrayBuilder createArrayBuilder() { 57 | return new JsonArrayBuilderImpl(); 58 | } 59 | 60 | @Override 61 | public JsonArrayBuilder createArrayBuilder(JsonArray array) { 62 | requireNonNull(array, "array"); 63 | return new JsonArrayBuilderImpl(array); 64 | } 65 | 66 | @Override 67 | public JsonArrayBuilder createArrayBuilder(Collection collection) { 68 | requireNonNull(collection, "collection"); 69 | return new JsonArrayBuilderImpl(collection); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonChar.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.util.AbstractSet; 19 | import java.util.EnumSet; 20 | import java.util.Iterator; 21 | import java.util.Set; 22 | import java.util.stream.Collectors; 23 | 24 | /** 25 | * Special characters in JSON. 26 | * 27 | * @author leadpony 28 | */ 29 | enum JsonChar { 30 | CLOSING_CURLY_BRACKET('}'), 31 | CLOSING_SQURE_BRACKET(']'), 32 | COLON(':'), 33 | COMMA(','); 34 | 35 | @SuppressWarnings("unused") 36 | private final char c; 37 | private final String s; 38 | 39 | JsonChar(char c) { 40 | this.c = c; 41 | this.s = "'" + Character.toString(c) + "'"; 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return s; 47 | } 48 | 49 | private static final String[] ESCAPED = { 50 | "\\u0000", 51 | "\\u0001", 52 | "\\u0002", 53 | "\\u0003", 54 | "\\u0004", 55 | "\\u0005", 56 | "\\u0006", 57 | "\\u0007", 58 | "\\b", // backspace 59 | "\\t", // tab 60 | "\\n", // line feed 61 | "\\u000b", 62 | "\\f", // form feed 63 | "\\r", // carriage return 64 | "\\u000e", 65 | "\\u000f", 66 | "\\u0010", 67 | "\\u0011", 68 | "\\u0012", 69 | "\\u0013", 70 | "\\u0014", 71 | "\\u0015", 72 | "\\u0016", 73 | "\\u0017", 74 | "\\u0018", 75 | "\\u0019", 76 | "\\u001a", 77 | "\\u001b", 78 | "\\u001c", 79 | "\\u001d", 80 | "\\u001e", 81 | "\\u001f" 82 | }; 83 | 84 | static String escape(char c) { 85 | return ESCAPED[c]; 86 | } 87 | 88 | static String toString(char c) { 89 | StringBuilder b = new StringBuilder("'"); 90 | if (c < 0x20) { 91 | b.append(escape(c)); 92 | } else { 93 | b.append(c); 94 | } 95 | return b.append("'").toString(); 96 | } 97 | 98 | static Set of(JsonChar... chars) { 99 | return new JsonCharSet(chars); 100 | } 101 | 102 | /** 103 | * A set of JSON characters. 104 | * 105 | * @author leadpony 106 | */ 107 | private static class JsonCharSet extends AbstractSet { 108 | 109 | private final EnumSet chars; 110 | private final String stringified; 111 | 112 | JsonCharSet(JsonChar... chars) { 113 | this.chars = EnumSet.noneOf(JsonChar.class); 114 | for (JsonChar c : chars) { 115 | this.chars.add(c); 116 | } 117 | this.stringified = this.chars.stream() 118 | .map(JsonChar::toString) 119 | .collect(Collectors.joining(",", "[", "]")); 120 | } 121 | 122 | @Override 123 | public Iterator iterator() { 124 | return chars.iterator(); 125 | } 126 | 127 | @Override 128 | public int size() { 129 | return chars.size(); 130 | } 131 | 132 | @Override 133 | public String toString() { 134 | return stringified; 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonGeneratorFactoryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import static org.leadpony.joy.core.Preconditions.requireNonNull; 19 | 20 | import java.io.OutputStream; 21 | import java.io.OutputStreamWriter; 22 | import java.io.Writer; 23 | import java.nio.charset.Charset; 24 | import java.nio.charset.StandardCharsets; 25 | import java.util.Map; 26 | 27 | import jakarta.json.stream.JsonGeneratorFactory; 28 | 29 | import org.leadpony.joy.api.JsonGenerator; 30 | 31 | /** 32 | * An implementation of {@link JsonGeneratorFactory}. 33 | * 34 | * @author leadpony 35 | */ 36 | class JsonGeneratorFactoryImpl extends ConfigurableFactory implements JsonGeneratorFactory { 37 | 38 | private static final String[] SUPPORTED_PROPERTIES = { 39 | JsonGenerator.PRETTY_PRINTING, 40 | JsonGenerator.INDENTATION_SIZE, 41 | JsonGenerator.TAB_INDENTATION 42 | }; 43 | 44 | private static final int DEFAULT_INDENTATION_SIZE = 4; 45 | 46 | private final boolean prettyPrinting; 47 | private final char indentationChar; 48 | private final int indentationSize; 49 | private final CharBufferFactory bufferFactory; 50 | 51 | JsonGeneratorFactoryImpl(Map config, CharBufferFactory bufferFactory) { 52 | super(config, SUPPORTED_PROPERTIES); 53 | this.bufferFactory = bufferFactory; 54 | this.prettyPrinting = containsProperty(JsonGenerator.PRETTY_PRINTING); 55 | if (containsProperty(JsonGenerator.TAB_INDENTATION)) { 56 | this.indentationChar = '\t'; 57 | this.indentationSize = 1; 58 | } else { 59 | this.indentationChar = ' '; 60 | this.indentationSize = getPropertyValue(JsonGenerator.INDENTATION_SIZE, DEFAULT_INDENTATION_SIZE); 61 | } 62 | } 63 | 64 | @Override 65 | public JsonGenerator createGenerator(Writer writer) { 66 | requireNonNull(writer, "writer"); 67 | return createConfiguredGenerator(writer); 68 | } 69 | 70 | @Override 71 | public JsonGenerator createGenerator(OutputStream out) { 72 | requireNonNull(out, "out"); 73 | Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8); 74 | return createConfiguredGenerator(writer); 75 | } 76 | 77 | @Override 78 | public JsonGenerator createGenerator(OutputStream out, Charset charset) { 79 | requireNonNull(out, "out"); 80 | requireNonNull(charset, "charset"); 81 | Writer writer = new OutputStreamWriter(out, charset); 82 | return createConfiguredGenerator(writer); 83 | } 84 | 85 | private JsonGenerator createConfiguredGenerator(Writer writer) { 86 | if (prettyPrinting) { 87 | return new PrettyJsonGenerator(writer, bufferFactory, indentationChar, indentationSize); 88 | } else { 89 | return new CompactJsonGenerator(writer, bufferFactory); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonMergePatchImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import static org.leadpony.joy.core.Preconditions.requireNonNull; 19 | 20 | import java.util.Map; 21 | 22 | import jakarta.json.JsonMergePatch; 23 | import jakarta.json.JsonObject; 24 | import jakarta.json.JsonObjectBuilder; 25 | import jakarta.json.JsonValue; 26 | import jakarta.json.JsonValue.ValueType; 27 | 28 | /** 29 | * The implementation class of {@link JsonMergePatch}. 30 | * 31 | * @author leadpony 32 | */ 33 | final class JsonMergePatchImpl implements JsonMergePatch { 34 | 35 | private final JsonValue value; 36 | 37 | private static final JsonMergePatch EMPTY_OBJECT_PATCH = new JsonMergePatchImpl(JsonValue.EMPTY_JSON_OBJECT); 38 | 39 | static JsonMergePatch of(JsonValue value) { 40 | if (value == JsonValue.EMPTY_JSON_OBJECT) { 41 | return EMPTY_OBJECT_PATCH; 42 | } 43 | return new JsonMergePatchImpl(value); 44 | } 45 | 46 | static JsonMergePatch between(JsonValue source, JsonValue target) { 47 | JsonValue value = diff(source, target); 48 | return of(value); 49 | } 50 | 51 | private JsonMergePatchImpl(JsonValue value) { 52 | this.value = value; 53 | } 54 | 55 | @Override 56 | public JsonValue apply(JsonValue target) { 57 | requireNonNull(target, "target"); 58 | return mergePatch(target, value); 59 | } 60 | 61 | @Override 62 | public JsonValue toJsonValue() { 63 | return value; 64 | } 65 | 66 | private static JsonValue mergePatch(JsonValue target, JsonValue patch) { 67 | if (patch.getValueType() == ValueType.OBJECT) { 68 | if (target.getValueType() == ValueType.OBJECT) { 69 | return mergePatch((JsonObject) target, (JsonObject) patch); 70 | } else { 71 | return removeNull((JsonObject) patch); 72 | } 73 | } else { 74 | return patch; 75 | } 76 | } 77 | 78 | private static JsonObject mergePatch(JsonObject target, JsonObject patch) { 79 | JsonObjectBuilder builder = new JsonObjectBuilderImpl(target); 80 | for (Map.Entry entry : patch.entrySet()) { 81 | final String key = entry.getKey(); 82 | JsonValue value = entry.getValue(); 83 | if (value == JsonValue.NULL) { 84 | if (target.containsKey(key)) { 85 | builder.remove(key); 86 | } 87 | } else if (target.containsKey(key)) { 88 | builder.add(key, mergePatch(target.get(key), value)); 89 | } else { 90 | if (value.getValueType() == ValueType.OBJECT) { 91 | value = removeNull((JsonObject) value); 92 | } 93 | builder.add(key, value); 94 | } 95 | } 96 | return builder.build(); 97 | } 98 | 99 | /** 100 | * Removes any property whose value is null from the object. 101 | * 102 | * @param object the object to modify. 103 | * @return modified object. 104 | */ 105 | private static JsonObject removeNull(JsonObject object) { 106 | JsonObjectBuilder builder = new JsonObjectBuilderImpl(); 107 | object.forEach((k, v) -> { 108 | if (v.getValueType() == ValueType.OBJECT) { 109 | builder.add(k, removeNull((JsonObject) v)); 110 | } else if (v != JsonValue.NULL) { 111 | builder.add(k, v); 112 | } 113 | }); 114 | return builder.build(); 115 | } 116 | 117 | private static JsonValue diff(JsonValue source, JsonValue target) { 118 | if (source.getValueType() == ValueType.OBJECT 119 | && target.getValueType() == ValueType.OBJECT) { 120 | return diff((JsonObject) source, (JsonObject) target); 121 | } else { 122 | return target; 123 | } 124 | } 125 | 126 | private static JsonObject diff(JsonObject source, JsonObject target) { 127 | JsonObjectBuilder builder = new JsonObjectBuilderImpl(); 128 | 129 | target.forEach((k, v) -> { 130 | if (source.containsKey(k)) { 131 | final JsonValue v0 = source.get(k); 132 | if (!v0.equals(v)) { 133 | builder.add(k, diff(v0, v)); 134 | } 135 | } else { 136 | builder.add(k, v); 137 | } 138 | }); 139 | 140 | source.forEach((k, v) -> { 141 | if (!target.containsKey(k)) { 142 | builder.addNull(k); 143 | } 144 | }); 145 | 146 | return builder.build(); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonNumberImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.math.BigInteger; 19 | 20 | import jakarta.json.JsonNumber; 21 | 22 | /** 23 | * The implementation of {@link JsonNumber}. 24 | * 25 | * @author leadpony 26 | */ 27 | abstract class JsonNumberImpl implements JsonNumber { 28 | 29 | @Override 30 | public ValueType getValueType() { 31 | return ValueType.NUMBER; 32 | } 33 | 34 | @Override 35 | public boolean isIntegral() { 36 | return bigDecimalValue().scale() == 0; 37 | } 38 | 39 | @Override 40 | public int intValue() { 41 | return bigDecimalValue().intValue(); 42 | } 43 | 44 | @Override 45 | public int intValueExact() { 46 | return bigDecimalValue().intValueExact(); 47 | } 48 | 49 | @Override 50 | public long longValue() { 51 | return bigDecimalValue().longValue(); 52 | } 53 | 54 | @Override 55 | public long longValueExact() { 56 | return bigDecimalValue().longValueExact(); 57 | } 58 | 59 | public BigInteger bigIntegerValue() { 60 | return bigDecimalValue().toBigInteger(); 61 | } 62 | 63 | @Override 64 | public BigInteger bigIntegerValueExact() { 65 | return bigDecimalValue().toBigIntegerExact(); 66 | } 67 | 68 | @Override 69 | public double doubleValue() { 70 | return bigDecimalValue().doubleValue(); 71 | } 72 | 73 | @Override 74 | public Number numberValue() { 75 | return bigDecimalValue(); 76 | } 77 | 78 | @Override 79 | public String toString() { 80 | return bigDecimalValue().toString(); 81 | } 82 | 83 | @Override 84 | public int hashCode() { 85 | return bigDecimalValue().hashCode(); 86 | } 87 | 88 | @Override 89 | public boolean equals(Object obj) { 90 | if (this == obj) { 91 | return true; 92 | } 93 | if (!(obj instanceof JsonNumber)) { 94 | return false; 95 | } 96 | JsonNumber other = (JsonNumber) obj; 97 | return bigDecimalValue().equals(other.bigDecimalValue()); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonObjectBuilderImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import static org.leadpony.joy.core.Preconditions.requireNonNull; 19 | 20 | import java.math.BigDecimal; 21 | import java.math.BigInteger; 22 | import java.util.Collections; 23 | import java.util.LinkedHashMap; 24 | import java.util.Map; 25 | import java.util.Optional; 26 | 27 | import jakarta.json.JsonArrayBuilder; 28 | import jakarta.json.JsonObject; 29 | import jakarta.json.JsonObjectBuilder; 30 | import jakarta.json.JsonValue; 31 | 32 | /** 33 | * An implementation of {@link JsonObjectBuilder}. 34 | * 35 | * @author leadpony 36 | */ 37 | class JsonObjectBuilderImpl implements JsonObjectBuilder { 38 | 39 | private Map properties; 40 | 41 | JsonObjectBuilderImpl() { 42 | } 43 | 44 | JsonObjectBuilderImpl(JsonObject object) { 45 | this.properties = new LinkedHashMap<>(object); 46 | } 47 | 48 | JsonObjectBuilderImpl(Map map) { 49 | Map properties = new LinkedHashMap<>(); 50 | for (Map.Entry entry : map.entrySet()) { 51 | final String key = entry.getKey(); 52 | final Object value = entry.getValue(); 53 | if (value instanceof Optional) { 54 | Optional optional = (Optional) value; 55 | if (optional.isPresent()) { 56 | properties.put(key, JsonValues.valueOf(optional.get())); 57 | } 58 | } else { 59 | properties.put(key, JsonValues.valueOf(value)); 60 | } 61 | } 62 | this.properties = properties; 63 | } 64 | 65 | @Override 66 | public JsonObjectBuilder add(String name, JsonValue value) { 67 | requireNonNull(name, "name"); 68 | requireNonNull(value, "value"); 69 | return put(name, value); 70 | } 71 | 72 | @Override 73 | public JsonObjectBuilder add(String name, String value) { 74 | requireNonNull(name, "name"); 75 | requireNonNull(value, "value"); 76 | return put(name, JsonValues.valueOf(value)); 77 | } 78 | 79 | @Override 80 | public JsonObjectBuilder add(String name, BigInteger value) { 81 | requireNonNull(name, "name"); 82 | requireNonNull(value, "value"); 83 | return put(name, JsonValues.valueOf(value)); 84 | } 85 | 86 | @Override 87 | public JsonObjectBuilder add(String name, BigDecimal value) { 88 | requireNonNull(name, "name"); 89 | requireNonNull(value, "value"); 90 | return put(name, JsonValues.valueOf(value)); 91 | } 92 | 93 | @Override 94 | public JsonObjectBuilder add(String name, int value) { 95 | requireNonNull(name, "name"); 96 | return put(name, JsonValues.valueOf(value)); 97 | } 98 | 99 | @Override 100 | public JsonObjectBuilder add(String name, long value) { 101 | requireNonNull(name, "name"); 102 | return put(name, JsonValues.valueOf(value)); 103 | } 104 | 105 | @Override 106 | public JsonObjectBuilder add(String name, double value) { 107 | requireNonNull(name, "name"); 108 | return put(name, JsonValues.valueOf(value)); 109 | } 110 | 111 | @Override 112 | public JsonObjectBuilder add(String name, boolean value) { 113 | requireNonNull(name, "name"); 114 | return put(name, JsonValues.valueOf(value)); 115 | } 116 | 117 | @Override 118 | public JsonObjectBuilder addNull(String name) { 119 | requireNonNull(name, "name"); 120 | return put(name, JsonValue.NULL); 121 | } 122 | 123 | @Override 124 | public JsonObjectBuilder add(String name, JsonObjectBuilder builder) { 125 | requireNonNull(name, "name"); 126 | requireNonNull(builder, "builder"); 127 | return put(name, builder.build()); 128 | } 129 | 130 | @Override 131 | public JsonObjectBuilder add(String name, JsonArrayBuilder builder) { 132 | requireNonNull(name, "name"); 133 | requireNonNull(builder, "builder"); 134 | return put(name, builder.build()); 135 | } 136 | 137 | @Override 138 | public JsonObjectBuilder addAll(JsonObjectBuilder builder) { 139 | requireNonNull(builder, "builder"); 140 | requireProperties().putAll(builder.build()); 141 | return this; 142 | } 143 | 144 | @Override 145 | public JsonObjectBuilder remove(String name) { 146 | requireNonNull(name, "name"); 147 | requireProperties().remove(name); 148 | return this; 149 | } 150 | 151 | @Override 152 | public JsonObject build() { 153 | if (properties == null) { 154 | return JsonValue.EMPTY_JSON_OBJECT; 155 | } 156 | JsonObject object = new JsonObjectImpl(Collections.unmodifiableMap(properties)); 157 | properties = null; 158 | return object; 159 | } 160 | 161 | private Map requireProperties() { 162 | if (properties == null) { 163 | properties = new LinkedHashMap<>(); 164 | } 165 | return properties; 166 | } 167 | 168 | private JsonObjectBuilder put(String name, JsonValue value) { 169 | requireProperties().put(name, value); 170 | return this; 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonObjectImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import static org.leadpony.joy.core.Preconditions.requireNonNull; 19 | 20 | import java.util.AbstractMap; 21 | import java.util.Map; 22 | import java.util.Set; 23 | 24 | import jakarta.json.JsonArray; 25 | import jakarta.json.JsonNumber; 26 | import jakarta.json.JsonObject; 27 | import jakarta.json.JsonString; 28 | import jakarta.json.JsonValue; 29 | 30 | /** 31 | * An implementation of {@link JsonObject}. 32 | * 33 | * @author leadpony 34 | */ 35 | class JsonObjectImpl extends AbstractMap implements JsonObject { 36 | 37 | private final Map properties; 38 | 39 | JsonObjectImpl(Map properties) { 40 | this.properties = properties; 41 | } 42 | 43 | /* As a JsonValue */ 44 | 45 | @Override 46 | public ValueType getValueType() { 47 | return ValueType.OBJECT; 48 | } 49 | 50 | @Override 51 | public JsonObject asJsonObject() { 52 | return this; 53 | } 54 | 55 | /* As a JsonStructure */ 56 | 57 | @Override 58 | public JsonValue getValue(String jsonPointer) { 59 | requireNonNull(jsonPointer, "jsonPointer"); 60 | return JsonPointerImpl.parse(jsonPointer).getValue(this); 61 | } 62 | 63 | /* As a JsonObject */ 64 | 65 | @Override 66 | public JsonArray getJsonArray(String name) { 67 | return (JsonArray) get(name); 68 | } 69 | 70 | @Override 71 | public JsonObject getJsonObject(String name) { 72 | return (JsonObject) get(name); 73 | } 74 | 75 | @Override 76 | public JsonNumber getJsonNumber(String name) { 77 | return (JsonNumber) get(name); 78 | } 79 | 80 | @Override 81 | public JsonString getJsonString(String name) { 82 | return (JsonString) get(name); 83 | } 84 | 85 | @Override 86 | public String getString(String name) { 87 | return getJsonString(name).getString(); 88 | } 89 | 90 | @Override 91 | public String getString(String name, String defaultValue) { 92 | JsonValue value = get(name); 93 | if (value != null && value.getValueType() == ValueType.STRING) { 94 | return ((JsonString) value).getString(); 95 | } else { 96 | return defaultValue; 97 | } 98 | } 99 | 100 | @Override 101 | public int getInt(String name) { 102 | return getJsonNumber(name).intValue(); 103 | } 104 | 105 | @Override 106 | public int getInt(String name, int defaultValue) { 107 | JsonValue value = get(name); 108 | if (value != null && value.getValueType() == ValueType.NUMBER) { 109 | return ((JsonNumber) value).intValue(); 110 | } else { 111 | return defaultValue; 112 | } 113 | } 114 | 115 | @Override 116 | public boolean getBoolean(String name) { 117 | JsonValue value = get(name); 118 | if (value == null) { 119 | throw new NullPointerException(); 120 | } 121 | if (value == JsonValue.TRUE) { 122 | return true; 123 | } else if (value == JsonValue.FALSE) { 124 | return false; 125 | } else { 126 | throw new ClassCastException(); 127 | } 128 | } 129 | 130 | @Override 131 | public boolean getBoolean(String name, boolean defaultValue) { 132 | JsonValue value = get(name); 133 | if (value == JsonValue.TRUE) { 134 | return true; 135 | } else if (value == JsonValue.FALSE) { 136 | return false; 137 | } else { 138 | return defaultValue; 139 | } 140 | } 141 | 142 | @Override 143 | public boolean isNull(String name) { 144 | return get(name).equals(JsonValue.NULL); 145 | } 146 | 147 | /* As a Map */ 148 | 149 | @Override 150 | public Set> entrySet() { 151 | return properties.entrySet(); 152 | } 153 | 154 | @Override 155 | public int size() { 156 | return properties.size(); 157 | } 158 | 159 | @Override 160 | public boolean containsValue(Object value) { 161 | return properties.containsValue(value); 162 | } 163 | 164 | @Override 165 | public boolean containsKey(Object key) { 166 | return properties.containsKey(key); 167 | } 168 | 169 | @Override 170 | public JsonValue get(Object key) { 171 | return properties.get(key); 172 | } 173 | 174 | @Override 175 | public String toString() { 176 | try (SimpleJsonGenerator g = new SimpleJsonGenerator()) { 177 | g.write(this); 178 | return g.toString(); 179 | } 180 | } 181 | 182 | private JsonValue get(String name) { 183 | requireNonNull(name, "name"); 184 | return properties.get(name); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonParserFactoryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import static org.leadpony.joy.core.Preconditions.requireNonNull; 19 | 20 | import java.io.InputStream; 21 | import java.io.InputStreamReader; 22 | import java.io.Reader; 23 | import java.nio.charset.Charset; 24 | import java.util.Map; 25 | 26 | import jakarta.json.stream.JsonParser; 27 | import jakarta.json.stream.JsonParserFactory; 28 | 29 | /** 30 | * An implementation of {@link JsonParserFactory}. 31 | * 32 | * @author leadpony 33 | */ 34 | class JsonParserFactoryImpl extends AbstractJsonParserFactory { 35 | 36 | private final CharBufferFactory bufferFactory; 37 | 38 | JsonParserFactoryImpl(Map config, CharBufferFactory bufferFactory) { 39 | super(config); 40 | this.bufferFactory = bufferFactory; 41 | } 42 | 43 | @Override 44 | public JsonParser createParser(Reader reader) { 45 | requireNonNull(reader, "reader"); 46 | return new BasicJsonParser(reader, bufferFactory); 47 | } 48 | 49 | @Override 50 | public JsonParser createParser(InputStream in) { 51 | requireNonNull(in, "in"); 52 | Reader reader = createStreamReader(in); 53 | return new BasicJsonParser(reader, bufferFactory); 54 | } 55 | 56 | @Override 57 | public JsonParser createParser(InputStream in, Charset charset) { 58 | requireNonNull(in, "in"); 59 | requireNonNull(charset, "charset"); 60 | Reader reader = new InputStreamReader(in, charset); 61 | return new BasicJsonParser(reader, bufferFactory); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonPatchBuilderImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import static org.leadpony.joy.core.Preconditions.requireNonNull; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | import jakarta.json.JsonArray; 24 | import jakarta.json.JsonArrayBuilder; 25 | import jakarta.json.JsonObject; 26 | import jakarta.json.JsonObjectBuilder; 27 | import jakarta.json.JsonPatch; 28 | import jakarta.json.JsonPatchBuilder; 29 | import jakarta.json.JsonValue; 30 | 31 | /** 32 | * @author leadpony 33 | */ 34 | class JsonPatchBuilderImpl implements JsonPatchBuilder { 35 | 36 | private List operations; 37 | 38 | JsonPatchBuilderImpl() { 39 | } 40 | 41 | JsonPatchBuilderImpl(JsonArray array) { 42 | this.operations = PatchOperation.asOperations(array); 43 | } 44 | 45 | @Override 46 | public final JsonPatchBuilder add(String path, JsonValue value) { 47 | requireNonNull(path, "path"); 48 | requireNonNull(path, "value"); 49 | return append(new PatchOperation.Add(path, value)); 50 | } 51 | 52 | @Override 53 | public final JsonPatchBuilder add(String path, String value) { 54 | requireNonNull(path, "path"); 55 | requireNonNull(path, "value"); 56 | return append(new PatchOperation.Add(path, JsonValues.valueOf(value))); 57 | } 58 | 59 | @Override 60 | public final JsonPatchBuilder add(String path, int value) { 61 | requireNonNull(path, "path"); 62 | return append(new PatchOperation.Add(path, JsonValues.valueOf(value))); 63 | } 64 | 65 | @Override 66 | public final JsonPatchBuilder add(String path, boolean value) { 67 | requireNonNull(path, "path"); 68 | return append(new PatchOperation.Add(path, JsonValues.valueOf(value))); 69 | } 70 | 71 | @Override 72 | public final JsonPatchBuilder remove(String path) { 73 | requireNonNull(path, "path"); 74 | return append(new PatchOperation.Remove(path)); 75 | } 76 | 77 | @Override 78 | public final JsonPatchBuilder replace(String path, JsonValue value) { 79 | requireNonNull(path, "path"); 80 | requireNonNull(path, "value"); 81 | return append(new PatchOperation.Replace(path, value)); 82 | } 83 | 84 | @Override 85 | public final JsonPatchBuilder replace(String path, String value) { 86 | requireNonNull(path, "path"); 87 | requireNonNull(path, "value"); 88 | return append(new PatchOperation.Replace(path, JsonValues.valueOf(value))); 89 | } 90 | 91 | @Override 92 | public final JsonPatchBuilder replace(String path, int value) { 93 | requireNonNull(path, "path"); 94 | return append(new PatchOperation.Replace(path, JsonValues.valueOf(value))); 95 | } 96 | 97 | @Override 98 | public final JsonPatchBuilder replace(String path, boolean value) { 99 | requireNonNull(path, "path"); 100 | return append(new PatchOperation.Replace(path, JsonValues.valueOf(value))); 101 | } 102 | 103 | @Override 104 | public final JsonPatchBuilder move(String path, String from) { 105 | requireNonNull(path, "path"); 106 | requireNonNull(from, "from"); 107 | return append(new PatchOperation.Move(path, from)); 108 | } 109 | 110 | @Override 111 | public final JsonPatchBuilder copy(String path, String from) { 112 | requireNonNull(path, "path"); 113 | requireNonNull(from, "from"); 114 | return append(new PatchOperation.Copy(path, from)); 115 | } 116 | 117 | @Override 118 | public final JsonPatchBuilder test(String path, JsonValue value) { 119 | requireNonNull(path, "path"); 120 | requireNonNull(value, "value"); 121 | return append(new PatchOperation.Test(path, value)); 122 | } 123 | 124 | @Override 125 | public final JsonPatchBuilder test(String path, String value) { 126 | requireNonNull(path, "path"); 127 | requireNonNull(value, "value"); 128 | return append(new PatchOperation.Test(path, JsonValues.valueOf(value))); 129 | } 130 | 131 | @Override 132 | public final JsonPatchBuilder test(String path, int value) { 133 | requireNonNull(path, "path"); 134 | return append(new PatchOperation.Test(path, JsonValues.valueOf(value))); 135 | } 136 | 137 | @Override 138 | public final JsonPatchBuilder test(String path, boolean value) { 139 | requireNonNull(path, "path"); 140 | return append(new PatchOperation.Test(path, JsonValues.valueOf(value))); 141 | } 142 | 143 | @Override 144 | public final JsonPatch build() { 145 | JsonPatch patch = JsonPatchImpl.of(buildAsArray(), operations); 146 | this.operations = null; 147 | return patch; 148 | } 149 | 150 | private JsonPatchBuilder append(PatchOperation op) { 151 | if (operations == null) { 152 | operations = new ArrayList<>(); 153 | } 154 | operations.add(op); 155 | return this; 156 | } 157 | 158 | private JsonArray buildAsArray() { 159 | if (operations == null) { 160 | return JsonValue.EMPTY_JSON_ARRAY; 161 | } 162 | JsonArrayBuilder arrayBuilder = new JsonArrayBuilderImpl(); 163 | JsonObjectBuilder objectBuilder = new JsonObjectBuilderImpl(); 164 | for (PatchOperation operation : operations) { 165 | JsonObject object = operation.toJsonObject(objectBuilder); 166 | arrayBuilder.add(object); 167 | } 168 | return arrayBuilder.build(); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonPatchImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.util.Collections; 19 | import java.util.List; 20 | 21 | import jakarta.json.JsonArray; 22 | import jakarta.json.JsonPatch; 23 | import jakarta.json.JsonStructure; 24 | import jakarta.json.JsonValue; 25 | 26 | /** 27 | * The implementation of {@link JsonPatch}. 28 | * 29 | * @author leadpony 30 | */ 31 | final class JsonPatchImpl implements JsonPatch { 32 | 33 | private final JsonArray array; 34 | private final List operations; 35 | 36 | /* 37 | * An empty JSON patch. 38 | */ 39 | private static final JsonPatch EMPTY = new JsonPatchImpl( 40 | JsonValue.EMPTY_JSON_ARRAY, Collections.emptyList()); 41 | 42 | static JsonPatch of(JsonArray array) { 43 | return of(array, PatchOperation.asOperations(array)); 44 | } 45 | 46 | static JsonPatch of(JsonArray array, List operations) { 47 | if (array.isEmpty()) { 48 | return EMPTY; 49 | } else { 50 | return new JsonPatchImpl(array, operations); 51 | } 52 | } 53 | 54 | /** 55 | * Returns an empty JSON patch. 56 | * 57 | * @return an empty JSON patch. 58 | */ 59 | static JsonPatch empty() { 60 | return EMPTY; 61 | } 62 | 63 | /** 64 | * Constructs this patch. 65 | * 66 | * @param array the JSON array representing this patch. 67 | * @param operations the list of operations. 68 | */ 69 | private JsonPatchImpl(JsonArray array, List operations) { 70 | this.array = array; 71 | this.operations = operations; 72 | } 73 | 74 | @Override 75 | public T apply(T target) { 76 | for (PatchOperation operation : this.operations) { 77 | target = operation.apply(target); 78 | } 79 | return target; 80 | } 81 | 82 | @Override 83 | public JsonArray toJsonArray() { 84 | return array; 85 | } 86 | 87 | /* As an Object */ 88 | 89 | @Override 90 | public int hashCode() { 91 | return array.hashCode(); 92 | } 93 | 94 | @Override 95 | public boolean equals(Object obj) { 96 | if (this == obj) { 97 | return true; 98 | } 99 | if (obj == null) { 100 | return false; 101 | } 102 | if (!(obj instanceof JsonPatch)) { 103 | return false; 104 | } 105 | JsonPatch other = (JsonPatch) obj; 106 | return array.equals(other.toJsonArray()); 107 | } 108 | 109 | @Override 110 | public String toString() { 111 | return array.toString(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonReaderFactoryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.io.InputStream; 19 | import java.io.Reader; 20 | import java.nio.charset.Charset; 21 | import java.util.Map; 22 | 23 | import jakarta.json.JsonReader; 24 | import jakarta.json.JsonReaderFactory; 25 | import jakarta.json.stream.JsonParser; 26 | import jakarta.json.stream.JsonParserFactory; 27 | 28 | /** 29 | * An implementation of {@link JsonReaderFactory}. 30 | * 31 | * @author leadpony 32 | */ 33 | class JsonReaderFactoryImpl extends ConfigurableFactory implements JsonReaderFactory { 34 | 35 | private final JsonParserFactory parserFactory; 36 | 37 | JsonReaderFactoryImpl(Map config, JsonParserFactory parserFactory) { 38 | super(config); 39 | this.parserFactory = parserFactory; 40 | } 41 | 42 | @Override 43 | public JsonReader createReader(Reader reader) { 44 | JsonParser parser = getParserFactory().createParser(reader); 45 | return new JsonReaderImpl(parser); 46 | } 47 | 48 | @Override 49 | public JsonReader createReader(InputStream in) { 50 | JsonParser parser = getParserFactory().createParser(in); 51 | return new JsonReaderImpl(parser); 52 | } 53 | 54 | @Override 55 | public JsonReader createReader(InputStream in, Charset charset) { 56 | JsonParser parser = getParserFactory().createParser(in, charset); 57 | return new JsonReaderImpl(parser); 58 | } 59 | 60 | private JsonParserFactory getParserFactory() { 61 | return parserFactory; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonReaderImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.util.Set; 19 | 20 | import jakarta.json.JsonArray; 21 | import jakarta.json.JsonObject; 22 | import jakarta.json.JsonReader; 23 | import jakarta.json.JsonStructure; 24 | import jakarta.json.JsonValue; 25 | import jakarta.json.stream.JsonLocation; 26 | import jakarta.json.stream.JsonParser; 27 | import jakarta.json.stream.JsonParser.Event; 28 | import jakarta.json.stream.JsonParsingException; 29 | 30 | /** 31 | * An implementation of {@link JsonReader}. 32 | * 33 | * @author leadpony 34 | */ 35 | class JsonReaderImpl implements JsonReader { 36 | 37 | private final JsonParser parser; 38 | private boolean alreadyRead; 39 | private boolean alreadyClosed; 40 | 41 | JsonReaderImpl(JsonParser parser) { 42 | this.parser = parser; 43 | } 44 | 45 | @Override 46 | public JsonStructure read() { 47 | checkState(); 48 | alreadyRead = true; 49 | if (parser.hasNext()) { 50 | Event event = parser.next(); 51 | switch (event) { 52 | case START_ARRAY: 53 | return parser.getArray(); 54 | case START_OBJECT: 55 | return parser.getObject(); 56 | default: 57 | break; 58 | } 59 | } 60 | throw newUnexpectedEndException(ParserEventSet.START_STRUCTURE); 61 | } 62 | 63 | @Override 64 | public JsonArray readArray() { 65 | checkState(); 66 | alreadyRead = true; 67 | if (parser.hasNext()) { 68 | Event event = parser.next(); 69 | if (event == Event.START_ARRAY) { 70 | return parser.getArray(); 71 | } 72 | } 73 | throw newUnexpectedEndException(ParserEventSet.START_ARRAY); 74 | } 75 | 76 | @Override 77 | public JsonObject readObject() { 78 | checkState(); 79 | alreadyRead = true; 80 | if (parser.hasNext()) { 81 | Event event = parser.next(); 82 | if (event == Event.START_OBJECT) { 83 | return parser.getObject(); 84 | } 85 | } 86 | throw newUnexpectedEndException(ParserEventSet.START_OBJECT); 87 | } 88 | 89 | @Override 90 | public JsonValue readValue() { 91 | checkState(); 92 | alreadyRead = true; 93 | if (parser.hasNext()) { 94 | parser.next(); 95 | return parser.getValue(); 96 | } 97 | throw newUnexpectedEndException( 98 | ParserEventSet.VALUES); 99 | } 100 | 101 | @Override 102 | public void close() { 103 | if (alreadyClosed) { 104 | return; 105 | } 106 | alreadyClosed = true; 107 | parser.close(); 108 | } 109 | 110 | private void checkState() { 111 | if (alreadyRead || alreadyClosed) { 112 | throw new IllegalStateException(); 113 | } 114 | } 115 | 116 | private JsonParsingException newUnexpectedEndException(Set expected) { 117 | JsonLocation location = parser.getLocation(); 118 | return new JsonParsingException( 119 | Message.thatUnexpectedEndOfInputWasReachedBeforeEvents(location, expected), 120 | location); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonStreams.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.core; 18 | 19 | import java.util.AbstractMap; 20 | import java.util.Map; 21 | import java.util.Spliterator; 22 | import java.util.Spliterators; 23 | import java.util.Map.Entry; 24 | import java.util.function.Consumer; 25 | import java.util.stream.Stream; 26 | import java.util.stream.StreamSupport; 27 | 28 | import jakarta.json.JsonValue; 29 | import jakarta.json.stream.JsonLocation; 30 | import jakarta.json.stream.JsonParser; 31 | import jakarta.json.stream.JsonParsingException; 32 | import jakarta.json.stream.JsonParser.Event; 33 | 34 | /** 35 | * A helper class for generating streams of JSON values. 36 | * 37 | * @author leadpony 38 | */ 39 | final class JsonStreams { 40 | 41 | static Stream arrayStream(JsonParser parser) { 42 | Spliterator spliterator = new AbstractSpliterator() { 43 | @Override 44 | public boolean tryAdvance(Consumer action) { 45 | if (parser.hasNext() && parser.next() != Event.END_ARRAY) { 46 | action.accept(parser.getValue()); 47 | return true; 48 | } else { 49 | return false; 50 | } 51 | } 52 | }; 53 | return StreamSupport.stream(spliterator, false); 54 | } 55 | 56 | static Stream> objectStream(JsonParser parser) { 57 | Spliterator> spliterator = new AbstractSpliterator>() { 58 | 59 | @Override 60 | public boolean tryAdvance(Consumer> action) { 61 | if (!parser.hasNext()) { 62 | return false; 63 | } 64 | Event event = parser.next(); 65 | if (event == Event.END_OBJECT) { 66 | return false; 67 | } else if (event == Event.KEY_NAME) { 68 | String key = parser.getString(); 69 | if (parser.hasNext()) { 70 | parser.next(); 71 | JsonValue value = parser.getValue(); 72 | action.accept(new AbstractMap.SimpleImmutableEntry<>(key, value)); 73 | return true; 74 | } else { 75 | JsonLocation location = parser.getLocation(); 76 | String message = Message.thatUnexpectedEndOfInputWasReachedBeforeEvents( 77 | location, ParserEventSet.VALUES); 78 | throw new JsonParsingException(message, location); 79 | } 80 | } else { 81 | // This never happen. 82 | throw new IllegalStateException(); 83 | } 84 | } 85 | }; 86 | return StreamSupport.stream(spliterator, false); 87 | } 88 | 89 | static Stream valueStream(JsonParser parser) { 90 | Spliterator spliterator = new AbstractSpliterator() { 91 | 92 | @Override 93 | public boolean tryAdvance(Consumer action) { 94 | if (parser.hasNext()) { 95 | parser.next(); 96 | action.accept(parser.getValue()); 97 | return true; 98 | } else { 99 | return false; 100 | } 101 | } 102 | }; 103 | return StreamSupport.stream(spliterator, false); 104 | } 105 | 106 | private JsonStreams() { 107 | } 108 | 109 | /** 110 | * A skeletal implementation of {@link Spliterator}. 111 | * @author leadpony 112 | * 113 | * @param the type of stream element. 114 | */ 115 | private abstract static class AbstractSpliterator extends Spliterators.AbstractSpliterator { 116 | 117 | protected AbstractSpliterator() { 118 | super(Long.MAX_VALUE, Spliterator.ORDERED); 119 | } 120 | 121 | @Override 122 | public Spliterator trySplit() { 123 | // this spliterator cannot be split 124 | return null; 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonStringBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.math.BigDecimal; 19 | import java.math.BigInteger; 20 | import java.util.Arrays; 21 | 22 | /** 23 | * @author leadpony 24 | */ 25 | class JsonStringBuilder { 26 | 27 | protected char[] writeBuffer; 28 | protected int writePos; 29 | 30 | protected JsonStringBuilder() { 31 | this(new char[16]); 32 | } 33 | 34 | protected JsonStringBuilder(char[] buffer) { 35 | this.writeBuffer = buffer; 36 | } 37 | 38 | final JsonStringBuilder append(String string) { 39 | final int end = string.length(); 40 | int last = 0; 41 | for (int i = 0; i < end; i++) { 42 | char c = string.charAt(i); 43 | if (c < 0x20 || c == '"' || c == '\\') { 44 | if (last < i) { 45 | appendString(string, last, i); 46 | } 47 | switch (c) { 48 | case '"': 49 | append('\\').append('"'); 50 | break; 51 | case '\\': 52 | append('\\').append('\\'); 53 | break; 54 | default: 55 | appendString(JsonChar.escape(c)); 56 | break; 57 | } 58 | last = i + 1; 59 | } 60 | } 61 | 62 | if (last < end) { 63 | appendString(string, last, end); 64 | } 65 | 66 | return this; 67 | } 68 | 69 | final JsonStringBuilder append(char c) { 70 | if (writePos >= writeBuffer.length) { 71 | refreshBuffer(writePos); 72 | } 73 | writeBuffer[writePos++] = c; 74 | return this; 75 | } 76 | 77 | final JsonStringBuilder append(char c, int count) { 78 | while (count-- > 0) { 79 | if (writePos >= writeBuffer.length) { 80 | refreshBuffer(writePos); 81 | } 82 | writeBuffer[writePos++] = c; 83 | } 84 | return this; 85 | } 86 | 87 | final JsonStringBuilder append(BigInteger value) { 88 | return appendString(value.toString()); 89 | } 90 | 91 | final JsonStringBuilder append(BigDecimal value) { 92 | return appendString(value.toString()); 93 | } 94 | 95 | final JsonStringBuilder append(int value) { 96 | return appendString(String.valueOf(value)); 97 | } 98 | 99 | final JsonStringBuilder append(long value) { 100 | return appendString(String.valueOf(value)); 101 | } 102 | 103 | final JsonStringBuilder append(double value) { 104 | return appendString(String.valueOf(value)); 105 | } 106 | 107 | final JsonStringBuilder append(boolean value) { 108 | return appendString(value ? "true" : "false"); 109 | } 110 | 111 | final JsonStringBuilder appendNull() { 112 | return appendString("null"); 113 | } 114 | 115 | @Override 116 | public final String toString() { 117 | return new String(writeBuffer, 0, writePos); 118 | } 119 | 120 | private JsonStringBuilder appendString(String string) { 121 | return appendString(string, 0, string.length()); 122 | } 123 | 124 | private JsonStringBuilder appendString(String string, int start, int end) { 125 | char[] writeBuffer = this.writeBuffer; 126 | int writePos = this.writePos; 127 | 128 | int i = start; 129 | while (i < end) { 130 | if (writePos >= writeBuffer.length) { 131 | refreshBuffer(writePos); 132 | writeBuffer = this.writeBuffer; 133 | writePos = this.writePos; 134 | } 135 | int charsToCopy = end - i; 136 | if (writePos + charsToCopy > writeBuffer.length) { 137 | charsToCopy = writeBuffer.length - writePos; 138 | } 139 | string.getChars(i, i + charsToCopy, writeBuffer, writePos); 140 | i += charsToCopy; 141 | writePos += charsToCopy; 142 | } 143 | 144 | this.writePos = writePos; 145 | 146 | return this; 147 | } 148 | 149 | protected void refreshBuffer(int pos) { 150 | final int newBufferSize = writeBuffer.length * 2; 151 | writeBuffer = Arrays.copyOf(writeBuffer, newBufferSize); 152 | writePos = pos; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonStringImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import jakarta.json.JsonString; 19 | 20 | /** 21 | * @author leadpony 22 | */ 23 | class JsonStringImpl implements JsonString { 24 | 25 | static final JsonString EMPTY = new JsonStringImpl("") { 26 | @Override 27 | public String toString() { 28 | return "\"\""; 29 | } 30 | }; 31 | 32 | private final String value; 33 | 34 | JsonStringImpl(String value) { 35 | this.value = value; 36 | } 37 | 38 | @Override 39 | public ValueType getValueType() { 40 | return ValueType.STRING; 41 | } 42 | 43 | @Override 44 | public String getString() { 45 | return value; 46 | } 47 | 48 | @Override 49 | public CharSequence getChars() { 50 | return value; 51 | } 52 | 53 | @Override 54 | public int hashCode() { 55 | return getString().hashCode(); 56 | } 57 | 58 | @Override 59 | public boolean equals(Object obj) { 60 | if (this == obj) { 61 | return true; 62 | } else if (!(obj instanceof JsonString)) { 63 | return false; 64 | } 65 | JsonString other = (JsonString) obj; 66 | return getString().equals(other.getString()); 67 | } 68 | 69 | @Override 70 | public String toString() { 71 | StringBuilder b = new StringBuilder("\""); 72 | String value = this.value; 73 | final int length = value.length(); 74 | int lastStart = 0; 75 | for (int i = 0; i < length; i++) { 76 | char c = value.charAt(i); 77 | if (c < 0x20 || c == '"' || c == '\\') { 78 | if (lastStart < i) { 79 | b.append(value, lastStart, i); 80 | } 81 | switch (c) { 82 | case '"': // quotation mark 83 | b.append('\\').append('"'); 84 | break; 85 | case '\\': // reverse solidus 86 | b.append('\\').append('\\'); 87 | break; 88 | default: 89 | b.append(JsonChar.escape(c)); 90 | break; 91 | } 92 | lastStart = i + 1; 93 | } 94 | } 95 | if (lastStart < length) { 96 | b.append(value, lastStart, length); 97 | } 98 | return b.append('"').toString(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonWriterFactoryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import static org.leadpony.joy.core.Preconditions.requireNonNull; 19 | 20 | import java.io.OutputStream; 21 | import java.io.OutputStreamWriter; 22 | import java.io.Writer; 23 | import java.nio.charset.Charset; 24 | import java.nio.charset.StandardCharsets; 25 | import java.util.Map; 26 | 27 | import jakarta.json.JsonWriter; 28 | import jakarta.json.JsonWriterFactory; 29 | import jakarta.json.stream.JsonGenerator; 30 | 31 | /** 32 | * @author leadpony 33 | */ 34 | class JsonWriterFactoryImpl extends JsonGeneratorFactoryImpl implements JsonWriterFactory { 35 | 36 | JsonWriterFactoryImpl(Map config, CharBufferFactory bufferFactory) { 37 | super(config, bufferFactory); 38 | } 39 | 40 | @Override 41 | public JsonWriter createWriter(Writer writer) { 42 | requireNonNull(writer, "writer"); 43 | JsonGenerator generator = createGenerator(writer); 44 | return new JsonWriterImpl(generator); 45 | } 46 | 47 | @Override 48 | public JsonWriter createWriter(OutputStream out) { 49 | requireNonNull(out, "out"); 50 | Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8); 51 | JsonGenerator generator = createGenerator(writer); 52 | return new JsonWriterImpl(generator); 53 | } 54 | 55 | @Override 56 | public JsonWriter createWriter(OutputStream out, Charset charset) { 57 | requireNonNull(out, "out"); 58 | requireNonNull(charset, "charset"); 59 | Writer writer = new OutputStreamWriter(out, charset); 60 | JsonGenerator generator = createGenerator(writer); 61 | return new JsonWriterImpl(generator); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/JsonWriterImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import static org.leadpony.joy.core.Preconditions.requireNonNull; 19 | 20 | import java.util.Map; 21 | 22 | import jakarta.json.JsonArray; 23 | import jakarta.json.JsonObject; 24 | import jakarta.json.JsonStructure; 25 | import jakarta.json.JsonValue; 26 | import jakarta.json.JsonWriter; 27 | import jakarta.json.JsonValue.ValueType; 28 | import jakarta.json.stream.JsonGenerator; 29 | 30 | /** 31 | * @author leadpony 32 | */ 33 | class JsonWriterImpl implements JsonWriter { 34 | 35 | private final JsonGenerator generator; 36 | 37 | private boolean alreadyWritten; 38 | private boolean alreadyClosed; 39 | 40 | JsonWriterImpl(JsonGenerator generator) { 41 | this.generator = generator; 42 | } 43 | 44 | @Override 45 | public void writeArray(JsonArray array) { 46 | requireNonNull(array, "array"); 47 | checkState(); 48 | 49 | alreadyWritten = true; 50 | 51 | generator.writeStartArray(); 52 | for (JsonValue item : array) { 53 | generator.write(item); 54 | } 55 | generator.writeEnd(); 56 | generator.flush(); 57 | } 58 | 59 | @Override 60 | public void writeObject(JsonObject object) { 61 | requireNonNull(object, "object"); 62 | checkState(); 63 | 64 | alreadyWritten = true; 65 | 66 | generator.writeStartObject(); 67 | for (Map.Entry property : object.entrySet()) { 68 | generator.writeKey(property.getKey()); 69 | generator.write(property.getValue()); 70 | } 71 | generator.writeEnd(); 72 | generator.flush(); 73 | } 74 | 75 | @Override 76 | public void write(JsonStructure value) { 77 | requireNonNull(value, "value"); 78 | if (value.getValueType() == ValueType.ARRAY) { 79 | writeArray((JsonArray) value); 80 | } else { 81 | writeObject((JsonObject) value); 82 | } 83 | } 84 | 85 | @Override 86 | public void write(JsonValue value) { 87 | requireNonNull(value, "value"); 88 | checkState(); 89 | alreadyWritten = true; 90 | generator.write(value); 91 | generator.flush(); 92 | } 93 | 94 | @Override 95 | public void close() { 96 | if (alreadyClosed) { 97 | return; 98 | } 99 | alreadyClosed = true; 100 | generator.close(); 101 | } 102 | 103 | private void checkState() { 104 | if (alreadyClosed) { 105 | throw new IllegalStateException(Message.thatWriterHasBeenAlreadyClosed()); 106 | } 107 | if (alreadyWritten) { 108 | throw new IllegalStateException(Message.thatWriterHasAlreadyWritten()); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/LongJsonNumber.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.math.BigDecimal; 19 | 20 | /** 21 | * A JSON number which holds a long integer. 22 | * 23 | * @author leadpony 24 | */ 25 | class LongJsonNumber extends JsonNumberImpl { 26 | 27 | private final long value; 28 | 29 | LongJsonNumber(long value) { 30 | this.value = value; 31 | } 32 | 33 | @Override 34 | public boolean isIntegral() { 35 | return true; 36 | } 37 | 38 | @Override 39 | public int intValue() { 40 | return (int) value; 41 | } 42 | 43 | @Override 44 | public int intValueExact() { 45 | return Math.toIntExact(value); 46 | } 47 | 48 | @Override 49 | public long longValue() { 50 | return value; 51 | } 52 | 53 | @Override 54 | public long longValueExact() { 55 | return value; 56 | } 57 | 58 | @Override 59 | public double doubleValue() { 60 | return value; 61 | } 62 | 63 | @Override 64 | public BigDecimal bigDecimalValue() { 65 | return BigDecimal.valueOf(value); 66 | } 67 | 68 | @Override 69 | public Number numberValue() { 70 | return value; 71 | } 72 | 73 | @Override 74 | public String toString() { 75 | return Long.toString(value); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/ParserEventSet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.util.AbstractSet; 19 | import java.util.Arrays; 20 | import java.util.EnumSet; 21 | import java.util.Iterator; 22 | import java.util.Set; 23 | import java.util.stream.Collectors; 24 | 25 | import jakarta.json.stream.JsonParser.Event; 26 | 27 | /** 28 | * @author leadpony 29 | * 30 | */ 31 | final class ParserEventSet extends AbstractSet { 32 | 33 | static final Set VALUES = of( 34 | Event.START_ARRAY, 35 | Event.START_OBJECT, 36 | Event.VALUE_STRING, 37 | Event.VALUE_NUMBER, 38 | Event.VALUE_TRUE, 39 | Event.VALUE_FALSE, 40 | Event.VALUE_NULL); 41 | 42 | static final Set START_ARRAY = of(Event.START_ARRAY); 43 | 44 | static final Set START_OBJECT = of(Event.START_OBJECT); 45 | 46 | static final Set START_STRUCTURE = of( 47 | Event.START_ARRAY, 48 | Event.START_OBJECT); 49 | 50 | static final Set VALUES_OR_END_ARRAY = of( 51 | Event.START_ARRAY, 52 | Event.START_OBJECT, 53 | Event.VALUE_STRING, 54 | Event.VALUE_NUMBER, 55 | Event.VALUE_TRUE, 56 | Event.VALUE_FALSE, 57 | Event.VALUE_NULL, 58 | Event.END_ARRAY); 59 | 60 | static final Set KEY_NAME_OR_END_OBJECT = of( 61 | Event.KEY_NAME, 62 | Event.END_OBJECT); 63 | 64 | static Set of(Event... events) { 65 | return new ParserEventSet(events); 66 | } 67 | 68 | private final Set events; 69 | private final String stringified; 70 | 71 | private ParserEventSet(Event... events) { 72 | EnumSet set = EnumSet.noneOf(Event.class); 73 | set.addAll(Arrays.asList(events)); 74 | this.events = set; 75 | this.stringified = stringify(set); 76 | } 77 | 78 | @Override 79 | public Iterator iterator() { 80 | return events.iterator(); 81 | } 82 | 83 | @Override 84 | public int size() { 85 | return events.size(); 86 | } 87 | 88 | @Override 89 | public String toString() { 90 | return stringified; 91 | } 92 | 93 | private String stringify(EnumSet events) { 94 | return events.stream() 95 | .map(Event::toString) 96 | .collect(Collectors.joining(",", "[", "]")); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/PooledCharBufferFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.lang.ref.WeakReference; 19 | import java.util.ArrayDeque; 20 | import java.util.Queue; 21 | 22 | /** 23 | * A char buffer factory which can keep created buffers. 24 | * 25 | * @author leadpony 26 | */ 27 | class PooledCharBufferFactory implements CharBufferFactory { 28 | 29 | private final int defaultSize; 30 | private final int maxBuffers; 31 | 32 | private final Queue> pool; 33 | 34 | PooledCharBufferFactory() { 35 | this(4096, 5); 36 | } 37 | 38 | PooledCharBufferFactory(int defaultSize, int maxBuffers) { 39 | this.defaultSize = defaultSize; 40 | this.maxBuffers = maxBuffers; 41 | this.pool = new ArrayDeque<>(); 42 | } 43 | 44 | @Override 45 | public char[] createBuffer() { 46 | char[] buffer = getBuffer(); 47 | if (buffer != null) { 48 | return buffer; 49 | } 50 | return createNewBuffer(); 51 | } 52 | 53 | @Override 54 | public void releaseBuffer(char[] buffer) { 55 | putBuffer(buffer); 56 | } 57 | 58 | private char[] createNewBuffer() { 59 | return new char[defaultSize]; 60 | } 61 | 62 | private synchronized char[] getBuffer() { 63 | while (!pool.isEmpty()) { 64 | WeakReference ref = pool.poll(); 65 | char[] buffer = ref.get(); 66 | if (buffer != null) { 67 | return buffer; 68 | } 69 | } 70 | return null; 71 | } 72 | 73 | private synchronized void putBuffer(char[] buffer) { 74 | while (pool.size() >= maxBuffers) { 75 | pool.poll(); 76 | } 77 | pool.offer(new WeakReference<>(buffer)); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/Preconditions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | /** 19 | * A utility class that checks preconditions of methods and constructors. 20 | * 21 | * @author leadpony 22 | */ 23 | public final class Preconditions { 24 | 25 | public static void requireNonNull(Object arg, String name) { 26 | if (arg == null) { 27 | throw new NullPointerException(name + " must not be null."); 28 | } 29 | } 30 | 31 | public static void requireFiniteNumber(double value) { 32 | if (Double.isNaN(value) || Double.isInfinite(value)) { 33 | throw new NumberFormatException("value must be a finite number."); 34 | } 35 | } 36 | 37 | private Preconditions() { 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/PrettyJsonGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import java.io.Writer; 19 | 20 | /** 21 | * @author leadpony 22 | */ 23 | final class PrettyJsonGenerator extends CompactJsonGenerator { 24 | 25 | private final char indentationChar; 26 | private final int indentationSize; 27 | private int indentationTotal; 28 | 29 | PrettyJsonGenerator(Writer writer, CharBufferFactory bufferFactory, char indentationChar, int indentationSize) { 30 | super(writer, bufferFactory); 31 | this.indentationChar = indentationChar; 32 | this.indentationSize = indentationSize; 33 | } 34 | 35 | @Override 36 | protected void appendOpeningBracket(char c) { 37 | super.appendOpeningBracket(c); 38 | indent(); 39 | } 40 | 41 | @Override 42 | protected void appendClosingBracket(char c) { 43 | dedent(); 44 | append('\n'); 45 | appendIndentation(); 46 | super.appendClosingBracket(c); 47 | } 48 | 49 | @Override 50 | protected void appendBreak() { 51 | append('\n'); 52 | appendIndentation(); 53 | } 54 | 55 | @Override 56 | protected void appendComma() { 57 | super.appendComma(); 58 | append('\n'); 59 | appendIndentation(); 60 | } 61 | 62 | @Override 63 | protected void appendColon() { 64 | super.appendColon(); 65 | append(' '); 66 | } 67 | 68 | private void indent() { 69 | indentationTotal += indentationSize; 70 | } 71 | 72 | private void dedent() { 73 | indentationTotal -= indentationSize; 74 | } 75 | 76 | private void appendIndentation() { 77 | append(indentationChar, indentationTotal); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/StreamReaders.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2021 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.leadpony.joy.core; 17 | 18 | import static java.nio.charset.StandardCharsets.UTF_16BE; 19 | import static java.nio.charset.StandardCharsets.UTF_16LE; 20 | import static java.nio.charset.StandardCharsets.UTF_8; 21 | 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.io.InputStreamReader; 25 | import java.io.PushbackInputStream; 26 | import java.io.Reader; 27 | import java.nio.charset.Charset; 28 | import java.nio.charset.StandardCharsets; 29 | 30 | import jakarta.json.JsonException; 31 | 32 | /** 33 | * A factory of input stream readers. 34 | * 35 | * @author leadpony 36 | */ 37 | final class StreamReaders { 38 | 39 | /** 40 | * UTF-32 Big Endian. 41 | */ 42 | private static final Charset UTF_32BE = Charset.forName("UTF-32BE"); 43 | 44 | /** 45 | * UTF-32 Little Endian. 46 | */ 47 | private static final Charset UTF_32LE = Charset.forName("UTF-32LE"); 48 | 49 | /** 50 | * The default character encoding. 51 | */ 52 | private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8; 53 | 54 | /** 55 | * Creates a reader which will read from the specified input stream. The The 56 | * character encoding of the input will be detected according to the logic 57 | * described in RFC 4627. 58 | * 59 | * @param in the original input source. 60 | * @return newly create reader. 61 | * 62 | * @see RFC 4627 63 | */ 64 | static Reader createStreamReader(InputStream in) { 65 | try { 66 | int b1 = in.read(); 67 | if (b1 < 0) { 68 | // empty 69 | return createReader(in, DEFAULT_ENCODING); 70 | } 71 | 72 | int b2 = in.read(); 73 | if (b2 < 0) { 74 | // 1 letter 75 | if (b1 == 0) { 76 | throw unknownEncodingException(); 77 | } 78 | return createReader(in, DEFAULT_ENCODING, (byte) b1); 79 | } 80 | 81 | // 2 letters or more 82 | 83 | if (b1 == 0xfe && b2 == 0xff) { 84 | // UTF-16BE with BOM 85 | return createReader(in, UTF_16BE); 86 | } 87 | 88 | int b3 = in.read(); 89 | if (b3 < 0) { 90 | // 2 letters 91 | if (b1 == 0xff && b2 == 0xfe) { 92 | return createReader(in, UTF_16LE); 93 | } else { 94 | if (b1 == 0) { 95 | return createReader(in, UTF_16BE, (byte) b1, (byte) b2); 96 | } else if (b2 == 0) { 97 | return createReader(in, UTF_16LE, (byte) b1, (byte) b2); 98 | } 99 | return createReader(in, DEFAULT_ENCODING, (byte) b1, (byte) b2); 100 | } 101 | } 102 | 103 | // 3 letters or more 104 | 105 | if (b1 == 0xef && b2 == 0xbb && b3 == 0xbf) { 106 | // UTF-8 with BOM 107 | return createReader(in, UTF_8); 108 | } 109 | 110 | int b4 = in.read(); 111 | if (b4 < 0) { 112 | // 3 letters 113 | return createReader(in, DEFAULT_ENCODING, (byte) b1, (byte) b2, (byte) b3); 114 | } 115 | 116 | // 4 letters or more 117 | 118 | if (b1 == 0 && b2 == 0 && b3 == 0xfe && b4 == 0xff) { 119 | // UTF-32BE with BOM 120 | return createReader(in, UTF_32BE); 121 | } else if (b1 == 0xff && b2 == 0xfe && b3 == 0 && b4 == 0) { 122 | // UTF-32LE with BOM 123 | return createReader(in, UTF_32LE); 124 | } else if (b1 == 0xff && b2 == 0xfe) { 125 | // UTF-16LE with BOM 126 | return createReader(in, UTF_16LE, (byte) b3, (byte) b4); 127 | } 128 | 129 | if (b1 == 0 && b3 == 0) { 130 | if (b2 == 0) { 131 | return createReader(in, UTF_32BE, (byte) b1, (byte) b2, (byte) b3, (byte) b4); 132 | } else { 133 | return createReader(in, UTF_16BE, (byte) b1, (byte) b2, (byte) b3, (byte) b4); 134 | } 135 | } else if (b2 == 0 && b4 == 0) { 136 | if (b3 == 0) { 137 | return createReader(in, UTF_32LE, (byte) b1, (byte) b2, (byte) b3, (byte) b4); 138 | } else { 139 | return createReader(in, UTF_16LE, (byte) b1, (byte) b2, (byte) b3, (byte) b4); 140 | } 141 | } 142 | 143 | return createReader(in, DEFAULT_ENCODING, (byte) b1, (byte) b2, (byte) b3, (byte) b4); 144 | 145 | } catch (IOException e) { 146 | throw new JsonException(Message.thatIOErrorOccurredWhileParserWasReading(), e); 147 | } 148 | } 149 | 150 | private static Reader createReader(InputStream in, Charset charset) { 151 | return new InputStreamReader(in, charset); 152 | } 153 | 154 | private static Reader createReader(InputStream in, Charset charset, byte... bytes) throws IOException { 155 | PushbackInputStream s = new PushbackInputStream(in, bytes.length); 156 | s.unread(bytes); 157 | return new InputStreamReader(s, charset); 158 | } 159 | 160 | private static JsonException unknownEncodingException() { 161 | return new JsonException(Message.thatCharacterEncodingCannotBeDetected()); 162 | } 163 | 164 | private StreamReaders() { 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /joy-core/src/main/java/org/leadpony/joy/core/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | /** 17 | * Provides the groundwork for Jakarta JSON Processing API (JSON-P). 18 | * 19 | * @author leadpony 20 | */ 21 | package org.leadpony.joy.core; 22 | -------------------------------------------------------------------------------- /joy-core/src/main/javadoc/jakarta.json/package-list: -------------------------------------------------------------------------------- 1 | module:jakarta.json 2 | jakarta.json 3 | jakarta.json.spi 4 | jakarta.json.stream 5 | -------------------------------------------------------------------------------- /joy-core/src/main/javadoc/java.base/package-list: -------------------------------------------------------------------------------- 1 | module:java.base 2 | java.io 3 | java.lang 4 | java.math 5 | java.net 6 | java.nio.charset 7 | java.nio.file 8 | java.util 9 | java.util.function 10 | java.util.stream -------------------------------------------------------------------------------- /joy-core/src/main/resources/META_INF/NOTICE: -------------------------------------------------------------------------------- 1 | # Joy 2 | Copyright 2019-2020 the original author or authors. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this product except in compliance with the License. 6 | You may obtain a copy of the License at 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /joy-core/src/main/resources/org/leadpony/joy/core/messages.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019-2020 the Joy Authors. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # 17 | # Common 18 | # 19 | 20 | location=[line={0},column={1},offset={2}] 21 | 22 | # 23 | # Messages for JsonParser 24 | # 25 | ParserIsInIllegalState={0} was called in illegal parser event {1}. 26 | 27 | UnexpectedCharWasFound={0} Unexpected char {1} was found. 28 | UnexpectedCharWasFoundFor={0} Unexpected char {1} was found where {2} are expected. 29 | 30 | UnexpectedEndOfInputWasReached={0} The end of input was reached. 31 | UnexpectedEndOfInputWasReachedBeforeChar={0} The end of input was reached where {1} are expected. 32 | UnexpectedEndOfInputWasReachedBeforeEvents={0} The end of input was reached. Expected events are {1}. 33 | 34 | NoMoreParserEventsWereFound=No more parser events. 35 | 36 | IOErrorOccurredWhileParserWasReading=An I/O error occurred while the parser was reading. 37 | IOErrorOccurredWhileParserWasClosing=An I/O error occurred while the parser was closing. 38 | 39 | ParserHasBeenAlreadyClosed=The parser has been already closed. 40 | 41 | CharacterEncodingCannotBeDetected=Character encoding cannot be detected automatically. 42 | 43 | # 44 | # Messages for JsonGenerator 45 | # 46 | IllegalGeneratorMethodWasCalledBeforeAll=Illegal method {0} was called at the beginning of JSON. 47 | IllegalGeneratorMethodWasCalledAfterArrayStart=Illegal method {0} was called after starting an array. 48 | IllegalGeneratorMethodWasCalledAfterArrayItem=Illegal method {0} was called after an array item. 49 | IllegalGeneratorMethodWasCalledAfterObjectStart=Illegal method {0} was called after starting an object. 50 | IllegalGeneratorMethodWasCalledAfterPropertyKey=Illegal method {0} was called after a property key. 51 | IllegalGeneratorMethodWasCalledAfterPropertyValue=Illegal method {0} was called after a property value. 52 | IllegalGeneratorMethodWasCalledAfterAll=Illegal method {0} was called after the end of JSON. 53 | 54 | GeneratorIsNotCompleted=Generated JSON is not completed. 55 | IOErrorOccurredWhileGeneratorWasWriting=An I/O error occurred while the generator was writing or flushing. 56 | IOErrorOccurredWhileGeneratorWasClosing=An I/O error occurred while the generator was closing. 57 | 58 | # 59 | # Messages for JsonWriter 60 | # 61 | WriterHasAlreadyWritten=The writer has already written a JSON value. 62 | WriterHasBeenAlreadyClosed=The writer has been already closed. 63 | 64 | # 65 | # Messages for JsonPointer 66 | # 67 | JsonPointerMustStartWithSlash=A non-empty JSON Pointer must begin with a '/'. 68 | JsonValueDoesNotExistAt=No JSON value exists at "{0}". 69 | JsonValueCannotBeAddedAt=No JSON value can be added to the array at "{0}". 70 | JsonDocumentCannotBeRemoved=The whole JSON document cannot be removed. 71 | JsonDocumentCannotBeReplaced=The whole JSON document cannot be replaced. 72 | JsonValueMustBeTheSameTypeAsTarget=The value must have the same type as the target. 73 | 74 | # 75 | # Messages for JsonPatch 76 | # 77 | JsonValueCannotBeMoved=The value at "{0}" cannot be moved to "{1}". 78 | JsonValueIsNotEqualToExpected=The value at "{0}" is not equal to the expected value. 79 | SourceAndTargetTypesDoNotMatch=The target must be the same type as the source. 80 | JsonPatchDoesNotContainOperation=The JSON patch operation must contain an "op" property. 81 | JsonPatchContainsUnknownOperation=The JSON patch contains an unknown operation "{0}". 82 | JsonPatchDoesNotContainProperty=The JSON patch operation "{0}" must contain a "{1}" property. 83 | 84 | # 85 | # Messages for JsonValue 86 | # 87 | ObjectCannotBeConvertedToJsonValue=The value of type "{0}" cannot be converted to a JSON value. 88 | -------------------------------------------------------------------------------- /joy-yaml-tests/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | 8 | 9 | org.leadpony.joy 10 | joy-parent 11 | 2.1.0 12 | 13 | 14 | joy-yaml-tests 15 | jar 16 | org.leadpony.joy.yaml.tests 17 | 18 | 19 | 14 20 | 21 | 22 | 23 | 24 | org.junit.jupiter 25 | junit-jupiter-engine 26 | test 27 | 28 | 29 | org.junit.jupiter 30 | junit-jupiter-params 31 | test 32 | 33 | 34 | org.assertj 35 | assertj-core 36 | test 37 | 38 | 39 | ${project.groupId} 40 | joy-yaml 41 | ${project.version} 42 | test 43 | 44 | 45 | org.leadpony 46 | jsonp-test-suite 47 | test 48 | 49 | 50 | 51 | 52 | 53 | 54 | org.apache.maven.plugins 55 | maven-checkstyle-plugin 56 | 57 | 58 | org.apache.maven.plugins 59 | maven-compiler-plugin 60 | 61 | --enable-preview 62 | 63 | 64 | 65 | org.apache.maven.plugins 66 | maven-surefire-plugin 67 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | release 81 | 82 | 83 | 84 | org.apache.maven.plugins 85 | maven-javadoc-plugin 86 | 87 | 88 | org.apache.maven.plugins 89 | maven-source-plugin 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/java/org/leadpony/joy/yaml/tests/IllFormedYamlTestCase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.yaml.tests; 18 | 19 | /** 20 | * @author leadpony 21 | */ 22 | public enum IllFormedYamlTestCase { 23 | KEY_IS_ARRAY("[]: 1", 2), 24 | KEY_IS_OBJECT("{}: 1", 2), 25 | ALIAS("{a: &abc 1, b: *abc}", 5); 26 | 27 | final String yaml; 28 | final int iterations; 29 | 30 | IllFormedYamlTestCase(String yaml, int iterations) { 31 | this.yaml = yaml; 32 | this.iterations = iterations; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/java/org/leadpony/joy/yaml/tests/JsonParserFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.yaml.tests; 18 | 19 | import java.io.InputStream; 20 | import java.io.InputStreamReader; 21 | import java.io.Reader; 22 | import java.io.StringReader; 23 | import java.nio.charset.Charset; 24 | import java.nio.charset.StandardCharsets; 25 | import java.util.Collections; 26 | 27 | import org.junit.jupiter.api.BeforeEach; 28 | import org.junit.jupiter.api.Nested; 29 | 30 | import jakarta.json.Json; 31 | import jakarta.json.stream.JsonParser; 32 | import jakarta.json.stream.JsonParserFactory; 33 | 34 | /** 35 | * @author leadpony 36 | */ 37 | public class JsonParserFactoryTest { 38 | 39 | private JsonParserFactory factory; 40 | 41 | @BeforeEach 42 | public void setUp() { 43 | factory = Json.createParserFactory(Collections.emptyMap()); 44 | } 45 | 46 | @Nested 47 | public class InputStreamTest extends JsonParserTest.BaseTest { 48 | 49 | @Override 50 | protected JsonParser createParser(InputStream in) { 51 | return factory.createParser(in); 52 | } 53 | } 54 | 55 | @Nested 56 | public class InputStreamAndCharsetTest extends JsonParserTest.BaseTest { 57 | 58 | @Override 59 | protected JsonParser createParser(InputStream in) { 60 | Charset charset = StandardCharsets.UTF_8; 61 | return factory.createParser(in, charset); 62 | } 63 | } 64 | 65 | @Nested 66 | public class ReaderTest extends JsonParserTest.BaseTest { 67 | 68 | @Override 69 | protected JsonParser createParser(InputStream in) { 70 | Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8); 71 | return factory.createParser(reader); 72 | } 73 | 74 | @Override 75 | protected JsonParser createParser(String json) { 76 | Reader reader = new StringReader(json); 77 | return factory.createParser(reader); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/java/org/leadpony/joy/yaml/tests/JsonReaderFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.yaml.tests; 18 | 19 | import java.io.InputStream; 20 | import java.io.InputStreamReader; 21 | import java.nio.charset.Charset; 22 | import java.nio.charset.StandardCharsets; 23 | import java.util.Collections; 24 | 25 | import org.junit.jupiter.api.BeforeEach; 26 | import org.junit.jupiter.api.Nested; 27 | 28 | import jakarta.json.Json; 29 | import jakarta.json.JsonReader; 30 | import jakarta.json.JsonReaderFactory; 31 | 32 | /** 33 | * @author leadpony 34 | */ 35 | public class JsonReaderFactoryTest { 36 | 37 | private JsonReaderFactory factory; 38 | 39 | @BeforeEach 40 | public void setUp() { 41 | factory = Json.createReaderFactory(Collections.emptyMap()); 42 | } 43 | 44 | @Nested 45 | public class InputStreamTest extends JsonReaderTest.BaseTest { 46 | 47 | @Override 48 | protected JsonReader createReader(InputStream in) { 49 | return factory.createReader(in); 50 | } 51 | } 52 | 53 | @Nested 54 | public class InputStreamAndCharsetTest extends JsonReaderTest.BaseTest { 55 | 56 | @Override 57 | protected JsonReader createReader(InputStream in) { 58 | Charset charset = StandardCharsets.UTF_8; 59 | return factory.createReader(in, charset); 60 | } 61 | } 62 | 63 | @Nested 64 | public class ReaderTest extends JsonReaderTest.BaseTest { 65 | 66 | @Override 67 | protected JsonReader createReader(InputStream in) { 68 | var source = new InputStreamReader(in, StandardCharsets.UTF_8); 69 | return factory.createReader(source); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/java/org/leadpony/joy/yaml/tests/JsonReaderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.yaml.tests; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | 21 | import java.io.BufferedReader; 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.io.InputStreamReader; 25 | import java.io.StringWriter; 26 | import java.io.UncheckedIOException; 27 | import java.nio.charset.StandardCharsets; 28 | import java.util.HashMap; 29 | import java.util.Map; 30 | 31 | import org.junit.jupiter.api.BeforeAll; 32 | import org.junit.jupiter.params.ParameterizedTest; 33 | import org.junit.jupiter.params.provider.EnumSource; 34 | 35 | import jakarta.json.Json; 36 | import jakarta.json.JsonReader; 37 | import jakarta.json.JsonStructure; 38 | import jakarta.json.JsonWriter; 39 | import jakarta.json.JsonWriterFactory; 40 | import jakarta.json.stream.JsonGenerator; 41 | 42 | /** 43 | * @author leadpony 44 | */ 45 | public class JsonReaderTest { 46 | 47 | static abstract class BaseTest { 48 | 49 | private static JsonWriterFactory writerFactory; 50 | 51 | @BeforeAll 52 | public static void setUpOnce() { 53 | Map config = new HashMap<>(); 54 | config.put(JsonGenerator.PRETTY_PRINTING, Boolean.TRUE); 55 | writerFactory = Json.createWriterFactory(config); 56 | } 57 | 58 | @ParameterizedTest 59 | @EnumSource(YamlResource.class) 60 | public void readShouldReadYamlAsExpected(YamlResource test) { 61 | JsonStructure yaml = null; 62 | try (JsonReader reader = createReader(test.getYamlAsStream())) { 63 | yaml = reader.read(); 64 | } 65 | 66 | assertThat(yaml).isNotNull(); 67 | 68 | String expected = readExpectedJson(test.getJsonAsStream()); 69 | 70 | assertThat(formatAsJson(yaml)).isEqualTo(expected); 71 | } 72 | 73 | @ParameterizedTest 74 | @EnumSource(YamlResource.class) 75 | public void readShouldReadJsonAsExpected(YamlResource test) { 76 | JsonStructure json = null; 77 | try (JsonReader reader = createReader(test.getJsonAsStream())) { 78 | json = reader.read(); 79 | } 80 | 81 | assertThat(json).isNotNull(); 82 | 83 | String expected = readExpectedJson(test.getJsonAsStream()); 84 | assertThat(formatAsJson(json)).isEqualTo(expected); 85 | } 86 | 87 | protected abstract JsonReader createReader(InputStream in); 88 | 89 | private static String formatAsJson(JsonStructure value) { 90 | StringWriter target = new StringWriter(); 91 | try (JsonWriter writer = writerFactory.createWriter(target)) { 92 | writer.write(value); 93 | } 94 | return target.toString(); 95 | } 96 | 97 | private String readExpectedJson(InputStream in) { 98 | StringBuilder builder = new StringBuilder(); 99 | try (BufferedReader reader = new BufferedReader( 100 | new InputStreamReader(in, StandardCharsets.UTF_8))) { 101 | String line; 102 | while ((line = reader.readLine()) != null) { 103 | if (builder.length() > 0) { 104 | builder.append('\n'); 105 | } 106 | builder.append(line); 107 | } 108 | } catch (IOException e) { 109 | throw new UncheckedIOException(e); 110 | } 111 | return builder.toString(); 112 | } 113 | } 114 | 115 | public static class InputStreamTest extends BaseTest { 116 | @Override 117 | protected JsonReader createReader(InputStream in) { 118 | return Json.createReader(in); 119 | } 120 | } 121 | 122 | public static class ReaderTest extends BaseTest { 123 | @Override 124 | protected JsonReader createReader(InputStream in) { 125 | return Json.createReader(new InputStreamReader(in, StandardCharsets.UTF_8)); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/java/org/leadpony/joy/yaml/tests/SimpleYamlTestCase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.yaml.tests; 18 | 19 | import jakarta.json.stream.JsonParser.Event; 20 | 21 | /** 22 | * @author leadpony 23 | */ 24 | public enum SimpleYamlTestCase { 25 | EMPTY(""), 26 | TRUE("true", Event.VALUE_TRUE), 27 | FALSE("false", Event.VALUE_FALSE), 28 | NULL("null", Event.VALUE_NULL), 29 | 30 | INTEGER_ZERO("0", Event.VALUE_NUMBER), 31 | INTEGER_NEGATIVE_ZERO("-0", Event.VALUE_NUMBER), 32 | INTEGER_POSITIVE("3", Event.VALUE_NUMBER), 33 | INTEGER_NEGATIVE("-19", Event.VALUE_NUMBER), 34 | 35 | NUMBER_ZERO("0.", Event.VALUE_NUMBER), 36 | NUMBER_NEGATIVE_ZERO("-0.0", Event.VALUE_NUMBER), 37 | NUMBER_SCIENTIFIC("12e03", Event.VALUE_NUMBER), 38 | NUMBER_NEGATIVE_SCIENTIFIC("-2E+05", Event.VALUE_NUMBER), 39 | 40 | SEQUENCE_EMPTY("[]", 41 | Event.START_ARRAY, 42 | Event.END_ARRAY), 43 | SEQUENCE_SINGLE_ITEM("[1]", 44 | Event.START_ARRAY, 45 | Event.VALUE_NUMBER, 46 | Event.END_ARRAY), 47 | SEQUENCE_MULTIPLE_ITEMS("[1, 2]", 48 | Event.START_ARRAY, 49 | Event.VALUE_NUMBER, 50 | Event.VALUE_NUMBER, 51 | Event.END_ARRAY), 52 | SEQUENCE_OF_MAPPINGS("[{}, {}]", 53 | Event.START_ARRAY, 54 | Event.START_OBJECT, 55 | Event.END_OBJECT, 56 | Event.START_OBJECT, 57 | Event.END_OBJECT, 58 | Event.END_ARRAY), 59 | SEQUENCE_MISSING_ITEM("-", 60 | Event.START_ARRAY, 61 | Event.VALUE_NULL, 62 | Event.END_ARRAY), 63 | 64 | MAPPING_EMPTY("{}", 65 | Event.START_OBJECT, 66 | Event.END_OBJECT), 67 | MAPPING_SINGLE_PROPERTY("{a: 1}", 68 | Event.START_OBJECT, 69 | Event.KEY_NAME, 70 | Event.VALUE_NUMBER, 71 | Event.END_OBJECT 72 | ), 73 | MAPPING_MULTIPLE_PROPERTIES("{a: 1, b: 2}", 74 | Event.START_OBJECT, 75 | Event.KEY_NAME, 76 | Event.VALUE_NUMBER, 77 | Event.KEY_NAME, 78 | Event.VALUE_NUMBER, 79 | Event.END_OBJECT 80 | ), 81 | MAPPING_MISSING_PROPERTY_VALUE("{a:}", 82 | Event.START_OBJECT, 83 | Event.KEY_NAME, 84 | Event.VALUE_NULL, 85 | Event.END_OBJECT 86 | ), 87 | MAPPING_PROPERTY_KEY_ONLY("{a}", 88 | Event.START_OBJECT, 89 | Event.KEY_NAME, 90 | Event.VALUE_NULL, 91 | Event.END_OBJECT 92 | ), 93 | 94 | MULTIPLE_DOCUMENTS( 95 | """ 96 | - 1 97 | --- 98 | - 2 99 | """, 100 | Event.START_ARRAY, 101 | Event.VALUE_NUMBER, 102 | Event.END_ARRAY 103 | ); 104 | 105 | final String yaml; 106 | final Event events[]; 107 | 108 | SimpleYamlTestCase(String yaml, Event... events) { 109 | this.yaml = yaml; 110 | this.events = events; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/java/org/leadpony/joy/yaml/tests/YamlResource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.yaml.tests; 18 | 19 | import java.io.InputStream; 20 | 21 | /** 22 | * YAML documents provided as resources. 23 | * 24 | * @author leadpony 25 | */ 26 | public enum YamlResource { 27 | PERSON_SCHEMA("/org/json-schema/person.schema.yaml"), 28 | INVOICE("/org/yaml/invoice.yaml"), 29 | TWO_DOCUMENTS("/org/yaml/two-documents.yaml"), 30 | PETSTORE("/org/openapis/petstore.yaml"), 31 | NULL_KEY("null-key.yaml"); 32 | 33 | private final String name; 34 | 35 | YamlResource(String name) { 36 | this.name = name; 37 | } 38 | 39 | InputStream getYamlAsStream() { 40 | return getClass().getResourceAsStream(name); 41 | } 42 | 43 | InputStream getJsonAsStream() { 44 | String jsonName = this.name.replaceAll("\\.yaml", ".json"); 45 | return getClass().getResourceAsStream(jsonName); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/java/org/leadpony/joy/yaml/tests/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * @author leadpony 19 | */ 20 | package org.leadpony.joy.yaml.tests; -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/resources/org/json-schema/person.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$id": "https://example.com/person.schema.json", 3 | "$schema": "http://json-schema.org/draft-07/schema#", 4 | "title": "Person", 5 | "type": "object", 6 | "properties": { 7 | "firstName": { 8 | "type": "string", 9 | "description": "The person's first name." 10 | }, 11 | "lastName": { 12 | "type": "string", 13 | "description": "The person's last name." 14 | }, 15 | "age": { 16 | "description": "Age in years which must be equal to or greater than zero.", 17 | "type": "integer", 18 | "minimum": 0 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/resources/org/json-schema/person.schema.yaml: -------------------------------------------------------------------------------- 1 | $id: https://example.com/person.schema.json 2 | $schema: http://json-schema.org/draft-07/schema# 3 | title: Person 4 | type: object 5 | properties: 6 | firstName: 7 | type: string 8 | description: The person's first name. 9 | lastName: 10 | type: string 11 | description: The person's last name. 12 | age: 13 | description: Age in years which must be equal to or greater than zero. 14 | type: integer 15 | minimum: 0 16 | -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/resources/org/leadpony/joy/yaml/tests/null-key.json: -------------------------------------------------------------------------------- 1 | { 2 | "": 1 3 | } -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/resources/org/leadpony/joy/yaml/tests/null-key.yaml: -------------------------------------------------------------------------------- 1 | !!null : 1 -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/resources/org/openapis/README.md: -------------------------------------------------------------------------------- 1 | The contents in this directory are copied from . 2 | 3 | Copyright The Linux Foundation 4 | 5 | Licensed under the Apache License, Version 2.0 -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/resources/org/openapis/petstore.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "license": { 7 | "name": "MIT" 8 | } 9 | }, 10 | "host": "petstore.swagger.io", 11 | "basePath": "/v1", 12 | "schemes": [ 13 | "http" 14 | ], 15 | "consumes": [ 16 | "application/json" 17 | ], 18 | "produces": [ 19 | "application/json" 20 | ], 21 | "paths": { 22 | "/pets": { 23 | "get": { 24 | "summary": "List all pets", 25 | "operationId": "listPets", 26 | "tags": [ 27 | "pets" 28 | ], 29 | "parameters": [ 30 | { 31 | "name": "limit", 32 | "in": "query", 33 | "description": "How many items to return at one time (max 100)", 34 | "required": false, 35 | "type": "integer", 36 | "format": "int32" 37 | } 38 | ], 39 | "responses": { 40 | "200": { 41 | "description": "A paged array of pets", 42 | "headers": { 43 | "x-next": { 44 | "type": "string", 45 | "description": "A link to the next page of responses" 46 | } 47 | }, 48 | "schema": { 49 | "$ref": "#/definitions/Pets" 50 | } 51 | }, 52 | "default": { 53 | "description": "unexpected error", 54 | "schema": { 55 | "$ref": "#/definitions/Error" 56 | } 57 | } 58 | } 59 | }, 60 | "post": { 61 | "summary": "Create a pet", 62 | "operationId": "createPets", 63 | "tags": [ 64 | "pets" 65 | ], 66 | "responses": { 67 | "201": { 68 | "description": "Null response" 69 | }, 70 | "default": { 71 | "description": "unexpected error", 72 | "schema": { 73 | "$ref": "#/definitions/Error" 74 | } 75 | } 76 | } 77 | } 78 | }, 79 | "/pets/{petId}": { 80 | "get": { 81 | "summary": "Info for a specific pet", 82 | "operationId": "showPetById", 83 | "tags": [ 84 | "pets" 85 | ], 86 | "parameters": [ 87 | { 88 | "name": "petId", 89 | "in": "path", 90 | "required": true, 91 | "description": "The id of the pet to retrieve", 92 | "type": "string" 93 | } 94 | ], 95 | "responses": { 96 | "200": { 97 | "description": "Expected response to a valid request", 98 | "schema": { 99 | "$ref": "#/definitions/Pets" 100 | } 101 | }, 102 | "default": { 103 | "description": "unexpected error", 104 | "schema": { 105 | "$ref": "#/definitions/Error" 106 | } 107 | } 108 | } 109 | } 110 | } 111 | }, 112 | "definitions": { 113 | "Pet": { 114 | "type": "object", 115 | "required": [ 116 | "id", 117 | "name" 118 | ], 119 | "properties": { 120 | "id": { 121 | "type": "integer", 122 | "format": "int64" 123 | }, 124 | "name": { 125 | "type": "string" 126 | }, 127 | "tag": { 128 | "type": "string" 129 | } 130 | } 131 | }, 132 | "Pets": { 133 | "type": "array", 134 | "items": { 135 | "$ref": "#/definitions/Pet" 136 | } 137 | }, 138 | "Error": { 139 | "type": "object", 140 | "required": [ 141 | "code", 142 | "message" 143 | ], 144 | "properties": { 145 | "code": { 146 | "type": "integer", 147 | "format": "int32" 148 | }, 149 | "message": { 150 | "type": "string" 151 | } 152 | } 153 | } 154 | } 155 | } -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/resources/org/openapis/petstore.yaml: -------------------------------------------------------------------------------- 1 | swagger: "2.0" 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | host: petstore.swagger.io 8 | basePath: /v1 9 | schemes: 10 | - http 11 | consumes: 12 | - application/json 13 | produces: 14 | - application/json 15 | paths: 16 | /pets: 17 | get: 18 | summary: List all pets 19 | operationId: listPets 20 | tags: 21 | - pets 22 | parameters: 23 | - name: limit 24 | in: query 25 | description: How many items to return at one time (max 100) 26 | required: false 27 | type: integer 28 | format: int32 29 | responses: 30 | "200": 31 | description: A paged array of pets 32 | headers: 33 | x-next: 34 | type: string 35 | description: A link to the next page of responses 36 | schema: 37 | $ref: '#/definitions/Pets' 38 | default: 39 | description: unexpected error 40 | schema: 41 | $ref: '#/definitions/Error' 42 | post: 43 | summary: Create a pet 44 | operationId: createPets 45 | tags: 46 | - pets 47 | responses: 48 | "201": 49 | description: Null response 50 | default: 51 | description: unexpected error 52 | schema: 53 | $ref: '#/definitions/Error' 54 | /pets/{petId}: 55 | get: 56 | summary: Info for a specific pet 57 | operationId: showPetById 58 | tags: 59 | - pets 60 | parameters: 61 | - name: petId 62 | in: path 63 | required: true 64 | description: The id of the pet to retrieve 65 | type: string 66 | responses: 67 | "200": 68 | description: Expected response to a valid request 69 | schema: 70 | $ref: '#/definitions/Pets' 71 | default: 72 | description: unexpected error 73 | schema: 74 | $ref: '#/definitions/Error' 75 | definitions: 76 | Pet: 77 | type: "object" 78 | required: 79 | - id 80 | - name 81 | properties: 82 | id: 83 | type: integer 84 | format: int64 85 | name: 86 | type: string 87 | tag: 88 | type: string 89 | Pets: 90 | type: array 91 | items: 92 | $ref: '#/definitions/Pet' 93 | Error: 94 | type: "object" 95 | required: 96 | - code 97 | - message 98 | properties: 99 | code: 100 | type: integer 101 | format: int32 102 | message: 103 | type: string -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/resources/org/yaml/README.md: -------------------------------------------------------------------------------- 1 | The contents in this directory are copied from . 2 | 3 | © 2001-2006 YAML.org All Rights Reserved 4 | -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/resources/org/yaml/invoice.json: -------------------------------------------------------------------------------- 1 | { 2 | "invoice": 34843, 3 | "date": "2001-01-23", 4 | "bill-to": { 5 | "given": "Chris", 6 | "family": "Dumars", 7 | "address": { 8 | "lines": "458 Walkman Dr.\nSuite #292\n", 9 | "city": "Royal Oak", 10 | "state": "MI", 11 | "postal": 48046 12 | } 13 | }, 14 | "product": [ 15 | { 16 | "sku": "BL394D", 17 | "quantity": 4, 18 | "description": "Basketball", 19 | "price": 450.00 20 | }, 21 | { 22 | "sku": "BL4438H", 23 | "quantity": 1, 24 | "description": "Super Hoop", 25 | "price": 2392.00 26 | } 27 | ], 28 | "tax": 251.42, 29 | "total": 4443.52, 30 | "comments": "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.\n" 31 | } -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/resources/org/yaml/invoice.yaml: -------------------------------------------------------------------------------- 1 | invoice: 34843 2 | date : 2001-01-23 3 | bill-to: 4 | given : Chris 5 | family : Dumars 6 | address: 7 | lines: | 8 | 458 Walkman Dr. 9 | Suite #292 10 | city : Royal Oak 11 | state : MI 12 | postal : 48046 13 | product: 14 | - sku : BL394D 15 | quantity : 4 16 | description : Basketball 17 | price : 450.00 18 | - sku : BL4438H 19 | quantity : 1 20 | description : Super Hoop 21 | price : 2392.00 22 | tax : 251.42 23 | total: 4443.52 24 | comments: > 25 | Late afternoon is best. 26 | Backup contact is Nancy 27 | Billsmer @ 338-4338. 28 | -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/resources/org/yaml/two-documents.json: -------------------------------------------------------------------------------- 1 | [ 2 | "Mark McGwire", 3 | "Sammy Sosa", 4 | "Ken Griffey" 5 | ] -------------------------------------------------------------------------------- /joy-yaml-tests/src/test/resources/org/yaml/two-documents.yaml: -------------------------------------------------------------------------------- 1 | # Ranking of 1998 home runs 2 | --- 3 | - Mark McGwire 4 | - Sammy Sosa 5 | - Ken Griffey 6 | # Team ranking 7 | --- 8 | - Chicago Cubs 9 | - St Louis Cardinals -------------------------------------------------------------------------------- /joy-yaml/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | 8 | 9 | org.leadpony.joy 10 | joy-parent 11 | 2.1.0 12 | 13 | 14 | joy-yaml 15 | jar 16 | org.leadpony.joy.yaml 17 | 18 | 19 | 20 | ${project.groupId} 21 | joy-core 22 | ${project.version} 23 | 24 | 25 | org.snakeyaml 26 | snakeyaml-engine 27 | 2.1 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-javadoc-plugin 37 | 3.1.0 38 | 39 | false 40 | 41 | 42 | https://docs.oracle.com/en/java/javase/11/docs/api/ 43 | ${basedir}/src/main/javadoc/java.base/ 44 | 45 | 46 | 47 | https://static.javadoc.io/jakarta.json/jakarta.json-api/2.0.0-RC1 48 | ${basedir}/src/main/javadoc/jakarta.json/ 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | org.apache.maven.plugins 58 | maven-checkstyle-plugin 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-jar-plugin 63 | 64 | 65 | 66 | org.leadpony.joy.classic 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | release 77 | 78 | 79 | 80 | org.apache.maven.plugins 81 | maven-compiler-plugin 82 | 83 | 84 | default-compile 85 | 86 | compile 87 | 88 | 89 | 9 90 | 91 | 92 | 93 | base-compile 94 | 95 | compile 96 | 97 | 98 | 99 | module-info.java 100 | 101 | 102 | 103 | 104 | 105 | 106 | org.apache.maven.plugins 107 | maven-javadoc-plugin 108 | 109 | 110 | org.apache.maven.plugins 111 | maven-source-plugin 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /joy-yaml/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2020 the Joy Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | /** 17 | * Defines the provider of Jakarta JSON Processing API (JSON-P). 18 | */ 19 | module org.leadpony.joy.yaml { 20 | requires org.leadpony.joy.core; 21 | requires org.snakeyaml.engine.v2; 22 | requires jakarta.json; 23 | 24 | provides jakarta.json.spi.JsonProvider 25 | with org.leadpony.joy.yaml.YamlProvider; 26 | } 27 | -------------------------------------------------------------------------------- /joy-yaml/src/main/java/org/leadpony/joy/yaml/EventType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.yaml; 18 | 19 | import org.snakeyaml.engine.v2.common.ScalarStyle; 20 | import org.snakeyaml.engine.v2.events.ScalarEvent; 21 | 22 | import jakarta.json.stream.JsonParser; 23 | 24 | /** 25 | * YAML event types. 26 | * 27 | * @author leadpony 28 | */ 29 | enum EventType { 30 | UNKNOWN(null), 31 | TRUE(JsonParser.Event.VALUE_TRUE), 32 | FALSE(JsonParser.Event.VALUE_FALSE), 33 | NULL(JsonParser.Event.VALUE_NULL), 34 | STRING(JsonParser.Event.VALUE_STRING), 35 | NUMBER(JsonParser.Event.VALUE_NUMBER), 36 | INTEGER(JsonParser.Event.VALUE_NUMBER), 37 | KEY_NAME(JsonParser.Event.KEY_NAME), 38 | SEQUENCE_START(JsonParser.Event.START_ARRAY), 39 | SEQUENCE_END(JsonParser.Event.END_ARRAY), 40 | MAPPING_START(JsonParser.Event.START_OBJECT), 41 | MAPPING_END(JsonParser.Event.END_OBJECT); 42 | 43 | private static final EventType DEFAULT_TYPE = EventType.STRING; 44 | 45 | private final JsonParser.Event jsonEvent; 46 | 47 | EventType(JsonParser.Event jsonEvent) { 48 | this.jsonEvent = jsonEvent; 49 | } 50 | 51 | /** 52 | * Returns the corresponding JSON parser event. 53 | * 54 | * @return the JSON parser event for this type. 55 | */ 56 | final JsonParser.Event toJsonEvent() { 57 | return jsonEvent; 58 | } 59 | 60 | /** 61 | * Maps a scalar event to one of event types. 62 | * 63 | * @param event the scalar event to map. 64 | * @return the mapped event type. 65 | */ 66 | static EventType of(ScalarEvent event) { 67 | 68 | if (isQuoted(event)) { 69 | return EventType.STRING; 70 | } 71 | 72 | final String value = event.getValue(); 73 | if (value.isEmpty()) { 74 | return EventType.NULL; 75 | } else { 76 | switch (value.charAt(0)) { 77 | case 't': 78 | return value.equals("true") ? EventType.TRUE : DEFAULT_TYPE; 79 | case 'f': 80 | return value.equals("false") ? EventType.FALSE : DEFAULT_TYPE; 81 | case 'n': 82 | return value.equals("null") ? EventType.NULL : DEFAULT_TYPE; 83 | case '-': 84 | return testNegativeNumber(value); 85 | case '0': 86 | case '1': 87 | case '2': 88 | case '3': 89 | case '4': 90 | case '5': 91 | case '6': 92 | case '7': 93 | case '8': 94 | case '9': 95 | return testPositiveNumber(value); 96 | default: 97 | return DEFAULT_TYPE; 98 | } 99 | } 100 | } 101 | 102 | private static boolean isQuoted(ScalarEvent event) { 103 | ScalarStyle style = event.getScalarStyle(); 104 | return style == ScalarStyle.SINGLE_QUOTED || style == ScalarStyle.DOUBLE_QUOTED; 105 | } 106 | 107 | private static EventType testPositiveNumber(String value) { 108 | return testNumber(value, 0); 109 | } 110 | 111 | private static EventType testNegativeNumber(String value) { 112 | if (value.length() >= 2) { 113 | if (isDigit(value.charAt(1))) { 114 | return testNumber(value, 1); 115 | } 116 | } 117 | return DEFAULT_TYPE; 118 | } 119 | 120 | private static EventType testNumber(String value, int index) { 121 | final int length = value.length(); 122 | char c = value.charAt(index++); 123 | 124 | if (c == '0') { 125 | if (index < length) { 126 | c = value.charAt(index++); 127 | if (isDigit(c)) { 128 | return DEFAULT_TYPE; 129 | } 130 | } else { 131 | return EventType.INTEGER; 132 | } 133 | } else { // c is from 1 to 9 134 | do { 135 | if (index < length) { 136 | c = value.charAt(index++); 137 | } else { 138 | return EventType.INTEGER; 139 | } 140 | } while (isDigit(c)); 141 | } 142 | 143 | // not a digit 144 | 145 | if (c == '.') { 146 | do { 147 | if (index < length) { 148 | c = value.charAt(index++); 149 | } else { 150 | return EventType.NUMBER; 151 | } 152 | } while (isDigit(c)); 153 | } 154 | 155 | if (c == 'e' || c == 'E') { 156 | if (index < length) { 157 | c = value.charAt(index++); 158 | if (c == '-' || c == '+') { 159 | if (index < length) { 160 | c = value.charAt(index++); 161 | } else { 162 | return DEFAULT_TYPE; 163 | } 164 | } 165 | int exponent = 0; 166 | while (isDigit(c)) { 167 | ++exponent; 168 | if (index < length) { 169 | c = value.charAt(index++); 170 | } else { 171 | return (exponent > 0) ? EventType.NUMBER : DEFAULT_TYPE; 172 | } 173 | } 174 | } 175 | } 176 | 177 | return DEFAULT_TYPE; 178 | } 179 | 180 | private static boolean isDigit(char c) { 181 | return '0' <= c && c <= '9'; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /joy-yaml/src/main/java/org/leadpony/joy/yaml/JsonLocations.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.yaml; 18 | 19 | import java.util.Optional; 20 | 21 | import org.leadpony.joy.core.BasicJsonLocation; 22 | import org.snakeyaml.engine.v2.exceptions.Mark; 23 | 24 | import jakarta.json.stream.JsonLocation; 25 | 26 | /** 27 | * @author leadpony 28 | * 29 | */ 30 | final class JsonLocations { 31 | 32 | static JsonLocation at(Mark mark) { 33 | return new BasicJsonLocation( 34 | mark.getLine() + 1, 35 | mark.getColumn() + 1, 36 | mark.getIndex()); 37 | } 38 | 39 | static JsonLocation at(Optional mark) { 40 | return mark.map(JsonLocations::at).orElse(BasicJsonLocation.UNKNOWN); 41 | } 42 | 43 | private JsonLocations() { 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /joy-yaml/src/main/java/org/leadpony/joy/yaml/LocalMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.yaml; 18 | 19 | import static org.leadpony.joy.core.Preconditions.requireNonNull; 20 | 21 | import java.text.MessageFormat; 22 | import java.util.ResourceBundle; 23 | 24 | import org.snakeyaml.engine.v2.events.Event; 25 | 26 | import jakarta.json.stream.JsonLocation; 27 | 28 | /** 29 | * Messages for YAML processors. 30 | * 31 | * @author leadpony 32 | */ 33 | final class LocalMessage { 34 | 35 | private static final String BUNDLE_NAME = LocalMessage.class.getPackage().getName() + ".messages"; 36 | 37 | static String thatPropertyKeyMustNotBeArray(JsonLocation location) { 38 | requireNonNull(location, "location"); 39 | return format("PropertyKeyMustNotBeArray", at(location)); 40 | } 41 | 42 | static String thatPropertyKeyMustNotBeObject(JsonLocation location) { 43 | requireNonNull(location, "location"); 44 | return format("PropertyKeyMustNotBeObject", at(location)); 45 | } 46 | 47 | static String thatAliasIsNotSupported(JsonLocation location) { 48 | requireNonNull(location, "location"); 49 | return format("AliasIsNotSupported", at(location)); 50 | } 51 | 52 | static String thatParserDetectedUnexpectedEvent(JsonLocation location, Event event) { 53 | requireNonNull(location, "location"); 54 | requireNonNull(event, "event"); 55 | return format("ParserDetectedUnexpectedEvent", at(location), event.getEventId()); 56 | } 57 | 58 | static String thatRequiredEventIsMissing() { 59 | return format("RequiredEventIsMissing"); 60 | } 61 | 62 | /* helpers */ 63 | 64 | private static String format(String name, Object... arguments) { 65 | String pattern = getPattern(name); 66 | return MessageFormat.format(pattern, arguments); 67 | } 68 | 69 | private static String getPattern(String name) { 70 | ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_NAME); 71 | return bundle.getString(name); 72 | } 73 | 74 | private static String at(JsonLocation location) { 75 | return format("location", 76 | location.getLineNumber(), 77 | location.getColumnNumber(), 78 | location.getStreamOffset()); 79 | } 80 | 81 | private LocalMessage() { 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /joy-yaml/src/main/java/org/leadpony/joy/yaml/ParserContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.yaml; 18 | 19 | /** 20 | * A parsing context. 21 | * 22 | * @author leadpony 23 | */ 24 | interface ParserContext { 25 | 26 | /** 27 | * Changes the current state. 28 | * 29 | * @param state the new state. 30 | */ 31 | void setState(ParserState state); 32 | 33 | /** 34 | * Begins a sequence (array). 35 | */ 36 | void beginSequence(); 37 | 38 | /** 39 | * Ends a sequence (array). 40 | */ 41 | void endSequence(); 42 | 43 | /** 44 | * Begins a mapping (object). 45 | */ 46 | void beginMapping(); 47 | 48 | /** 49 | * Ends a mapping (object). 50 | */ 51 | void endMapping(); 52 | } 53 | -------------------------------------------------------------------------------- /joy-yaml/src/main/java/org/leadpony/joy/yaml/YamlParserFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.yaml; 18 | 19 | import static org.leadpony.joy.core.Preconditions.requireNonNull; 20 | 21 | import java.io.InputStream; 22 | import java.io.InputStreamReader; 23 | import java.io.Reader; 24 | import java.nio.charset.Charset; 25 | import java.util.Collections; 26 | import java.util.Iterator; 27 | import java.util.Map; 28 | 29 | import org.leadpony.joy.core.AbstractJsonParserFactory; 30 | import org.snakeyaml.engine.v2.api.LoadSettings; 31 | import org.snakeyaml.engine.v2.api.lowlevel.Parse; 32 | import org.snakeyaml.engine.v2.events.Event; 33 | 34 | import jakarta.json.stream.JsonParser; 35 | 36 | /** 37 | * @author leadpony 38 | */ 39 | final class YamlParserFactory extends AbstractJsonParserFactory { 40 | 41 | private final Parse parse; 42 | 43 | YamlParserFactory() { 44 | this(Collections.emptyMap()); 45 | } 46 | 47 | YamlParserFactory(Map properties) { 48 | super(properties); 49 | this.parse = buildParse(); 50 | } 51 | 52 | @Override 53 | public JsonParser createParser(Reader reader) { 54 | requireNonNull(reader, "reader"); 55 | return createYamlParser(reader); 56 | } 57 | 58 | @Override 59 | public JsonParser createParser(InputStream in) { 60 | requireNonNull(in, "in"); 61 | return createYamlParser(createStreamReader(in)); 62 | } 63 | 64 | @Override 65 | public JsonParser createParser(InputStream in, Charset charset) { 66 | requireNonNull(in, "in"); 67 | requireNonNull(charset, "charset"); 68 | Reader reader = new InputStreamReader(in, charset); 69 | return createYamlParser(reader); 70 | } 71 | 72 | /* helpers */ 73 | 74 | private Parse buildParse() { 75 | LoadSettings settings = LoadSettings.builder().build(); 76 | return new Parse(settings); 77 | } 78 | 79 | private YamlParser createYamlParser(Reader reader) { 80 | Iterator iterator = parse.parseReader(reader).iterator(); 81 | return new YamlParser(iterator, reader); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /joy-yaml/src/main/java/org/leadpony/joy/yaml/YamlProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.leadpony.joy.yaml; 18 | 19 | import static org.leadpony.joy.core.Preconditions.requireNonNull; 20 | 21 | import java.io.InputStream; 22 | import java.io.Reader; 23 | import java.util.Map; 24 | 25 | import org.leadpony.joy.core.AbstractJsonProvider; 26 | 27 | import jakarta.json.stream.JsonParser; 28 | import jakarta.json.stream.JsonParserFactory; 29 | import jakarta.json.spi.JsonProvider; 30 | 31 | /** 32 | * A {@link JsonProvider} for producing YAML parsers. 33 | * 34 | * @author leadpony 35 | */ 36 | public final class YamlProvider extends AbstractJsonProvider { 37 | 38 | private YamlParserFactory defaultParserFactory; 39 | 40 | /** 41 | * Constructs this provider. 42 | */ 43 | public YamlProvider() { 44 | } 45 | 46 | /** 47 | * {@inheritDoc} 48 | */ 49 | @Override 50 | public JsonParser createParser(Reader reader) { 51 | requireNonNull(reader, "reader"); 52 | return getDefaultParserFactory().createParser(reader); 53 | } 54 | 55 | /** 56 | * {@inheritDoc} 57 | */ 58 | @Override 59 | public JsonParser createParser(InputStream in) { 60 | requireNonNull(in, "in"); 61 | return getDefaultParserFactory().createParser(in); 62 | } 63 | 64 | /** 65 | * {@inheritDoc} 66 | */ 67 | @Override 68 | public JsonParserFactory createParserFactory(Map config) { 69 | if (config == null || config.isEmpty()) { 70 | return getDefaultParserFactory(); 71 | } else { 72 | return new YamlParserFactory(config); 73 | } 74 | } 75 | 76 | /* helpers */ 77 | 78 | private JsonParserFactory getDefaultParserFactory() { 79 | if (defaultParserFactory == null) { 80 | defaultParserFactory = new YamlParserFactory(); 81 | } 82 | return defaultParserFactory; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /joy-yaml/src/main/java/org/leadpony/joy/yaml/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Provides a YAML service provider. 19 | * 20 | * @author leadpony 21 | */ 22 | package org.leadpony.joy.yaml; 23 | -------------------------------------------------------------------------------- /joy-yaml/src/main/javadoc/jakarta.json/package-list: -------------------------------------------------------------------------------- 1 | module:jakarta.json 2 | jakarta.json 3 | jakarta.json.spi 4 | jakarta.json.stream 5 | -------------------------------------------------------------------------------- /joy-yaml/src/main/javadoc/java.base/package-list: -------------------------------------------------------------------------------- 1 | module:java.base 2 | java.io 3 | java.lang 4 | java.math 5 | java.net 6 | java.nio.charset 7 | java.nio.file 8 | java.util 9 | java.util.function 10 | java.util.stream -------------------------------------------------------------------------------- /joy-yaml/src/main/resources/META-INF/services/jakarta.json.spi.JsonProvider: -------------------------------------------------------------------------------- 1 | org.leadpony.joy.yaml.YamlProvider -------------------------------------------------------------------------------- /joy-yaml/src/main/resources/org/leadpony/joy/yaml/messages.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020 the Joy Authors. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | location=[line={0},column={1},offset={2}] 17 | 18 | PropertyKeyMustNotBeArray={0} Property key must not be an array. 19 | PropertyKeyMustNotBeObject={0} Property key must not be an object. 20 | AliasIsNotSupported={0} YAML alias is not supported. 21 | ParserDetectedUnexpectedEvent={0} Parser detected unexpected YAML event {1}. 22 | RequiredEventIsMissing=Required event is missing. 23 | -------------------------------------------------------------------------------- /tck/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.leadpony.joy 9 | joy-parent 10 | 2.1.0 11 | 12 | 13 | tck 14 | 15 | 16 | 17 | 18 | org.apache.maven.plugins 19 | maven-antrun-plugin 20 | 1.8 21 | 22 | 23 | validate 24 | validate 25 | 26 | 27 | 28 | 30 | 32 | 34 | 35 | 36 | 38 | 40 | 42 | 45 | 46 | 47 | 49 | 50 | 51 | 55 | 56 | 57 | 58 | run 59 | 60 | 61 | 62 | integration-test 63 | integration-test 64 | 65 | run 66 | 67 | 68 | 69 | 70 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | org.apache.maven.plugins 83 | maven-dependency-plugin 84 | 85 | 86 | copy 87 | initialize 88 | 89 | copy 90 | 91 | 92 | 93 | 94 | jakarta.json 95 | jakarta.json-api 96 | ${jsonp.version} 97 | ${work.home}/jars 98 | json-api.jar 99 | 100 | 101 | org.leadpony.joy 102 | joy-classic 103 | ${project.version} 104 | ${work.home}/jars 105 | joy-classic.jar 106 | 107 | 108 | org.leadpony.joy 109 | joy-core 110 | ${project.version} 111 | ${work.home}/jars 112 | joy-core.jar 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | ${project.build.directory}/work 124 | ${project.build.directory}/ant 125 | ${project.build.directory}/tck 126 | ${tck.home}/src/com/sun/ts/tests/jsonp 127 | 1.10.9 128 | 129 | 130 | 131 | --------------------------------------------------------------------------------