) mapperFactory.newMapper().toValue(value);
} else {
throwUnsupportedError(value.getClass());
}
diff --git a/elementfactory/src/main/java/io/github/xmljim/json/elementfactory/JsonArrayImpl.java b/elementfactory/src/main/java/io/github/xmljim/json/elementfactory/JsonArrayImpl.java
index e601e4a..fe78651 100644
--- a/elementfactory/src/main/java/io/github/xmljim/json/elementfactory/JsonArrayImpl.java
+++ b/elementfactory/src/main/java/io/github/xmljim/json/elementfactory/JsonArrayImpl.java
@@ -129,7 +129,7 @@ public boolean equals(Object o) {
if (!(o instanceof JsonArrayImpl jsonArray)) {
return false;
}
-
+
return Objects.equals(valueList, jsonArray.valueList);
}
@@ -183,6 +183,11 @@ public String prettyPrint(int indent) {
return builder.toString();
}
+ @Override
+ public int hashCode() {
+ return Objects.hash(this.valueList);
+ }
+
public String toString() {
return toJsonString();
}
diff --git a/elementfactory/src/main/java/io/github/xmljim/json/elementfactory/JsonObjectImpl.java b/elementfactory/src/main/java/io/github/xmljim/json/elementfactory/JsonObjectImpl.java
index c4ed8ad..3b0ae94 100644
--- a/elementfactory/src/main/java/io/github/xmljim/json/elementfactory/JsonObjectImpl.java
+++ b/elementfactory/src/main/java/io/github/xmljim/json/elementfactory/JsonObjectImpl.java
@@ -117,7 +117,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return Objects.hash(data, parent());
+ return Objects.hash(data);
}
@Override
diff --git a/json-api/README.md b/json-api/README.md
new file mode 100644
index 0000000..bc4d626
--- /dev/null
+++ b/json-api/README.md
@@ -0,0 +1,5 @@
+# JSON API
+
+The Json API combines all the reference implementation services into a single API layer for use as single library.
+
+Each "service" is exposed as static class instances that expose methods provided by that service.
\ No newline at end of file
diff --git a/json-api/pom.xml b/json-api/pom.xml
new file mode 100644
index 0000000..18fe787
--- /dev/null
+++ b/json-api/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+ json-library
+ io.github.xmljim.json
+ 1.0.2
+
+ 4.0.0
+
+ json-api
+
+
+
+
+ io.github.xmljim.json
+ json-parser
+ ${project.version}
+
+
+ io.github.xmljim.json
+ elementfactory
+ ${project.version}
+
+
+ io.github.xmljim.json
+ json-merger
+ ${project.version}
+
+
+ io.github.xmljim.json
+ json-mapper
+ ${project.version}
+
+
+ io.github.xmljim.json
+ jsonpath
+ ${project.version}
+ compile
+
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+
+ report
+ verify
+
+ report
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/json-api/src/main/java/io/github/xmljim/json/api/JsonApi.java b/json-api/src/main/java/io/github/xmljim/json/api/JsonApi.java
new file mode 100644
index 0000000..8566cff
--- /dev/null
+++ b/json-api/src/main/java/io/github/xmljim/json/api/JsonApi.java
@@ -0,0 +1,460 @@
+package io.github.xmljim.json.api;
+
+import io.github.xmljim.json.factory.jsonpath.JsonPathBuilder;
+import io.github.xmljim.json.factory.jsonpath.JsonPathFactory;
+import io.github.xmljim.json.factory.jsonpath.ResultType;
+import io.github.xmljim.json.factory.mapper.MapperFactory;
+import io.github.xmljim.json.factory.mapper.MappingConfig;
+import io.github.xmljim.json.factory.mapper.MappingParserConfig;
+import io.github.xmljim.json.factory.mapper.parser.MappingParser;
+import io.github.xmljim.json.factory.merge.MergeFactory;
+import io.github.xmljim.json.factory.merge.strategy.ArrayConflictStrategy;
+import io.github.xmljim.json.factory.merge.strategy.MergeResultStrategy;
+import io.github.xmljim.json.factory.merge.strategy.ObjectConflictStrategy;
+import io.github.xmljim.json.factory.model.ElementFactory;
+import io.github.xmljim.json.factory.parser.InputData;
+import io.github.xmljim.json.factory.parser.JsonParserException;
+import io.github.xmljim.json.factory.parser.ParserBuilder;
+import io.github.xmljim.json.factory.parser.ParserFactory;
+import io.github.xmljim.json.model.JsonArray;
+import io.github.xmljim.json.model.JsonNode;
+import io.github.xmljim.json.model.JsonObject;
+import io.github.xmljim.json.model.JsonValue;
+import io.github.xmljim.json.service.ServiceManager;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+public final class JsonApi {
+
+ /**
+ * JsonPath ({@link JsonPathFactory}) API functionality
+ */
+ public static final JsonPathApi JsonPath = new JsonPathApi();
+
+ /**
+ * JsonParser ({@link ParserFactory}) API functionality
+ */
+ public static final JsonParserApi JsonParser = new JsonParserApi();
+
+ /**
+ * JsonElement ({@link ElementFactory}) functionality
+ */
+ public static final ElementApi JsonElement = new ElementApi();
+
+ /**
+ * JsonMerge ({@link MergeFactory}) functionality
+ */
+ public static final JsonMergeApi JsonMerge = new JsonMergeApi();
+
+ /**
+ * JsonMapper ({@link MapperFactory}) functionality
+ */
+ public static final JsonMapperApi JsonMapper = new JsonMapperApi();
+
+ /**
+ * Private constructor, use static fields instead
+ */
+ private JsonApi() {
+ //private constructor
+ }
+
+ /**
+ * API for JsonPath functionality
+ */
+ public static final class JsonPathApi {
+ private final JsonPathFactory jsonPathFactory = ServiceManager.getProvider(JsonPathFactory.class);
+
+ private JsonPathApi() {
+ //no-op
+ }
+
+ /**
+ * Return the underlying JsonPathBuilder to modify settings
+ * for a new {@link io.github.xmljim.json.factory.jsonpath.JsonPath} instance
+ *
+ * @return a new JsonPathBuilder
+ */
+ public JsonPathBuilder getBuilder() {
+ return jsonPathFactory.newJsonPathBuilder();
+ }
+
+ /**
+ * Return a JsonArray of values selected from a JsonPath expression.
+ * This uses the default settings and properties for a JsonPath instance.
+ * If you need to modify settings (e.g., properties, or set variables),
+ * use {@link #getBuilder()} to apply these settings and return a
+ * {@link io.github.xmljim.json.factory.jsonpath.JsonPath} instance
+ *
+ * This is the syntactic equivalent of:
+ *
+ * JsonPathFactory jsonPathFactory = ServiceManager.getProvider(JsonPathFactory.class);
+ * JsonPath jsonPath = jsonPathFactory.newJsonPath();
+ * JsonArray result = jsonPath.select(node, pathExpression);
+ *
+ *
+ * @param node The context node that will be used to evaluate and select values
+ * @param pathExpression the JsonPath expression to query the context node
+ * @return a JsonArray of values that represent the select expression
+ */
+ public JsonArray select(JsonNode node, String pathExpression) {
+ return jsonPathFactory.newJsonPath().select(node, pathExpression);
+ }
+
+ /**
+ * Return a List of values selected from a JsonPath expression.
+ * This uses the default settings and properties for a JsonPath instance.
+ * If you need to modify settings (e.g., properties, or set variables),
+ * use {@link #getBuilder()} to apply these settings and return a
+ * {@link io.github.xmljim.json.factory.jsonpath.JsonPath} instance
+ *
+ * This is the syntactic equivalent of:
+ *
+ * JsonPathFactory jsonPathFactory = ServiceManager.getProvider(JsonPathFactory.class);
+ * JsonPath jsonPath = jsonPathFactory.newJsonPath();
+ * JsonArray result = jsonPath.select(node, pathExpression);
+ *
+ * MapperFactory mapperFactory = ServiceManager.getProvider(MapperFactory.class);
+ * Mapper mapper = mapperFactory.newMapper();
+ * return mapper.toList(result);
+ *
+ *
+ * @param node The context node that will be used to evaluate and select values
+ * @param pathExpression the JsonPath expression to query the context node
+ * @return a JsonArray of values that represent the select expression
+ */
+ @SuppressWarnings("unchecked")
+ public List selectList(JsonNode node, String pathExpression) {
+ JsonMapperApi jsonMapperApi = new JsonMapperApi();
+ return (List) jsonMapperApi.toList(select(node, pathExpression));
+ }
+
+ /**
+ * Return a JsonArray of paths selected from a JsonPath expression.
+ * This uses the default settings and properties for a JsonPath instance.
+ * If you need to modify settings (e.g., properties, or set variables),
+ * use {@link #getBuilder()} to apply these settings and return a
+ * {@link io.github.xmljim.json.factory.jsonpath.JsonPath} instance
+ *
+ * This is the syntactic equivalent of:
+ *
+ * JsonPathFactory jsonPathFactory = ServiceManager.getProvider(JsonPathFactory.class);
+ * JsonPath jsonPath = jsonPathFactory.newJsonPath();
+ * JsonArray result = jsonPath.select(node, pathExpression, ResultType.PATH);
+ *
+ *
+ * @param node The context node that will be used to evaluate and select values
+ * @param pathExpression the JsonPath expression to query the context node
+ * @return a JsonArray of normalized Json paths to each selected item
+ */
+ public JsonArray selectPath(JsonNode node, String pathExpression) {
+ return jsonPathFactory.newJsonPath().select(node, pathExpression, ResultType.PATH);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List selectPathList(JsonNode node, String pathExpression) {
+ JsonMapperApi jsonMapperApi = new JsonMapperApi();
+ return (List) jsonMapperApi.toList(select(node, pathExpression));
+ }
+
+ public T selectValue(JsonNode node, String pathExpression) {
+ return jsonPathFactory.newJsonPath().selectValue(node, pathExpression);
+ }
+ }
+
+ /**
+ * Parser API
+ */
+ public static final class JsonParserApi {
+ private final ParserFactory parserFactory = ServiceManager.getProvider(ParserFactory.class);
+
+ private JsonParserApi() {
+ //no-op
+ }
+
+ /**
+ * Parse a JSON String
+ *
+ * @param jsonString the JSON String
+ * @param The JsonNode type (either a {@link JsonArray} or {@link JsonObject})
+ * @return a new JsonNode type
+ */
+ public T parse(String jsonString) {
+ return parserFactory.newParser().parse(InputData.of(jsonString));
+ }
+
+ /**
+ * Parse a JSON String
+ *
+ * @param path the path to the Json data
+ * @param The JsonNode type (either a {@link JsonArray} or {@link JsonObject})
+ * @return a new JsonNode type
+ */
+ public T parse(Path path) {
+ if (path.getFileSystem().isOpen()) {
+ if (!Files.exists(path)) {
+ throw new JsonParserException("File does not exist: " + path.getFileName().toString());
+ }
+ }
+ return parserFactory.newParser().parse(InputData.of(path));
+ }
+
+ /**
+ * Parse a JSON String
+ *
+ * @param inputStream the InputStream to the Json data
+ * @param The JsonNode type (either a {@link JsonArray} or {@link JsonObject})
+ * @return a new JsonNode type
+ */
+ public T parse(InputStream inputStream) {
+ return parserFactory.newParser().parse(InputData.of(inputStream));
+ }
+
+ /**
+ * Parse a JSON String
+ *
+ * @param reader the Reader to the Json data
+ * @param The JsonNode type (either a {@link JsonArray} or {@link JsonObject})
+ * @return a new JsonNode type
+ */
+ public T parse(Reader reader) {
+ return parserFactory.newParser().parse(InputData.of(reader));
+ }
+
+ /**
+ * Return the ParserBuilder to configure a new Parser
+ *
+ * @return the ParserBuilder
+ */
+ public ParserBuilder getParserBuilder() {
+ return parserFactory.newParserBuilder();
+ }
+
+ public T parse(InputData inputData, Class targetClass) {
+ MappingParser mappingParser = JsonMapper.newMappingParser();
+ return mappingParser.parse(inputData, targetClass);
+ }
+
+ public T parse(MappingParserConfig mappingParserConfig, InputData inputData, Class targetClass) {
+ MappingParser mappingParser = JsonMapper.newMappingParser(mappingParserConfig);
+ return mappingParser.parse(inputData, targetClass);
+ }
+ }
+
+ /**
+ * Json Element API
+ */
+ public static final class ElementApi {
+ private final ElementFactory elementFactory = ServiceManager.getProvider(ElementFactory.class);
+
+ private ElementApi() {
+ //no-op
+ }
+
+ /**
+ * Create a new, empty JSONObject instance
+ *
+ * @return a new empty JSONObject instance
+ */
+ public JsonObject newObject() {
+ return elementFactory.newObject();
+ }
+
+ /**
+ * Create a new, empty JSONArray instance
+ *
+ * @return a new empty JSONArray instance
+ */
+ public JsonArray newArray() {
+ return elementFactory.newArray();
+ }
+
+ /**
+ * Create a new JsonValue instance
+ *
+ * @param value the raw value
+ * @param the value type
+ * @return the new JsonValue
+ */
+ public JsonValue newValue(T value) {
+ return elementFactory.newValue(value);
+ }
+ }
+
+ /**
+ * The JsonMerge API
+ */
+ public static final class JsonMergeApi {
+ private final MergeFactory mergeFactory = ServiceManager.getProvider(MergeFactory.class);
+
+ private JsonMergeApi() {
+ // no-op
+ }
+
+ /**
+ * Merge two JsonNodes, using the default configuration (i.e., conflict strategies)
+ *
+ * @param primary the primary node
+ * @param secondary the secondary node
+ * @param The JsonNode type
+ * @return The merged JsonNode
+ */
+ public T merge(T primary, T secondary) {
+ return mergeFactory.newMergeProcessor().merge(primary, secondary);
+ }
+
+ /**
+ * Merge two JsonNodes, specifying the ArrayConflictStrategy and ObjectConflict Strategy
+ *
+ * @param primary the primary node
+ * @param secondary the secondary node
+ * @param arrayConflictStrategy the conflict strategy to apply for JsonArrays
+ * @param objectConflictStrategy The conflict strategy to apply for JsonObjects
+ * @param the node type
+ * @return The merged JsonNode
+ */
+ public T merge(T primary, T secondary, ArrayConflictStrategy arrayConflictStrategy,
+ ObjectConflictStrategy objectConflictStrategy) {
+ return mergeFactory.newMergeBuilder()
+ .setArrayConflictStrategy(arrayConflictStrategy)
+ .setObjectConflictStrategy(objectConflictStrategy)
+ .build()
+ .merge(primary, secondary);
+ }
+
+ /**
+ * Merge two JsonNodes, specifying the ArrayConflictStrategy and ObjectConflict Strategy
+ *
+ * @param primary the primary node
+ * @param secondary the secondary node
+ * @param arrayConflictStrategy the conflict strategy to apply for JsonArrays
+ * @param objectConflictStrategy The conflict strategy to apply for JsonObjects
+ * @param mergeResultStrategy the merge result strategy - Here there be dragons. KNOW what you're doing
+ * @param mergeAppendKey the key value to append to a given JsonObject key for Append conflicts
+ * @param the node type
+ * @return The merged JsonNode
+ */
+ public T merge(T primary, T secondary, ArrayConflictStrategy arrayConflictStrategy,
+ ObjectConflictStrategy objectConflictStrategy,
+ MergeResultStrategy mergeResultStrategy,
+ String mergeAppendKey) {
+
+ return mergeFactory.newMergeBuilder()
+ .setArrayConflictStrategy(arrayConflictStrategy)
+ .setObjectConflictStrategy(objectConflictStrategy)
+ .setMergeAppendKey(mergeAppendKey)
+ .setMergeResultStrategy(mergeResultStrategy)
+ .build()
+ .merge(primary, secondary);
+ }
+ }
+
+ /**
+ * JsonMapper API
+ */
+ public static final class JsonMapperApi {
+ private final MapperFactory mapperFactory = ServiceManager.getProvider(MapperFactory.class);
+
+ private JsonMapperApi() {
+ //no-op
+ }
+
+ /**
+ * Convert an object into a JsonObject
+ *
+ * @param object the object instance
+ * @return the JsonObject
+ */
+ public JsonObject toJsonObject(Object object) {
+ return mapperFactory.newMapper().toJson(object);
+ }
+
+ /**
+ * Convert a map into a JsonObject
+ *
+ * @param objectMap the map instance
+ * @return a new JsonObject
+ */
+ public JsonObject toJsonObject(Map objectMap) {
+ return mapperFactory.newMapper().toJson(objectMap);
+ }
+
+ /**
+ * Convert a collection to a JsonArray
+ *
+ * @param collection the collection
+ * @return a new JsonArray
+ */
+ public JsonArray toJsonArray(Collection collection) {
+ return mapperFactory.newMapper().toJson(collection);
+ }
+
+ /**
+ * Convert a JsonObject to a class instance
+ *
+ * @param jsonObject The JsonObject
+ * @param targetClass the target class, should be concrete class
+ * @param the class type or a super type or interface
+ * @return the converted class
+ */
+ public T toClass(JsonObject jsonObject, Class targetClass) {
+ return mapperFactory.newMapper().toClass(jsonObject, targetClass);
+ }
+
+ public T toClass(MappingConfig mappingConfig, JsonObject jsonObject, Class targetClass) {
+ return mapperFactory.newMapper(mappingConfig).toClass(jsonObject, targetClass);
+ }
+
+ public JsonObject toJson(T instance) {
+ return mapperFactory.newMapper().toJson(instance);
+ }
+
+ public JsonObject toJson(MappingConfig mappingConfig, T instance) {
+ return mapperFactory.newMapper(mappingConfig).toJson(instance);
+ }
+
+ /**
+ * Convert a JsonObject to a Map
+ *
+ * @param jsonObject the JsonObject
+ * @return a new Map instance
+ */
+ public Map toMap(JsonObject jsonObject) {
+ return mapperFactory.newMapper().toMap(jsonObject);
+ }
+
+ /**
+ * Convert a JsonArray to a List
+ *
+ * @param jsonArray the JsonArray
+ * @return the new List instance
+ */
+ public List> toList(JsonArray jsonArray) {
+ return mapperFactory.newMapper().toList(jsonArray);
+ }
+
+ /**
+ * Convert a raw value to a JsonValue
+ *
+ * @param value the value to convert
+ * @return a new JsonValue
+ */
+ public JsonValue> toValue(Object value) {
+ return mapperFactory.newMapper().toValue(value);
+ }
+
+ MappingParser newMappingParser() {
+ return mapperFactory.newMappingParser();
+ }
+
+ MappingParser newMappingParser(MappingParserConfig mappingParserConfig) {
+ return mapperFactory.newMappingParser(mappingParserConfig);
+ }
+
+ }
+}
diff --git a/json-api/src/main/java/module-info.java b/json-api/src/main/java/module-info.java
new file mode 100644
index 0000000..16f3deb
--- /dev/null
+++ b/json-api/src/main/java/module-info.java
@@ -0,0 +1,38 @@
+import io.github.xmljim.json.factory.jsonpath.JsonPathFactory;
+import io.github.xmljim.json.factory.mapper.*;
+import io.github.xmljim.json.factory.merge.MergeFactory;
+import io.github.xmljim.json.factory.model.ElementFactory;
+import io.github.xmljim.json.factory.parser.ParserFactory;
+
+module io.github.xmljim.json.api {
+
+ requires transitive io.github.xmljim.json.elementfactory;
+ requires transitive io.github.xmljim.json.parser;
+ requires transitive io.github.xmljim.json.merger;
+ requires transitive io.github.xmljim.json.mapper;
+ requires transitive io.github.xmljim.json.jsonpath;
+
+ // ** Services Consumed *
+
+ // Element Factory: for creating new model elements
+ uses ElementFactory;
+
+ //Mapper Factory: for marshalling and unmarshalling Json and Java objects
+ uses MapperFactory;
+ //Builder for creating MappingConfig instances used by a Mapper
+ uses MappingConfig.Builder;
+ //Builder for creating ClassConfig instances used in a MappingConfig
+ uses ClassConfig.Builder;
+ //Builder for creating MemberConfig instances used in a ClassConfig
+ uses MemberConfig.Builder;
+ //Builder for creating a MapperParserConfig used by the MapperParser
+ uses MappingParserConfig.Builder;
+ //Parser Factory: for creating a new JsonParser
+ uses ParserFactory;
+ //JsonPath Factory: for creating JsonPath instances
+ uses JsonPathFactory;
+ //Merge Factory: for creating Merger instances
+ uses MergeFactory;
+
+ exports io.github.xmljim.json.api;
+}
\ No newline at end of file
diff --git a/json-api/src/test/java/io/github/xmljim/json/api/test/JsonApiTests.java b/json-api/src/test/java/io/github/xmljim/json/api/test/JsonApiTests.java
new file mode 100644
index 0000000..f52cbe2
--- /dev/null
+++ b/json-api/src/test/java/io/github/xmljim/json/api/test/JsonApiTests.java
@@ -0,0 +1,154 @@
+package io.github.xmljim.json.api.test;
+
+import io.github.xmljim.json.model.JsonArray;
+import io.github.xmljim.json.model.JsonObject;
+import io.github.xmljim.json.model.JsonValue;
+import io.github.xmljim.json.model.NodeType;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import static io.github.xmljim.json.api.JsonApi.JsonElement;
+import static io.github.xmljim.json.api.JsonApi.JsonParser;
+import static org.junit.jupiter.api.Assertions.*;
+
+public class JsonApiTests {
+
+ @Test
+ @DisplayName("JsonElement - New Array")
+ void testCreateNewArray() {
+ JsonArray array = JsonElement.newArray();
+ assertNotNull(array);
+ assertEquals(NodeType.ARRAY, array.type());
+ assertTrue(array.type().isArray());
+ }
+
+ @Test
+ @DisplayName("JsonElement - New Object")
+ void testCreateNewObject() {
+ JsonObject object = JsonElement.newObject();
+ assertNotNull(object);
+ assertEquals(NodeType.OBJECT, object.type());
+ assertTrue(object.type().isObject());
+ }
+
+ @Test
+ @DisplayName("JsonElement - String Value")
+ void testCreateStringValue() {
+ String value = "TestString";
+ JsonValue stringJsonValue = JsonElement.newValue(value);
+ assertNotNull(stringJsonValue);
+ assertEquals(NodeType.STRING, stringJsonValue.type());
+ assertEquals(value, stringJsonValue.get());
+ assertTrue(stringJsonValue.type().isPrimitive());
+ }
+
+ @Test
+ @DisplayName("JsonElement - Boolean Value")
+ void testCreateBooleanValue() {
+ boolean value = true;
+ JsonValue booleanJsonValue = JsonElement.newValue(value);
+ assertNotNull(booleanJsonValue);
+ assertEquals(NodeType.BOOLEAN, booleanJsonValue.type());
+ assertEquals(value, booleanJsonValue.get());
+ assertTrue(booleanJsonValue.type().isPrimitive());
+ }
+
+ @Test
+ @DisplayName("JsonElement - Long Value")
+ void testCreateLongValue() {
+ Long value = 1L;
+ JsonValue jsonValue = JsonElement.newValue(value);
+ assertNotNull(jsonValue);
+ assertEquals(NodeType.LONG, jsonValue.type());
+ assertEquals(value, jsonValue.get());
+ assertTrue(jsonValue.type().isPrimitive());
+ assertTrue(jsonValue.type().isNumeric());
+ }
+
+ @Test
+ @DisplayName("JsonElement - Integer Value")
+ void testCreateIntegerValue() {
+ int value = 1;
+ JsonValue jsonValue = JsonElement.newValue(value);
+ assertNotNull(jsonValue);
+ assertEquals(NodeType.INTEGER, jsonValue.type());
+ assertEquals(value, jsonValue.get());
+ assertTrue(jsonValue.type().isPrimitive());
+ assertTrue(jsonValue.type().isNumeric());
+ }
+
+ @Test
+ @DisplayName("JsonElement - Double Value")
+ void testCreateDoubleValue() {
+ double value = 3.1415926;
+ JsonValue jsonValue = JsonElement.newValue(value);
+ assertNotNull(jsonValue);
+ assertEquals(NodeType.DOUBLE, jsonValue.type());
+ assertEquals(value, jsonValue.get());
+ assertTrue(jsonValue.type().isPrimitive());
+ assertTrue(jsonValue.type().isNumeric());
+ }
+
+ @Test
+ @DisplayName("JsonElement - Null Value")
+ void testCreateNullValue() {
+ Object value = null;
+ JsonValue> jsonValue = JsonElement.newValue(value);
+ assertNotNull(jsonValue);
+ assertEquals(NodeType.NULL, jsonValue.type());
+ assertNull(jsonValue.get());
+ assertTrue(jsonValue.type().isPrimitive());
+ }
+
+ @Test
+ @DisplayName("JsonElement - JsonArray Value")
+ void testCreateArrayValue() {
+ JsonArray array = JsonElement.newArray();
+ JsonValue jsonValue = JsonElement.newValue(array);
+ assertNotNull(jsonValue);
+ assertEquals(NodeType.ARRAY, jsonValue.type());
+ assertEquals(array, jsonValue.get());
+ assertTrue(jsonValue.type().isArray());
+ }
+
+ @Test
+ @DisplayName("JsonElement - JsonObject Value")
+ void testCreateObjectValue() {
+ JsonObject value = JsonElement.newObject();
+ JsonValue jsonValue = JsonElement.newValue(value);
+ assertNotNull(jsonValue);
+ assertEquals(NodeType.OBJECT, jsonValue.type());
+ assertEquals(value, jsonValue.get());
+ assertTrue(jsonValue.type().isObject());
+ }
+
+ @Test
+ @DisplayName("JsonParser - Parse String")
+ void testParserString() {
+ String jsonString = """
+ {"a": 1, "b": true, "c": null, "d": {"foo": "bar"}, "e": [1, true, null, {"foo": "bar"}, [3.14, 1.62]]}
+ """;
+
+ JsonObject jsonObject = JsonParser.parse(jsonString);
+
+ assertNotNull(jsonObject);
+ assertEquals(1, (long) jsonObject.get("a"));
+ assertTrue((boolean) jsonObject.get("b"));
+ }
+
+ @Test
+ @DisplayName("JsonParser - Parse InputStream")
+ void testParserInputStream() {
+ try (InputStream inputStream = getClass().getResourceAsStream("/test1.json")) {
+ JsonObject jsonObject = JsonParser.parse(inputStream);
+ assertNotNull(jsonObject);
+ assertEquals(1, (long) jsonObject.get("a"));
+ assertTrue((boolean) jsonObject.get("b"));
+ } catch (IOException ioException) {
+ fail();
+ }
+ }
+}
diff --git a/json-api/src/test/resources/test1.json b/json-api/src/test/resources/test1.json
new file mode 100644
index 0000000..3058b85
--- /dev/null
+++ b/json-api/src/test/resources/test1.json
@@ -0,0 +1,20 @@
+{
+ "a": 1,
+ "b": true,
+ "c": null,
+ "d": {
+ "foo": "bar"
+ },
+ "e": [
+ 1,
+ true,
+ null,
+ {
+ "foo": "bar"
+ },
+ [
+ 3.14,
+ 1.62
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/json-logging/pom.xml b/json-logging/pom.xml
new file mode 100644
index 0000000..4f030c5
--- /dev/null
+++ b/json-logging/pom.xml
@@ -0,0 +1,19 @@
+
+
+
+ json-library
+ io.github.xmljim.json
+ 1.0.2
+
+ 4.0.0
+
+ json-logging
+
+
+ 17
+ 17
+
+
+
\ No newline at end of file
diff --git a/json-test-coverage/pom.xml b/json-test-coverage/pom.xml
new file mode 100644
index 0000000..4570728
--- /dev/null
+++ b/json-test-coverage/pom.xml
@@ -0,0 +1,65 @@
+
+
+
+ json-library
+ io.github.xmljim.json
+ 1.0.2
+
+ 4.0.0
+ pom
+
+ json-test-coverage
+
+
+ 17
+ 17
+
+
+
+
+ io.github.xmljim.json
+ elementfactory
+ ${project.version}
+
+
+ io.github.xmljim.json
+ jsonpath
+ ${project.version}
+
+
+ io.github.xmljim.json
+ json-parser
+ ${project.version}
+
+
+ io.github.xmljim.json
+ json-mapper
+ ${project.version}
+
+
+ io.github.xmljim.json
+ json-merger
+ ${project.version}
+
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+
+ report-aggregate
+ verify
+
+ report-aggregate
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jsonfactory/README.md b/jsonfactory/README.md
index e55226c..0e0d999 100644
--- a/jsonfactory/README.md
+++ b/jsonfactory/README.md
@@ -7,6 +7,18 @@ All services typically follow a *Factory* design pattern and all extend the `Jso
example, the `ElementFactory` interface extends `JsonService` and provides methods for creating concrete instances of
the JSON Model.
+## JsonService
+
+The `JsonService` interface is nothing more than a tagging interface that identifies that any interface that extends
+it _is_ intended to be a service to be consumed by another component. Internally, the `ServiceManager` scans
+the module path for all `JsonService` instances.
+
+## @JsonService Annotation
+
+The `@JsonService` annotation is applied to `JsonService` interface implementation classes. In addition to tagging
+the implementation class as a Service Provider, it contains other metadata that facilitate in helping the
+Service Manager select the appropriate implementation class, if more than one exists.
+
## ServiceManager
The `ServiceManager` class provides static methods for instantiating *Service Providers*. Service
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/config/AbstractConfiguration.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/config/AbstractConfiguration.java
new file mode 100644
index 0000000..5967ea3
--- /dev/null
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/config/AbstractConfiguration.java
@@ -0,0 +1,63 @@
+package io.github.xmljim.json.factory.config;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+public abstract class AbstractConfiguration implements Configuration {
+ private final Map configurationMap = new HashMap<>();
+ private boolean immutable = true;
+
+ @Override
+ public boolean put(ConfigKey configKey, V value) {
+ if (isImmutable()) {
+ return putIfAbsent(configKey, value);
+ } else {
+ configurationMap.put(configKey, ConfigurationEntry.of(configKey, value));
+ return true;
+ }
+ }
+
+ @Override
+ public boolean putIfAbsent(ConfigKey configKey, V value) {
+ @SuppressWarnings("unchecked")
+ V val = (V) configurationMap.putIfAbsent(configKey, ConfigurationEntry.of(configKey, value));
+ return val == null;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Optional getOptional(ConfigKey configKey) {
+ ConfigurationEntry entry = configurationMap.getOrDefault(configKey, null);
+ if (entry != null) {
+ return Optional.of(entry.getValue());
+ }
+ return Optional.empty();
+ }
+
+ @Override
+ public void setImmutable(boolean immutable) {
+ this.immutable = immutable;
+ }
+
+ @Override
+ public boolean isImmutable() {
+ return immutable;
+ }
+
+ @Override
+ public boolean containsKey(ConfigKey configKey) {
+ return configurationMap.containsKey(configKey);
+ }
+
+ @Override
+ public boolean containsValue(V value) {
+ return configurationMap.containsValue(value);
+ }
+
+ @Override
+ public Stream entries() {
+ return configurationMap.values().stream();
+ }
+}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/config/ConfigKey.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/config/ConfigKey.java
new file mode 100644
index 0000000..5d6dd6a
--- /dev/null
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/config/ConfigKey.java
@@ -0,0 +1,43 @@
+package io.github.xmljim.json.factory.config;
+
+import java.util.Objects;
+
+public final class ConfigKey {
+ private Object key;
+
+ private ConfigKey(T key) {
+ this.key = key;
+ }
+
+ public static ConfigKey of(T key) {
+ Objects.requireNonNull(key, "Key value cannot be null");
+ return new ConfigKey(key);
+ }
+
+ @SuppressWarnings("unchecked")
+ public T get() {
+ return (T) key;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ConfigKey configKey = (ConfigKey) o;
+ return key.equals(configKey.key);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(key);
+ }
+
+ @Override
+ public String toString() {
+ return key.toString();
+ }
+}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/config/Configuration.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/config/Configuration.java
new file mode 100644
index 0000000..671f110
--- /dev/null
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/config/Configuration.java
@@ -0,0 +1,72 @@
+package io.github.xmljim.json.factory.config;
+
+import java.util.Optional;
+import java.util.stream.Stream;
+
+public interface Configuration {
+
+ boolean put(ConfigKey configKey, V value);
+
+ default boolean put(K key, V value) {
+ return put(ConfigKey.of(key), value);
+ }
+
+ boolean putIfAbsent(ConfigKey configKey, V value);
+
+ default boolean putIfAbsent(K key, V value) {
+ return putIfAbsent(ConfigKey.of(key), value);
+ }
+
+ Optional getOptional(ConfigKey configKey);
+
+ default Optional getOptional(K key) {
+ return getOptional(ConfigKey.of(key));
+ }
+
+ @SuppressWarnings("unchecked")
+ default V getOrDefault(ConfigKey configKey, V defaultIfMissing) {
+ return (V) getOptional(configKey).orElse(defaultIfMissing);
+ }
+
+ default V getOrDefault(K key, V defaultIfMissing) {
+
+
+ return getOrDefault(ConfigKey.of(key), defaultIfMissing);
+ }
+
+ default V get(ConfigKey configKey) {
+ return getOrDefault(configKey, null);
+ }
+
+ default V get(K key) {
+ return get(ConfigKey.of(key));
+ }
+
+ void setImmutable(boolean immutable);
+
+ boolean isImmutable();
+
+ boolean containsKey(ConfigKey configKey);
+
+ default boolean containsKey(K key) {
+ return containsKey(ConfigKey.of(key));
+ }
+
+ boolean containsValue(V value);
+
+ default Stream configKeys() {
+ return entries().map(ConfigurationEntry::getKey);
+ }
+
+ default Stream keys() {
+ return configKeys().map(ConfigKey::get);
+ }
+
+ default Stream values() {
+ return entries().map(ConfigurationEntry::getValue);
+ }
+
+ Stream entries();
+
+
+}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/config/ConfigurationEntry.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/config/ConfigurationEntry.java
new file mode 100644
index 0000000..e0345ae
--- /dev/null
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/config/ConfigurationEntry.java
@@ -0,0 +1,61 @@
+package io.github.xmljim.json.factory.config;
+
+import java.util.Objects;
+
+public final class ConfigurationEntry {
+ private final ConfigKey key;
+ private final Object value;
+
+ private ConfigurationEntry(K key, V value) {
+ this.key = ConfigKey.of(key);
+ this.value = value;
+ }
+
+ private ConfigurationEntry(ConfigKey key, V value) {
+ this.key = key;
+ this.value = value;
+ }
+
+
+ public static ConfigurationEntry of(K key, V value) {
+ return new ConfigurationEntry(key, value);
+ }
+
+ public static ConfigurationEntry of(ConfigKey key, V value) {
+ return new ConfigurationEntry(key, value);
+ }
+
+ public ConfigKey getKey() {
+ return key;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T getValue() {
+ return (T) value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ConfigurationEntry that = (ConfigurationEntry) o;
+ return key.equals(that.key) && value.equals(that.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(key, value);
+ }
+
+ @Override
+ public String toString() {
+ return "ConfigurationEntry {" +
+ "key=" + key +
+ ", value=" + value +
+ '}';
+ }
+}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/jsonpath/JsonPath.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/jsonpath/JsonPath.java
index ce241da..26b2d10 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/jsonpath/JsonPath.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/jsonpath/JsonPath.java
@@ -74,5 +74,10 @@ default T selectValue(JsonNode jsonNode, String expression) {
return null;
}
+ /**
+ * To be implemented
+ *
+ * @return stay tuned
+ */
List getErrors();
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/ClassConfig.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/ClassConfig.java
new file mode 100644
index 0000000..bca002c
--- /dev/null
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/ClassConfig.java
@@ -0,0 +1,60 @@
+package io.github.xmljim.json.factory.mapper;
+
+import io.github.xmljim.json.factory.config.Configuration;
+import io.github.xmljim.json.service.JsonService;
+import io.github.xmljim.json.service.ServiceManager;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public interface ClassConfig extends Configuration {
+
+ Class getTargetClass();
+
+ Class getSourceClass();
+
+ Set getIgnoredKeys();
+
+ List getConstructorKeys();
+
+ Stream getMemberConfigurations();
+
+ default boolean containsMember(Field field) {
+ return getMemberConfigurations().anyMatch(memberConfig -> memberConfig.getField().equals(field));
+ }
+
+ default boolean containsMember(String jsonKey) {
+ return getMemberConfigurations().anyMatch(memberConfig -> memberConfig.getJsonKey().equals(jsonKey));
+ }
+
+ static ClassConfig.Builder with() {
+ return ServiceManager.getProvider(ClassConfig.Builder.class);
+ }
+
+ interface Builder extends JsonService {
+ Builder targetClass(Class targetClass);
+
+ Builder sourceClass(Class sourceClass);
+
+ default Builder ignoreKeys(String... keys) {
+ return ignoreKeys(Arrays.stream(keys).collect(Collectors.toSet()));
+ }
+
+ Builder ignoreKeys(Collection keys);
+
+ default Builder constructorKeys(String... keys) {
+ return constructorKeys(Arrays.stream(keys).toList());
+ }
+
+ Builder constructorKeys(List keys);
+
+ Builder appendMemberConfig(MemberConfig memberConfig);
+
+ ClassConfig build();
+ }
+}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/ClassMapping.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/ClassMapping.java
new file mode 100644
index 0000000..fc75b41
--- /dev/null
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/ClassMapping.java
@@ -0,0 +1,40 @@
+package io.github.xmljim.json.factory.mapper;
+
+import io.github.xmljim.json.model.JsonObject;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
+
+public interface ClassMapping {
+ ClassConfig getClassConfig();
+
+ Mapping getMapping();
+
+ Class getSourceClass();
+
+ Class getTargetClass();
+
+ boolean isPublic();
+
+ boolean isRecord();
+
+ List getConstructorKeys();
+
+ Stream getMemberMappings();
+
+ MemberMapping getMemberMapping(Field var1);
+
+ MemberMapping getMemberMapping(String var1);
+
+ Set getIgnoredKeys();
+
+ void appendMemberMapping(MemberMapping var1);
+
+
+ Constructor getConstructor();
+
+ T toClass(JsonObject jsonObject);
+}
\ No newline at end of file
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/Converter.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/Converter.java
new file mode 100644
index 0000000..1095152
--- /dev/null
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/Converter.java
@@ -0,0 +1,11 @@
+package io.github.xmljim.json.factory.mapper;
+
+
+import java.util.Map;
+
+public interface Converter {
+
+ R convert(T value);
+
+ Map getArguments();
+}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/KeyNameCase.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/KeyNameCase.java
index 90a7544..c9305cd 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/KeyNameCase.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/KeyNameCase.java
@@ -1,8 +1,20 @@
package io.github.xmljim.json.factory.mapper;
public enum KeyNameCase {
+ /**
+ * Default case
+ */
DEFAULT,
+ /**
+ * Camel case
+ */
CAMEL,
+ /**
+ * Snake case
+ */
SNAKE,
+ /**
+ * Kebab case
+ */
KEBAB
}
\ No newline at end of file
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/Mapper.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/Mapper.java
index bf6a056..6950d9b 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/Mapper.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/Mapper.java
@@ -21,6 +21,8 @@ public interface Mapper {
*/
MapperConfig getConfig();
+ Mapping getMapping();
+
/**
* Convert a Map to a JsonObject
*
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MapperBuilder.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MapperBuilder.java
deleted file mode 100644
index 666232a..0000000
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MapperBuilder.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package io.github.xmljim.json.factory.mapper;
-
-import java.util.Collection;
-
-public interface MapperBuilder {
-
- Mapper build();
-
- MapperBuilder setTargetClass(Class> targetClass);
-
- MapperBuilder setValueConverter(ValueConverter> valueConverter);
-
- MapperBuilder setKeyNameCase(KeyNameCase keyNameCase);
-
- MapperBuilder setIgnoreKeys(Collection ignoreKeys);
-
- @SuppressWarnings("unused")
- MapperBuilder setIgnoreKeys(String... ignoreKeys);
-
- default MapperBuilder merge(Mapper mapper) {
- return setTargetClass(mapper.getConfig().getTargetClass().orElse(null))
- .setValueConverter(mapper.getConfig().getValueConverter().orElse(null))
- .setKeyNameCase(mapper.getConfig().getKeyNameCase())
- .setIgnoreKeys(mapper.getConfig().getIgnoreKeys());
-
- }
-}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MapperConfig.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MapperConfig.java
index d102317..7c379b3 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MapperConfig.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MapperConfig.java
@@ -3,12 +3,30 @@
import java.util.Optional;
import java.util.Set;
+/**
+ * Interface for the Mapper Configuration
+ */
public interface MapperConfig {
+ /**
+ * Return the target class for this Mapper
+ *
+ * @return the target class for this Mapper
+ */
Optional> getTargetClass();
+ /**
+ * Return a value converter for this Mapper
+ *
+ * @return the value converter for this mapper
+ */
Optional> getValueConverter();
+ /**
+ * Return the keyNameCase for this mapper
+ *
+ * @return the keyNameCase for this mapper
+ */
KeyNameCase getKeyNameCase();
Set getIgnoreKeys();
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MapperFactory.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MapperFactory.java
index 200109b..4bf2ba9 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MapperFactory.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MapperFactory.java
@@ -1,12 +1,37 @@
package io.github.xmljim.json.factory.mapper;
+import io.github.xmljim.json.factory.mapper.parser.MappingParser;
import io.github.xmljim.json.service.JsonService;
+/**
+ * Factory/Service for Mapping Json to Java Classes
+ */
public interface MapperFactory extends JsonService {
- MapperBuilder newBuilder();
- default Mapper newMapper() {
- return newBuilder().build();
+ /**
+ * Create a new Mapper with default configurations, i.e., no {@link Mapping} data
+ *
+ * @return a new Mapper with default configurations
+ */
+ Mapper newMapper();
+
+ Mapper newMapper(Mapping mapping);
+
+ default Mapper newMapper(MappingConfig mappingConfig) {
+ return newMapper(newMapping(mappingConfig));
}
+
+ ClassMapping newClassMapping(Mapping mapping, ClassConfig classConfig);
+
+ MemberMapping newMemberMapping(ClassMapping classMapping, MemberConfig memberConfig);
+
+ Mapping newMapping(MappingConfig mappingConfig);
+
+ MappingParser newMappingParser(MappingParserConfig mappingParserConfig);
+
+ default MappingParser newMappingParser() {
+ return newMappingParser(MappingParserConfig.withDefaults());
+ }
+
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/Mapping.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/Mapping.java
new file mode 100644
index 0000000..e831706
--- /dev/null
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/Mapping.java
@@ -0,0 +1,18 @@
+package io.github.xmljim.json.factory.mapper;
+
+import java.util.stream.Stream;
+
+public interface Mapping {
+
+ MapperFactory getMapperFactory();
+
+ Stream getClassMappings();
+
+ ClassMapping getClassMapping(Class mappedClass);
+
+ boolean containsClassMapping(Class mappedClass);
+
+ void append(ClassMapping classMapping);
+
+ void append(Class classMapping);
+}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MappingConfig.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MappingConfig.java
new file mode 100644
index 0000000..69768b2
--- /dev/null
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MappingConfig.java
@@ -0,0 +1,30 @@
+package io.github.xmljim.json.factory.mapper;
+
+import io.github.xmljim.json.service.JsonService;
+import io.github.xmljim.json.service.ServiceManager;
+
+import java.util.List;
+
+public interface MappingConfig {
+
+ List getClassConfigurations();
+
+ static Builder with() {
+ return ServiceManager.getProvider(MappingConfig.Builder.class);
+ }
+
+ static MappingConfig empty() {
+ return with().build();
+ }
+
+ interface Builder extends JsonService {
+
+ default Builder withClass(Class sourceClass) {
+ return appendClassConfig(ClassConfig.with().sourceClass(sourceClass).build());
+ }
+
+ Builder appendClassConfig(ClassConfig classConfig);
+
+ MappingConfig build();
+ }
+}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MappingParserConfig.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MappingParserConfig.java
new file mode 100644
index 0000000..36f3c34
--- /dev/null
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MappingParserConfig.java
@@ -0,0 +1,70 @@
+package io.github.xmljim.json.factory.mapper;
+
+import io.github.xmljim.json.factory.parser.NumericValueType;
+import io.github.xmljim.json.factory.parser.Parser;
+import io.github.xmljim.json.factory.parser.ParserSettings;
+import io.github.xmljim.json.factory.parser.event.Assembler;
+import io.github.xmljim.json.factory.parser.event.EventHandler;
+import io.github.xmljim.json.factory.parser.event.Processor;
+import io.github.xmljim.json.service.JsonService;
+import io.github.xmljim.json.service.ServiceManager;
+
+import java.nio.charset.Charset;
+
+/**
+ * Configurations for Mapping Parser that extends both
+ * {@link ParserSettings} and {@link MappingConfig}
+ */
+public interface MappingParserConfig extends ParserSettings, MappingConfig {
+
+ /**
+ * Get the Builder for creating configuration settings for Mapping Parser. Requires a
+ * {@link JsonService} service provider implementation to be present on the module path
+ * @return a new Builder implementation. If no provider is present, it will throw
+ * a {@link io.github.xmljim.json.service.exception.JsonServiceProviderUnavailableException}.
+ */
+ static Builder with() {
+ return ServiceManager.getProvider(MappingParserConfig.Builder.class);
+ }
+
+ /**
+ * Create a new Configuration from default settings
+ * @return a new configuration
+ */
+ static MappingParserConfig withDefaults() {
+ return with().build();
+ }
+
+ /**
+ * Builder interface for creating the Mapper Parser settings. This is defined as a service
+ * so that a service provider can register with the ServiceManager.
+ */
+ interface Builder extends MappingConfig.Builder, JsonService {
+
+ Builder assembler(Assembler> assembler);
+
+ Builder blockCount(int blockCount);
+
+ Builder characterSet(Charset charset);
+
+ Builder eventHandler(EventHandler eventHandler);
+
+ Builder enableStatistics(boolean enableStatistics);
+
+ Builder fixedNumberStrategy(NumericValueType fixedNumberStrategy);
+
+ Builder floatingNumberStrategy(NumericValueType floatingNumberStrategy);
+
+ Builder maxEventBufferCapacity(int maxEventBufferCapacity);
+
+ Builder useStrict(boolean useStrict);
+
+ Builder parser(Parser parser);
+
+ Builder processor(Processor processor);
+
+ Builder requestNextLength(int requestNextLength);
+
+ MappingParserConfig build();
+ }
+}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MemberConfig.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MemberConfig.java
new file mode 100644
index 0000000..8422949
--- /dev/null
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MemberConfig.java
@@ -0,0 +1,60 @@
+package io.github.xmljim.json.factory.mapper;
+
+import io.github.xmljim.json.factory.config.Configuration;
+import io.github.xmljim.json.model.NodeType;
+import io.github.xmljim.json.service.JsonService;
+import io.github.xmljim.json.service.ServiceManager;
+
+import java.lang.reflect.Field;
+
+public interface MemberConfig extends Configuration {
+
+ Field getField();
+
+ String getJsonKey();
+
+ NodeType getNodeType();
+
+ Class getContainerClass();
+
+ Class getElementTargetClass();
+
+ Converter getFieldConverter();
+
+ Converter getJsonConverter();
+
+ String getGetterMethodName();
+
+ String getSetterMethodName();
+
+ boolean isIgnored();
+
+ public static Builder with() {
+ return ServiceManager.getProvider(MemberConfig.Builder.class);
+ }
+
+ interface Builder extends JsonService {
+
+ Builder field(Field field);
+
+ Builder jsonKey(String jsonKey);
+
+ Builder nodeType(NodeType nodeType);
+
+ Builder containerClass(Class containerClass);
+
+ Builder elementTargetClass(Class elementTargetClass);
+
+ Builder fieldConverter(Converter fieldConverter);
+
+ Builder jsonConverter(Converter jsonConverter);
+
+ Builder getterMethodName(String getterMethodName);
+
+ Builder setterMethodName(String setterMethodName);
+
+ Builder ignored(boolean ignored);
+
+ MemberConfig build();
+ }
+}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MemberMapping.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MemberMapping.java
new file mode 100644
index 0000000..a7384e5
--- /dev/null
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/MemberMapping.java
@@ -0,0 +1,40 @@
+package io.github.xmljim.json.factory.mapper;
+
+import io.github.xmljim.json.model.JsonObject;
+import io.github.xmljim.json.model.NodeType;
+
+import java.lang.reflect.Type;
+
+public interface MemberMapping {
+ String getJsonKey();
+
+ NodeType getNodeType();
+
+ String getFieldName();
+
+ Type getFieldType();
+
+ boolean isIgnored();
+
+ boolean isAccessible();
+
+ Class getContainerClass();
+
+ String getSetterMethodName();
+
+ String getGetterMethodName();
+
+ Class getElementTargetClass();
+
+ Converter getJsonConverter();
+
+ Converter getFieldConverter();
+
+ void applyToClass(JsonObject var1, T var2);
+
+ void applyToJson(T var1, JsonObject var2);
+
+ T getValue(JsonObject var1);
+
+ ClassMapping getClassMapping();
+}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/ValueConverter.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/ValueConverter.java
index fc311a7..760f835 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/ValueConverter.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/ValueConverter.java
@@ -3,12 +3,34 @@
import java.util.Map;
import java.util.Optional;
+/**
+ * Interface for value converters
+ *
+ * @param the converter value type
+ */
public interface ValueConverter {
+ /**
+ * Specifies the class types this converter will accept
+ *
+ * @return the accepted class types
+ */
Class>[] accepts();
+ /**
+ * Contains a map of arguments/parameters for this converter
+ *
+ * @return a map of arguments/parameters for this converter
+ */
Map args();
+ /**
+ * Convert the value
+ *
+ * @param value the input value
+ * @param The output type
+ * @return the output
+ */
T convert(V value);
static Optional> empty() {
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/ConvertClass.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/ConvertClass.java
index a21a16e..2b54a22 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/ConvertClass.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/ConvertClass.java
@@ -5,8 +5,16 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * Specifies the target class used for mapping to and from Json and Java
+ */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
public @interface ConvertClass {
+ /**
+ * The target class
+ *
+ * @return the target class
+ */
Class> target();
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/ConvertValue.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/ConvertValue.java
index 442df96..6fb74c2 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/ConvertValue.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/ConvertValue.java
@@ -7,6 +7,10 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * Annotation that is assigned to a field, method or class that
+ * assigns ValueConverters to and from Json and a class instance
+ */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface ConvertValue {
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/ConverterArg.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/ConverterArg.java
index aa4da94..5a2f23f 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/ConverterArg.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/ConverterArg.java
@@ -1,7 +1,20 @@
package io.github.xmljim.json.factory.mapper.annotation;
+/**
+ * Specifies an argument for a ValueConverter
+ */
public @interface ConverterArg {
+ /**
+ * The argument name
+ *
+ * @return the argument name
+ */
String name();
+ /**
+ * The argument value
+ *
+ * @return the argument value
+ */
String value();
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/JsonElement.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/JsonElement.java
index 34329ee..0f2ace0 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/JsonElement.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/annotation/JsonElement.java
@@ -2,6 +2,9 @@
import java.lang.annotation.*;
+/**
+ * Specifies a mapping to a Json element
+ */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/parser/MappingParser.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/parser/MappingParser.java
new file mode 100644
index 0000000..c6a3827
--- /dev/null
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/mapper/parser/MappingParser.java
@@ -0,0 +1,30 @@
+package io.github.xmljim.json.factory.mapper.parser;
+
+import io.github.xmljim.json.factory.mapper.Mapper;
+import io.github.xmljim.json.factory.parser.InputData;
+import io.github.xmljim.json.factory.parser.Parser;
+
+/**
+ * Wrapper interface around a {@link Parser} and {@link Mapper}.
+ * It's a parser in name only in the sense that it
+ * uses a Parser to load the {@link io.github.xmljim.json.model.JsonObject}
+ * data. After parsing, the JsonObject instance is passed to a Mapper to
+ * create a class instance.
+ *
+ * Internally this is a functional interface that passes in
+ * an {@link InputData} and {@code Class} targetClass
+ *
+ */
+@FunctionalInterface
+public interface MappingParser {
+
+ /**
+ * Parse a Json data and load into a class instance
+ *
+ * @param inputData The input data
+ * @param targetClass the target class
+ * @param
+ * @return
+ */
+ T parse(InputData inputData, Class targetClass);
+}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/merge/MergeConfig.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/merge/MergeConfig.java
index 4184cb5..1e29e53 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/merge/MergeConfig.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/merge/MergeConfig.java
@@ -4,13 +4,36 @@
import io.github.xmljim.json.factory.merge.strategy.MergeResultStrategy;
import io.github.xmljim.json.factory.merge.strategy.ObjectConflictStrategy;
+/**
+ * Merge configuration
+ */
public interface MergeConfig {
+ /**
+ * Return the Array Conflict Strategy
+ *
+ * @return the Array Conflict Strategy
+ */
ArrayConflictStrategy getArrayConflictStrategy();
+ /**
+ * Return the Object Conflict Strategy
+ *
+ * @return the Object Conflict Strategy
+ */
ObjectConflictStrategy getObjectConflictStrategy();
+ /**
+ * Return the MergeResultStrategy
+ *
+ * @return the MergeResultStrategy
+ */
MergeResultStrategy getMergeResultStrategy();
+ /**
+ * Return the key string to append to conflicted object keys in an Append strategy
+ *
+ * @return the key string to append
+ */
String getMergeAppendKey();
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/merge/MergeFactory.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/merge/MergeFactory.java
index 5a3b666..c41be72 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/merge/MergeFactory.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/merge/MergeFactory.java
@@ -2,10 +2,23 @@
import io.github.xmljim.json.service.JsonService;
+/**
+ * Factory/Service for Json Merging
+ */
public interface MergeFactory extends JsonService {
+ /**
+ * Create a new MergeBuilder for configuring a Merge
+ *
+ * @return a new MergeBuilder
+ */
MergeBuilder newMergeBuilder();
+ /**
+ * Create a default MergeProcessor
+ *
+ * @return a new MergeProcess with default configuration
+ */
default MergeProcessor newMergeProcessor() {
return newMergeBuilder().build();
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/merge/strategy/MergeResultStrategy.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/merge/strategy/MergeResultStrategy.java
index 9215cc0..ab47939 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/merge/strategy/MergeResultStrategy.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/merge/strategy/MergeResultStrategy.java
@@ -1,5 +1,8 @@
package io.github.xmljim.json.factory.merge.strategy;
+/**
+ * Specifies the output of a merge operation
+ */
public enum MergeResultStrategy {
/**
* Merge directly to the primary instance.
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/model/ElementFactory.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/model/ElementFactory.java
index 65f4192..57f0a20 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/model/ElementFactory.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/model/ElementFactory.java
@@ -6,17 +6,65 @@
import io.github.xmljim.json.model.JsonValue;
import io.github.xmljim.json.service.JsonService;
+/**
+ * Factory/service for creating Json elements
+ */
public interface ElementFactory extends JsonService {
+ /**
+ * Create a new JsonValue
+ *
+ * @param value the raw value
+ * @param the JsonValue type
+ * @param the raw value type
+ * @return a new JsonValue
+ */
JsonValue newValue(T value);
+ /**
+ * create a new JsonValue
+ *
+ * @param value the raw value
+ * @param parent the parent element
+ * @param the JsonValue type
+ * @param the raw value type
+ * @return a new JsonValue
+ * @deprecated Do not use, will be removed at a later date
+ */
+ @Deprecated
JsonValue newValue(T value, JsonElement parent);
+ /**
+ * Create a new JsonObject
+ *
+ * @return a new JsonObject instance
+ */
JsonObject newObject();
+ /**
+ * Create a new JsonObject
+ *
+ * @param parent the parent element
+ * @return a new JsonObject instance
+ * @deprecated do not use, will be removed
+ */
+ @Deprecated
JsonObject newObject(JsonElement parent);
+ /**
+ * Create a new JsonArray
+ *
+ * @return a new JsonArray
+ */
JsonArray newArray();
+ /**
+ * Create a new JsonArray
+ *
+ * @param parent the parent element
+ * @return a new JsonArray
+ * @deprecated do not use, will be removed
+ */
+ @Deprecated
JsonArray newArray(JsonElement parent);
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/FixedNumberValueType.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/FixedNumberValueType.java
index 3c4b2fe..8d0c09a 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/FixedNumberValueType.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/FixedNumberValueType.java
@@ -2,7 +2,13 @@
import java.math.BigInteger;
+/**
+ * An enumeration of fixed number strategies
+ */
public enum FixedNumberValueType implements NumericValueType {
+ /**
+ * Integer
+ */
INTEGER {
@Override
public Number apply(String numericString) {
@@ -10,6 +16,9 @@ public Number apply(String numericString) {
}
},
+ /**
+ * Long
+ */
LONG {
@Override
public Number apply(String numericString) {
@@ -17,6 +26,9 @@ public Number apply(String numericString) {
}
},
+ /**
+ * Big Integer
+ */
BIG_INTEGER {
@Override
public Number apply(String numericString) {
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/FloatingNumberValueType.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/FloatingNumberValueType.java
index 9e70bbd..5dd211c 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/FloatingNumberValueType.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/FloatingNumberValueType.java
@@ -2,7 +2,13 @@
import java.math.BigDecimal;
+/**
+ * An enumeration of floating number strategies
+ */
public enum FloatingNumberValueType implements NumericValueType {
+ /**
+ * Float
+ */
FLOAT {
@Override
public Number apply(String numericString) {
@@ -10,6 +16,9 @@ public Number apply(String numericString) {
}
},
+ /**
+ * Double
+ */
DOUBLE {
@Override
public Number apply(String numericString) {
@@ -17,6 +26,9 @@ public Number apply(String numericString) {
}
},
+ /**
+ * Big Decimal
+ */
BIG_DECIMAL {
@Override
public Number apply(String numericString) {
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/InputData.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/InputData.java
index 6963876..8a5bd26 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/InputData.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/InputData.java
@@ -12,16 +12,39 @@
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
+/**
+ * Utility class the takes an input and converts it to an InputStream for used by a Parser
+ *
+ * @param inputStream
+ */
public record InputData(InputStream inputStream) implements AutoCloseable {
+ /**
+ * Return the inputStream for this data
+ *
+ * @return the inputstream
+ */
public InputStream getInputStream() {
return inputStream;
}
+ /**
+ * Create an InputData from a Json String
+ *
+ * @param data the Json String
+ * @return a new InputData
+ */
public static InputData of(final String data) {
return of(data, StandardCharsets.UTF_8);
}
+ /**
+ * Create an InputData from a Json String
+ *
+ * @param data the Json String
+ * @param charSet the character set
+ * @return a new InputData
+ */
public static InputData of(final String data, final Charset charSet) {
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data.getBytes(charSet))) {
return new InputData(byteArrayInputStream);
@@ -30,6 +53,12 @@ public static InputData of(final String data, final Charset charSet) {
}
}
+ /**
+ * Create an InputData from a Path
+ *
+ * @param path the Path
+ * @return a new InputData
+ */
public static InputData of(final Path path) {
try (InputStream inputStream = Files.newInputStream(path, StandardOpenOption.READ)) {
return new InputData(inputStream);
@@ -38,6 +67,12 @@ public static InputData of(final Path path) {
}
}
+ /**
+ * Create an InputData from a Reader
+ *
+ * @param reader the Json String
+ * @return a new InputData
+ */
public static InputData of(final Reader reader) {
try {
char[] charBuffer = new char[8 * 1024];
@@ -57,10 +92,21 @@ public static InputData of(final Reader reader) {
}
+ /**
+ * Create an InputData from an InputStream
+ *
+ * @param inputStream the Json String
+ * @return a new InputData
+ */
public static InputData of(final InputStream inputStream) {
return new InputData(inputStream);
}
+ /**
+ * Close the underlying inputstream
+ *
+ * @throws Exception thrown if a problem occurs
+ */
@Override
public void close() throws Exception {
if (this.inputStream != null) {
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/JsonEventParserException.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/JsonEventParserException.java
index 062aa44..2f0fb29 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/JsonEventParserException.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/JsonEventParserException.java
@@ -1,34 +1,51 @@
package io.github.xmljim.json.factory.parser;
+/**
+ * An event parser exception
+ */
public class JsonEventParserException extends JsonParserException {
private int line = -1;
private int column = -1;
+ /**
+ * Constructor
+ */
public JsonEventParserException() {
}
+
+ /**
+ * Constructor
+ *
+ * @param lineNumber line number
+ * @param column column
+ * @param message message
+ */
public JsonEventParserException(int lineNumber, int column, String message) {
super(message + " [at line: " + lineNumber + "; col: " + column + "]");
this.line = lineNumber;
this.column = column;
}
+ /**
+ * Constructor
+ *
+ * @param message message
+ */
public JsonEventParserException(final String message) {
super(message);
}
- public JsonEventParserException(final String message, final Throwable cause) {
- super(message, cause);
- }
+ /**
+ * Constructor
+ *
+ * @param cause the underlying exception
+ */
public JsonEventParserException(final Throwable cause) {
super(cause);
}
- public JsonEventParserException(final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace) {
- super(message, cause, enableSuppression, writableStackTrace);
- }
-
public long getLineNumber() {
return line;
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/JsonParserException.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/JsonParserException.java
index fbec94a..cdb6ab5 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/JsonParserException.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/JsonParserException.java
@@ -2,24 +2,33 @@
import io.github.xmljim.json.exception.JsonException;
+/**
+ * A parser exception
+ */
public class JsonParserException extends JsonException {
+ /**
+ * Constructor
+ */
public JsonParserException() {
super();
}
+ /**
+ * Constructor
+ *
+ * @param message message
+ */
public JsonParserException(String message) {
super(message);
}
- public JsonParserException(String message, Throwable cause) {
- super(message, cause);
- }
-
+ /**
+ * Constructor
+ *
+ * @param cause the underlying exception
+ */
public JsonParserException(Throwable cause) {
super(cause);
}
- protected JsonParserException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
- super(message, cause, enableSuppression, writableStackTrace);
- }
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/NumericValueType.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/NumericValueType.java
index a66fad1..fcbc152 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/NumericValueType.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/NumericValueType.java
@@ -1,5 +1,9 @@
package io.github.xmljim.json.factory.parser;
+
+/**
+ * Applies a number value to a numeric string
+ */
@FunctionalInterface
public interface NumericValueType {
Number apply(String numericString);
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/Parser.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/Parser.java
index 644dbe5..e7d9c60 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/Parser.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/Parser.java
@@ -4,12 +4,32 @@
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
+/**
+ * A JSON Parser
+ */
public interface Parser {
+ /**
+ * Return the Parser's settings
+ *
+ * @return the parser settings
+ */
ParserSettings getSettings();
+ /**
+ * Utility method to apply parser settings
+ *
+ * @param settings the parser settings
+ */
void setSettings(ParserSettings settings);
+ /**
+ * Parse the data
+ *
+ * @param data the input data
+ * @param the data format
+ * @return the parsed JSON data in the format requested
+ */
default T parse(InputData data) {
initializeProcessor();
@@ -31,10 +51,18 @@ default T parse(InputData data) {
}
+ /**
+ * Initialize the Processer used by this parser
+ */
default void initializeProcessor() {
getSettings().getProcessor().subscribe(getSettings().getEventHandler());
}
+ /**
+ * Return the statistics from the parsing
+ *
+ * @return the statistics
+ */
default Statistics getStatistics() {
Statistics statistics = new Statistics();
if (getSettings().enableStatistics()) {
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/ParserBuilder.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/ParserBuilder.java
index 278fcb7..4242ec0 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/ParserBuilder.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/ParserBuilder.java
@@ -6,34 +6,154 @@
import java.nio.charset.Charset;
+/**
+ * Builder interface for creating a Parser with given settings
+ */
public interface ParserBuilder {
+ /**
+ * Specify a parser implementation
+ *
+ * @param parser the parser
+ * @return the builder
+ */
ParserBuilder withParser(Parser parser);
+ /**
+ * Specify the JSON character set to use
+ *
+ * @param characterSet the character set
+ * @return the builder
+ */
ParserBuilder setCharacterSet(Charset characterSet);
+ /**
+ * Specify the Event Handler implementation to use
+ *
+ * @param handler the event handler
+ * @return the builder
+ */
ParserBuilder setEventHandler(EventHandler handler);
+ /**
+ * Specify the Assembler to use with the Event Handler
+ *
+ * @param assembler the assembler
+ * @return the builder
+ */
ParserBuilder setAssembler(Assembler> assembler);
+ /**
+ * Specify a Processor that will process the JSON data
+ *
+ * @param processor the processor
+ * @return the builder
+ */
ParserBuilder withProcessor(Processor processor);
+ /**
+ * Specify a fixed number strategy (i.e., use a Long or Integer as a default)
+ *
+ * @param numberStrategy the number strategy
+ * @return the builder
+ */
ParserBuilder setFixedNumberStrategy(NumericValueType numberStrategy);
+ /**
+ * Specify a floating number strategy (i.e., Float or Double)
+ *
+ * @param numberStrategy the number strategy
+ * @return the builder
+ */
ParserBuilder setFloatingNumberStrategy(NumericValueType numberStrategy);
+ /**
+ * Specify whether or not use strict EMCA encoding rules
+ *
+ * @param useStrict true to use strict, false otherwise
+ * @return the builder
+ */
ParserBuilder setUseStrict(boolean useStrict);
+ /**
+ * Specify the block size to use with the Processor to process data.
+ * Note: Not all Processors will recognize this value
+ *
+ * @param blockCount the block size
+ * @return the builder
+ */
ParserBuilder setBlockCount(int blockCount);
+ /**
+ * Specify the MaxEventBufferCapacity to be used by EventHandlers for subscribed events.
+ * Not: Not all EventHandlers will recognize or use this value
+ *
+ * @param capacity the capacity
+ * @return the builder
+ */
ParserBuilder setMaxEventBufferCapacity(int capacity);
+ /**
+ * Specify a custom setting. These will be implementation specific
+ *
+ * @param name the setting name
+ * @param value the setting value
+ * @param The value type
+ * @return the bulder
+ */
ParserBuilder setSetting(String name, T value);
+ /**
+ * Return the default settings
+ *
+ * @return the builder
+ */
ParserBuilder withDefaultSettings();
+ default ParserBuilder mergeSettings(ParserSettings settings) {
+ if (settings.getAssembler() != null) {
+ setAssembler(settings.getAssembler());
+ }
+
+ setBlockCount(settings.getBlockCount());
+
+ if (settings.getCharacterSet() != null) {
+ setCharacterSet(settings.getCharacterSet());
+ }
+
+ if (settings.getEventHandler() != null) {
+ setEventHandler(settings.getEventHandler());
+ }
+
+ if (settings.fixedNumberStrategy() != null) {
+ setFixedNumberStrategy(settings.fixedNumberStrategy());
+ }
+
+ if (settings.floatingNumberStrategy() != null) {
+ setFloatingNumberStrategy(settings.floatingNumberStrategy());
+ }
+
+ setMaxEventBufferCapacity(settings.getMaxEventBufferCapacity());
+ setUseStrict(settings.useStrict());
+
+ if (settings.getProcessor() != null) {
+ withProcessor(settings.getProcessor());
+ }
+ return this;
+ }
+
+ /**
+ * Create a new Parser
+ *
+ * @return
+ */
Parser build();
+ /**
+ * Create a parser with default settings.
+ *
+ * @return
+ */
default Parser defaultParser() {
return withDefaultSettings().build();
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/ParserFactory.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/ParserFactory.java
index 25f8b79..a3d0507 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/ParserFactory.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/ParserFactory.java
@@ -2,9 +2,23 @@
import io.github.xmljim.json.service.JsonService;
+/**
+ * Factory/Service for the Json Parser
+ */
public interface ParserFactory extends JsonService {
+
+ /**
+ * Create a new builder to configure and build a Parser
+ *
+ * @return a new ParserBuilder
+ */
ParserBuilder newParserBuilder();
+ /**
+ * Create a new Parser with default settings
+ *
+ * @return a new Parser
+ */
default Parser newParser() {
return newParserBuilder().defaultParser();
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/ParserSettings.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/ParserSettings.java
index 2cb12f4..a596120 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/ParserSettings.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/ParserSettings.java
@@ -6,33 +6,107 @@
import java.nio.charset.Charset;
+/**
+ * Parser settings. Note that not all Parsers or constituent components
+ * orchestrated by the Parser will recognize or use these settings
+ */
public interface ParserSettings {
+ /**
+ * Returns whether nor not to enable statistics
+ *
+ * @return true to enable statistics; false otherwise
+ */
boolean enableStatistics();
+ /**
+ * Return the fixed number strategy
+ *
+ * @return the fixed number strategy for Json number values
+ */
NumericValueType fixedNumberStrategy();
+ /**
+ * Return the floating number strategy
+ *
+ * @return the floating number strategy
+ */
NumericValueType floatingNumberStrategy();
+ /**
+ * Return the Processor to use
+ *
+ * @return the Processor
+ */
Processor getProcessor();
+ /**
+ * Return the Event Handler to use
+ *
+ * @return the Event Handler
+ */
EventHandler getEventHandler();
+ /**
+ * Return the Assembler to use
+ *
+ * @param The assembler type/format
+ * @return the Assembler
+ */
Assembler getAssembler();
+ /**
+ * Return the character set to use for parsing
+ *
+ * @return the character set
+ */
Charset getCharacterSet();
+ /**
+ * Return the Maximum Event Buffer Capacity to use with Event subscriptions
+ *
+ * @return the Maximum Event Buffer Capacity to use with Event subscriptions
+ */
int getMaxEventBufferCapacity();
+ /**
+ * Return the number of events to send via subscription
+ *
+ * @return the number of events
+ */
long getRequestNextLength();
+ /**
+ * Return block count
+ *
+ * @return the block count
+ */
int getBlockCount();
+ /**
+ * Return the block size
+ *
+ * @return the block size
+ */
default int getBlockSizeBytes() {
return getBlockCount() * 1024;
}
+ /**
+ * Return whether to use strict ECMA rules for parsing
+ *
+ * @return true if using strict; false otherwise
+ */
boolean useStrict();
+ /**
+ * Return a custom setting
+ *
+ * @param name the setting name
+ * @param the value type
+ * @return the setting value
+ */
T getSetting(String name);
+ ParserSettings merge(ParserSettings settings);
+
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/Statistic.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/Statistic.java
index de2be9c..91d2021 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/Statistic.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/Statistic.java
@@ -1,10 +1,30 @@
package io.github.xmljim.json.factory.parser;
+/**
+ * A parser statistic. Can be applied to any component of the parser (i.e., Processor, EventHandler, or Assembler)
+ *
+ * @param the statistic value type
+ */
public interface Statistic {
+ /**
+ * Return the component name
+ *
+ * @return the component name
+ */
String getComponent();
+ /**
+ * Return the statistic name
+ *
+ * @return the statistic name
+ */
String getName();
+ /**
+ * return the statistic value
+ *
+ * @return the statistic value
+ */
T getValue();
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/Statistics.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/Statistics.java
index 4f1b56b..76acd6e 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/Statistics.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/Statistics.java
@@ -7,101 +7,270 @@
import java.util.Optional;
import java.util.stream.Stream;
+/**
+ * A collection of {@link Statistic} elements
+ */
public final class Statistics {
+ /**
+ * EventProcessor component
+ */
public static final String COMPONENT_EVENT_PROCESSOR = "EventProcessor";
+ /**
+ * EventHandler component
+ */
public static final String COMPONENT_EVENT_HANDLER = "EventHandler";
+ /**
+ * EventAssembler component
+ */
public static final String COMPONENT_EVENT_ASSEMBLER = "EventAssembler";
+ /**
+ * Processing Time statistic
+ */
public static final String STAT_PROCESS_TIME = "processingTime";
+ /**
+ * Bytes processed statistic
+ */
public static final String STAT_BYTES_PROCESSED = "bytesProcessed";
+ /**
+ * Event Send Time statistic
+ */
public static final String STAT_EVENT_SEND_TIME = "eventSendTime";
+ /**
+ * Entity count statistic
+ */
public static final String STAT_ENTITY_COUNT = "entityCount";
+
+ /**
+ * Assembly time statistic
+ */
public static final String STAT_ASSEMBLY_TIME = "assemblyTime";
+
+ /**
+ * Bytes per second statistic
+ */
public static final String STAT_BYTES_PER_SECOND = "bytesPerSecond";
+ /**
+ * Parsing time statistic
+ */
public static final String STAT_PARSING_TIME = "parsingTime";
+ /**
+ * Event processing time statistic
+ */
public static final String STAT_EVENT_PROCESSING_TIME = "eventProcessingTime";
+ /**
+ * Event count statistic
+ */
public static final String STAT_EVENT_COUNT = "eventCount";
+ /**
+ * Events sent per second statistic
+ */
public static final String STAT_EVENT_SEND_PER_SECOND = "eventSendPerSecond";
+ /**
+ * Entities assembled per second statistic
+ */
public static final String STAT_ASSEMBLY_ENTITY_PER_SECOND = "entitiesPerSecond";
private final Map> statisticMap = new LinkedHashMap<>();
+ /**
+ * Utility method for setting the {@link #STAT_PROCESS_TIME} linked to the
+ * {@link #COMPONENT_EVENT_PROCESSOR}
+ *
+ * @param value the value
+ * @param the value type
+ */
public void setProcessorBytesPerSecond(T value) {
setStatistic(COMPONENT_EVENT_PROCESSOR, STAT_PROCESS_TIME, value);
}
+ /**
+ * Utility method for setting the {@link #STAT_ASSEMBLY_TIME} linked to the
+ * {@link #COMPONENT_EVENT_ASSEMBLER}
+ *
+ * @param value the value
+ * @param the value type
+ */
public void setAssemblyTime(T value) {
setStatistic(COMPONENT_EVENT_ASSEMBLER, STAT_ASSEMBLY_TIME, value);
}
+ /**
+ * Utility method for setting the {@link #STAT_BYTES_PROCESSED} linked to the
+ * {@link #COMPONENT_EVENT_PROCESSOR}
+ *
+ * @param value the value
+ * @param the value type
+ */
public void setBytesProcessed(T value) {
setStatistic(COMPONENT_EVENT_PROCESSOR, STAT_BYTES_PROCESSED, value);
}
+ /**
+ * Utility method for setting the {@link #STAT_EVENT_SEND_TIME} linked to the
+ * {@link #COMPONENT_EVENT_PROCESSOR}
+ *
+ * @param value the value
+ * @param the value type
+ */
public void setEventSendTime(T value) {
setStatistic(COMPONENT_EVENT_PROCESSOR, STAT_EVENT_SEND_TIME, value);
}
+ /**
+ * Utility method for setting the {@link #STAT_ENTITY_COUNT} linked to the
+ * {@link #COMPONENT_EVENT_ASSEMBLER}
+ *
+ * @param value the value
+ * @param the value type
+ */
public void setEntityCount(T value) {
setStatistic(COMPONENT_EVENT_ASSEMBLER, STAT_ENTITY_COUNT, value);
}
+ /**
+ * Utility method for setting the {@link #STAT_BYTES_PER_SECOND} linked to the
+ * {@link #COMPONENT_EVENT_PROCESSOR}
+ *
+ * @param value the value
+ * @param the value type
+ */
public void setBytesPerSecond(T value) {
setStatistic(COMPONENT_EVENT_PROCESSOR, STAT_BYTES_PER_SECOND, value);
}
+ /**
+ * Utility method for setting the {@link #STAT_PARSING_TIME} linked to the
+ * {@link #COMPONENT_EVENT_PROCESSOR}
+ *
+ * @param value the value
+ * @param the value type
+ */
public void setParsingTime(T value) {
setStatistic(COMPONENT_EVENT_PROCESSOR, STAT_PARSING_TIME, value);
}
+ /**
+ * Utility method for setting the {@link #STAT_PROCESS_TIME} linked to the
+ * {@link #COMPONENT_EVENT_PROCESSOR}
+ *
+ * @param value the value
+ * @param the value type
+ */
public void setProcessingTime(T value) {
setStatistic(COMPONENT_EVENT_PROCESSOR, STAT_PROCESS_TIME, value);
}
+ /**
+ * Utility method for setting the {@link #STAT_EVENT_PROCESSING_TIME} linked to the
+ * {@link #COMPONENT_EVENT_HANDLER}
+ *
+ * @param value the value
+ * @param the value type
+ */
public void setEventProcessingTime(T value) {
setStatistic(COMPONENT_EVENT_HANDLER, STAT_EVENT_PROCESSING_TIME, value);
}
+ /**
+ * Utility method for setting the {@link #STAT_ENTITY_COUNT} linked to the
+ * {@link #COMPONENT_EVENT_HANDLER}
+ *
+ * @param value the value
+ * @param the value type
+ */
public void setEventCount(T value) {
setStatistic(COMPONENT_EVENT_HANDLER, STAT_EVENT_COUNT, value);
}
+ /**
+ * Utility method for setting the {@link #STAT_EVENT_SEND_PER_SECOND} linked to the
+ * {@link #COMPONENT_EVENT_HANDLER}
+ *
+ * @param value the value
+ * @param the value type
+ */
public void setEventsSentPerSecond(T value) {
setStatistic(COMPONENT_EVENT_HANDLER, STAT_EVENT_SEND_PER_SECOND, value);
}
+ /**
+ * Utility method for setting the {@link #STAT_ASSEMBLY_ENTITY_PER_SECOND} linked to the
+ * {@link #COMPONENT_EVENT_ASSEMBLER}
+ *
+ * @param value the value
+ * @param the value type
+ */
public void setAssemblyEntitiesPerSecond(T value) {
setStatistic(COMPONENT_EVENT_ASSEMBLER, STAT_ASSEMBLY_ENTITY_PER_SECOND, value);
}
+ /**
+ * Set a statistic
+ *
+ * @param componentName the component name
+ * @param statisticName the statistic name
+ * @param value the statistic value
+ * @param value type
+ */
public void setStatistic(String componentName, String statisticName, T value) {
appendStatistic(new StatisticsRecord<>(componentName, statisticName, value));
}
+ /**
+ * Append statistic
+ *
+ * @param statistic the statistic
+ */
private void appendStatistic(Statistic extends Number> statistic) {
statisticMap.put(statistic.getName(), statistic);
}
+ /**
+ * Merge statistics
+ *
+ * @param statistics another statistics instance
+ */
public void merge(Statistics statistics) {
- statistics.stream().forEach(stat -> {
- statisticMap.putIfAbsent(stat.getName(), stat);
- });
+ statistics.stream().forEach(stat -> statisticMap.putIfAbsent(stat.getName(), stat));
}
+ /**
+ * Stream of statistics
+ *
+ * @return a stream of statistics
+ */
public Stream> stream() {
return statisticMap.values().stream();
}
+ /**
+ * Return a statistic by name
+ *
+ * @param statisticName the statistic name
+ * @return the statistic
+ */
public Optional> getByName(String statisticName) {
return Optional.ofNullable(statisticMap.getOrDefault(statisticName, null));
}
+ /**
+ * Return a list of statistics by component name
+ *
+ * @param component the component name
+ * @return the list of statistics
+ */
public List> getByComponent(String component) {
return stream().filter(stat -> stat.getComponent().equals(component)).toList();
}
+ /**
+ * Convert the statistics to a string output
+ *
+ * @return the statistics to a string output
+ */
public String toString() {
StringBuilder builder = new StringBuilder();
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/Assembler.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/Assembler.java
index 0cae87f..82b412f 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/Assembler.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/Assembler.java
@@ -6,6 +6,11 @@
import java.math.BigDecimal;
import java.util.function.Supplier;
+/**
+ * Assembles a specific format instance from incoming JsonEvents
+ *
+ * @param The format type
+ */
public interface Assembler extends Configurable {
/**
@@ -114,9 +119,24 @@ public interface Assembler extends Configurable {
*/
void valueNull(String key);
+ /**
+ * Assembled from a new key
+ *
+ * @param key The key name
+ */
void newKey(String key);
+ /**
+ * Return the formatted result
+ *
+ * @return the formatted result
+ */
Supplier getResult();
+ /**
+ * Return the Statistics associated with the assembler
+ *
+ * @return the statistics associated with the assembler
+ */
Statistics getStatistics();
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/Configurable.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/Configurable.java
index a874c91..2591682 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/Configurable.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/Configurable.java
@@ -2,9 +2,22 @@
import io.github.xmljim.json.factory.parser.ParserSettings;
+/**
+ * Wrapper interface for configuration
+ */
public interface Configurable {
+ /**
+ * Set settings
+ *
+ * @param settings the parser settings
+ */
void setSettings(ParserSettings settings);
+ /**
+ * return the Parser settings
+ *
+ * @return the parser settings
+ */
ParserSettings getSettings();
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/EventHandler.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/EventHandler.java
index ac38e45..ca6a4ee 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/EventHandler.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/EventHandler.java
@@ -4,11 +4,30 @@
import java.util.concurrent.Flow;
+/**
+ * Interface for Event Handlers. It extends the Flow API Subscriber interface so that
+ * it can receive events from a {@link Processor} (which is a {@link Flow.Publisher})
+ */
public interface EventHandler extends Flow.Subscriber, Configurable {
+ /**
+ * Returns whether the event handler is complete
+ *
+ * @return true if complete
+ */
boolean isComplete();
+ /**
+ * Return the Assembler associated with this event handler
+ *
+ * @return the Assembler
+ */
Assembler> getAssembler();
+ /**
+ * Return the statistics from this event handler
+ *
+ * @return the statistics
+ */
Statistics getStatistics();
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/EventPublisher.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/EventPublisher.java
index 0ca1931..1c604a6 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/EventPublisher.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/EventPublisher.java
@@ -2,6 +2,9 @@
import java.util.concurrent.Flow;
+/**
+ * Tagging interface that extends the Flow.Publisher interface
+ */
public interface EventPublisher extends Flow.Publisher {
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/EventType.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/EventType.java
index 7cb8b52..1b352df 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/EventType.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/EventType.java
@@ -1,20 +1,74 @@
package io.github.xmljim.json.factory.parser.event;
+/**
+ * Enumeration of event types
+ */
public enum EventType {
+ /**
+ * Document Start - either with a {
or {@code [}
+ */
DOCUMENT_START,
+ /**
+ * Document End
+ */
DOCUMENT_END,
+ /**
+ * JsonObject start - with a {
+ */
OBJECT_START,
+ /**
+ * JsonObject end
+ */
OBJECT_END,
+ /**
+ * JsonArray start
+ */
ARRAY_START,
+ /**
+ * JsonArray end
+ */
ARRAY_END,
+ /**
+ * String value start
+ */
STRING_START,
+ /**
+ * String value end
+ */
STRING_END,
+ /**
+ * Number value start
+ */
NUMBER_START,
+ /**
+ * Number value end
+ */
NUMBER_END,
+ /**
+ * Boolean value start
+ */
BOOLEAN_START,
+
+ /**
+ * Boolean value end
+ */
BOOLEAN_END,
+ /**
+ * Null value start
+ */
NULL_START,
+ /**
+ * Null value end
+ */
NULL_END,
+
+ /**
+ * JsonObject key start
+ */
KEY_END,
+
+ /**
+ * JsonObject key end
+ */
ENTITY_END
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/JsonAssembler.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/JsonAssembler.java
index 4413a89..fc31e09 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/JsonAssembler.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/JsonAssembler.java
@@ -2,5 +2,8 @@
import io.github.xmljim.json.model.JsonNode;
+/**
+ * Tagging interface for Assemblers that create Json instances
+ */
public interface JsonAssembler extends Assembler {
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/JsonEvent.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/JsonEvent.java
index 529bc10..0a1cc5d 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/JsonEvent.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/JsonEvent.java
@@ -2,12 +2,36 @@
import java.nio.ByteBuffer;
+/**
+ * A processing event produced by a {@link Processor}, handled by
+ * an {@link EventHandler} and then subsequently assembed by an {@link Assembler}
+ */
public interface JsonEvent {
+ /**
+ * The column number for the event
+ *
+ * @return the column number for the event
+ */
int getColumn();
+ /**
+ * The line number of the event
+ *
+ * @return the line number of the event
+ */
int getLineNumber();
+ /**
+ * The data associated with the event
+ *
+ * @return the data associated with the event
+ */
ByteBuffer getData();
+ /**
+ * The event type
+ *
+ * @return the event type
+ */
EventType getEventType();
}
diff --git a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/Processor.java b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/Processor.java
index 5f9c9c1..855406f 100644
--- a/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/Processor.java
+++ b/jsonfactory/src/main/java/io/github/xmljim/json/factory/parser/event/Processor.java
@@ -4,9 +4,23 @@
import java.io.InputStream;
+/**
+ * The Json Processer, which processes the JSON data and passes the data
+ * as events to an {@link EventHandler}
+ */
public interface Processor extends EventPublisher, Configurable {
+ /**
+ * Begin processing the data
+ *
+ * @param inputStream the input stream containing the JSON data
+ */
void process(InputStream inputStream);
+ /**
+ * Return the Statistics associated with this processor
+ *
+ * @return the Statistics associated with this processor
+ */
Statistics getStatistics();
}
diff --git a/jsonfactory/src/main/java/module-info.java b/jsonfactory/src/main/java/module-info.java
index ea64d79..3419fe9 100644
--- a/jsonfactory/src/main/java/module-info.java
+++ b/jsonfactory/src/main/java/module-info.java
@@ -11,4 +11,6 @@
exports io.github.xmljim.json.service;
exports io.github.xmljim.json.service.exception;
exports io.github.xmljim.json.factory.jsonpath;
+ exports io.github.xmljim.json.factory.config;
+ exports io.github.xmljim.json.factory.mapper.parser;
}
\ No newline at end of file
diff --git a/jsonfactory/src/test/java/io/github/xmljim/json/factory/test/ServiceManagerTests.java b/jsonfactory/src/test/java/io/github/xmljim/json/factory/test/ServiceManagerTests.java
new file mode 100644
index 0000000..11d0da4
--- /dev/null
+++ b/jsonfactory/src/test/java/io/github/xmljim/json/factory/test/ServiceManagerTests.java
@@ -0,0 +1,50 @@
+package io.github.xmljim.json.factory.test;
+
+import io.github.xmljim.json.factory.jsonpath.JsonPathFactory;
+import io.github.xmljim.json.factory.mapper.MapperFactory;
+import io.github.xmljim.json.factory.model.ElementFactory;
+import io.github.xmljim.json.factory.parser.ParserFactory;
+import io.github.xmljim.json.service.JsonService;
+import io.github.xmljim.json.service.ServiceManager;
+import io.github.xmljim.json.service.exception.JsonServiceProviderUnavailableException;
+import org.junit.jupiter.api.Test;
+
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class ServiceManagerTests {
+
+ @Test
+ void testGetProviderFails() {
+
+ assertFalse(ServiceManager.isServiceAvailable(ElementFactory.class));
+ assertThrows(JsonServiceProviderUnavailableException.class,
+ () -> ServiceManager.getProvider(MapperFactory.class));
+ }
+
+ @Test
+ void testGetProviderSuccess() {
+ ParserFactory parserFactory = ServiceManager.getProvider(ParserFactory.class);
+ assertTrue(parserFactory instanceof TestServiceClass);
+ }
+
+ @Test
+ void testListServices() {
+ Set serviceSet = ServiceManager.listServices();
+
+ assertEquals(1, serviceSet.size());
+ assertTrue(serviceSet.iterator().next() instanceof TestServiceClass);
+ }
+
+ @Test
+ void testListServiceProviders() {
+ assertTrue(ServiceManager.listProviders(ElementFactory.class).isEmpty());
+ assertTrue(ServiceManager.listProviders(JsonPathFactory.class).isEmpty());
+
+ Set serviceProviders = ServiceManager.listProviders(ParserFactory.class);
+ assertEquals(1, serviceProviders.size());
+ assertTrue(serviceProviders.iterator().next() instanceof TestServiceClass);
+ }
+
+}
diff --git a/jsonfactory/src/test/java/io/github/xmljim/json/factory/test/TestServiceClass.java b/jsonfactory/src/test/java/io/github/xmljim/json/factory/test/TestServiceClass.java
new file mode 100644
index 0000000..5354da7
--- /dev/null
+++ b/jsonfactory/src/test/java/io/github/xmljim/json/factory/test/TestServiceClass.java
@@ -0,0 +1,18 @@
+package io.github.xmljim.json.factory.test;
+
+import io.github.xmljim.json.factory.parser.ParserBuilder;
+import io.github.xmljim.json.factory.parser.ParserFactory;
+import io.github.xmljim.json.service.JsonServiceProvider;
+
+@JsonServiceProvider(version = "0.1.1", service = ParserFactory.class)
+public class TestServiceClass implements ParserFactory {
+
+ public TestServiceClass() {
+ //no-op
+ }
+
+ @Override
+ public ParserBuilder newParserBuilder() {
+ return null;
+ }
+}
diff --git a/jsonfactory/src/test/java/module-info.java b/jsonfactory/src/test/java/module-info.java
new file mode 100644
index 0000000..cc348ab
--- /dev/null
+++ b/jsonfactory/src/test/java/module-info.java
@@ -0,0 +1,15 @@
+import io.github.xmljim.json.factory.parser.ParserFactory;
+import io.github.xmljim.json.factory.test.TestServiceClass;
+
+module io.github.xmljim.json.factory.test {
+
+ requires transitive io.github.xmljim.json.factory;
+
+ opens io.github.xmljim.json.factory.test;
+
+ //These dependencies are needed to run tests
+ requires org.junit.jupiter.api;
+ requires org.junit.jupiter.engine;
+
+ provides ParserFactory with TestServiceClass;
+}
\ No newline at end of file
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/compiler/Compiler.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/compiler/Compiler.java
index a525a34..34b744c 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/compiler/Compiler.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/compiler/Compiler.java
@@ -10,7 +10,6 @@
/**
* Base class for JsonPath expression compilation
- *
* @param The return result argType from the compilation
*/
public abstract class Compiler {
@@ -42,7 +41,7 @@ public abstract class Compiler {
private final Deque enclosures = new ArrayDeque<>();
private final Global global;
- protected Compiler(PathExpression expression, Global global) {
+ protected Compiler(@SuppressWarnings("ClassEscapesDefinedScope") PathExpression expression, Global global) {
this.expression = expression;
this.global = global;
}
@@ -59,6 +58,7 @@ public static Compiler> newPredicateCompiler(String expressio
return new PredicateCompiler(new PathExpression(expression), global);
}
+ @SuppressWarnings("ClassEscapesDefinedScope")
public PathExpression expression() {
return expression;
}
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/Accessor.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/Accessor.java
similarity index 97%
rename from jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/Accessor.java
rename to jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/Accessor.java
index 72cca42..8dcd693 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/Accessor.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/Accessor.java
@@ -1,4 +1,4 @@
-package io.github.xmljim.json.jsonpath.filter;
+package io.github.xmljim.json.jsonpath.context;
import java.util.Objects;
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/ArrayContext.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/ArrayContext.java
index 1c016aa..6cc0ffa 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/ArrayContext.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/ArrayContext.java
@@ -1,6 +1,5 @@
package io.github.xmljim.json.jsonpath.context;
-import io.github.xmljim.json.jsonpath.filter.Accessor;
import io.github.xmljim.json.model.JsonArray;
import java.util.stream.IntStream;
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/Context.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/Context.java
index 390d1b7..205487c 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/Context.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/Context.java
@@ -2,7 +2,6 @@
import io.github.xmljim.json.factory.model.ElementFactory;
import io.github.xmljim.json.jsonpath.JsonPathException;
-import io.github.xmljim.json.jsonpath.filter.Accessor;
import io.github.xmljim.json.jsonpath.util.DataType;
import io.github.xmljim.json.model.JsonArray;
import io.github.xmljim.json.model.JsonElement;
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/DateContext.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/DateContext.java
index 73232da..af6c19e 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/DateContext.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/DateContext.java
@@ -4,7 +4,7 @@
import java.time.LocalDate;
-public class DateContext extends TemporalContext {
+class DateContext extends TemporalContext {
public DateContext(LocalDate value) {
super(value);
}
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/DateTimeContext.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/DateTimeContext.java
index da502d1..349ee03 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/DateTimeContext.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/DateTimeContext.java
@@ -4,7 +4,7 @@
import java.time.LocalDateTime;
-public class DateTimeContext extends TemporalContext {
+class DateTimeContext extends TemporalContext {
public DateTimeContext(LocalDateTime value) {
super(value);
}
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/ObjectContext.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/ObjectContext.java
index c97a6e8..62f3b78 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/ObjectContext.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/ObjectContext.java
@@ -1,6 +1,5 @@
package io.github.xmljim.json.jsonpath.context;
-import io.github.xmljim.json.jsonpath.filter.Accessor;
import io.github.xmljim.json.model.JsonObject;
import java.util.stream.Stream;
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/ValueContext.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/ValueContext.java
index 696d860..ade99f3 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/ValueContext.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/context/ValueContext.java
@@ -1,6 +1,5 @@
package io.github.xmljim.json.jsonpath.context;
-import io.github.xmljim.json.jsonpath.filter.Accessor;
import io.github.xmljim.json.model.JsonValue;
import java.util.stream.Stream;
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/ChildFilter.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/ChildFilter.java
index f5ed24e..55831aa 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/ChildFilter.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/ChildFilter.java
@@ -1,5 +1,6 @@
package io.github.xmljim.json.jsonpath.filter;
+import io.github.xmljim.json.jsonpath.context.Accessor;
import io.github.xmljim.json.jsonpath.context.Context;
import io.github.xmljim.json.jsonpath.util.Global;
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/SliceFilter.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/SliceFilter.java
index 3ae0925..2193e05 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/SliceFilter.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/SliceFilter.java
@@ -1,6 +1,7 @@
package io.github.xmljim.json.jsonpath.filter;
import io.github.xmljim.json.jsonpath.compiler.JsonPathExpressionException;
+import io.github.xmljim.json.jsonpath.context.Accessor;
import io.github.xmljim.json.jsonpath.context.Context;
import io.github.xmljim.json.jsonpath.util.Global;
import io.github.xmljim.json.model.JsonArray;
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/UnionFilter.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/UnionFilter.java
index 6421be0..a1fafe7 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/UnionFilter.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/filter/UnionFilter.java
@@ -1,5 +1,6 @@
package io.github.xmljim.json.jsonpath.filter;
+import io.github.xmljim.json.jsonpath.context.Accessor;
import io.github.xmljim.json.jsonpath.context.Context;
import io.github.xmljim.json.jsonpath.util.Global;
import io.github.xmljim.json.model.JsonArray;
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/function/FunctionFactory.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/function/FunctionFactory.java
index efff626..e8e0447 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/function/FunctionFactory.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/function/FunctionFactory.java
@@ -7,14 +7,28 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
-import java.util.*;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FunctionFactory {
- private static final String FUNCTION_PATTERN = "(?[a-z0-9\\-]+)\\((?.*)\\)";
- private static final String ARGS_PATTERN = "(([@$.a-zA-Z\\d_\\-'{}*#]+(\\[[,:a-z\\d'-]+])*)(\\s[!<>=a-z]+\\s\\2?)?(\\s?[&|]{2}\\s?)?)+";//"(([@$.a-zA-Z0-9_\\-'{}#\\[,:\\]]+)(\\s?[=!<>a-z]+\\s)?([@$.a-zA-Z0-9_\\-'{}#\\[,:\\]]+)?(\\s?[&|]+\\s?)?([@$.a-zA-Z0-9_\\-'{}#\\[,:\\]]+)(\\s?[=!<>a-z]+\\s)?([@$.a-zA-Z0-9_\\-'{}#\\[,\\]]+)?)(,\\s?((([@$.a-zA-Z0-9_\\-'{}#\\[,:\\]]+)(\\s?[=!<>a-z]+\\s)?([@$.a-zA-Z0-9_\\-'{}#\\[,:\\]]+)?(\\s?[&|]+\\s?)?([@$.a-zA-Z0-9_\\-'{}#\\[,:\\]]+)(\\s?[=!<>a-z]+\\s)?([@$.a-zA-Z0-9_\\-'{}#\\[,:\\]]+)?)))*";
+ private static final String FUNCTION_PATTERN = "(?[a-zA-Z0-9_\\-]+)\\((?.*)\\)";
+ private static final String PATH_PATTERN = "([@$.a-zA-Z\\d_\\-'{}*#]+(\\[[,:a-z\\d'-]+])*)";
+ private static final String OPERATOR_PATTERN = "(\\s[!<>=a-z]+\\s\\2?)?";
+ private static final String JUNCTION_PATTERN = "(\\s?[&|]{2}\\s?)?";
+ private static final String MATH_OPERATOR_PATTERN = "(\\s?[+-*/%^])?";
+ private static final String ARG_SEPARATOR_PATTERN = "(,\\s?)?";
+ private static final String ARGUMENTS_PATTERN = "(?(" + PATH_PATTERN + MATH_OPERATOR_PATTERN + OPERATOR_PATTERN + JUNCTION_PATTERN + ARG_SEPARATOR_PATTERN + ")*)";
+ private static final String FUNCTION_NAME = "(?[a-zA-Z0-9_\\-]+)";
+ private static final String FULL_PATTERN = FUNCTION_NAME + "\\(" + ARGUMENTS_PATTERN + "\\)";
+ private static final String ARGS_PATTERN = "(([@$.a-zA-Z\\d_\\-'{}*#]+(\\[[,:a-z\\d'-]+])*)(\\s[!<>=~a-z]+\\s\\2?)?(\\s?[&|]{2}\\s?)?)+";//"(([@$.a-zA-Z0-9_\\-'{}#\\[,:\\]]+)(\\s?[=!<>a-z]+\\s)?([@$.a-zA-Z0-9_\\-'{}#\\[,:\\]]+)?(\\s?[&|]+\\s?)?([@$.a-zA-Z0-9_\\-'{}#\\[,:\\]]+)(\\s?[=!<>a-z]+\\s)?([@$.a-zA-Z0-9_\\-'{}#\\[,\\]]+)?)(,\\s?((([@$.a-zA-Z0-9_\\-'{}#\\[,:\\]]+)(\\s?[=!<>a-z]+\\s)?([@$.a-zA-Z0-9_\\-'{}#\\[,:\\]]+)?(\\s?[&|]+\\s?)?([@$.a-zA-Z0-9_\\-'{}#\\[,:\\]]+)(\\s?[=!<>a-z]+\\s)?([@$.a-zA-Z0-9_\\-'{}#\\[,:\\]]+)?)))*";
+
public static JsonPathFunction createFunction(String expression, Global global) {
Pattern functionPattern = Pattern.compile(FUNCTION_PATTERN);
@@ -24,8 +38,8 @@ public static JsonPathFunction createFunction(String expression, Global global)
String fxName = matcher.group("function");
FunctionInfo functionInfo = global.getFunctionRegistry()
- .getFunctionInfo(fxName)
- .orElseThrow(() -> new JsonPathException("Function not found: " + fxName));
+ .getFunctionInfo(fxName)
+ .orElseThrow(() -> new JsonPathException("Function not found: " + fxName));
String argsString = matcher.group("args");
@@ -50,8 +64,8 @@ public static JsonPathFunction createFunction(String expression, Global global)
while (matcher.find()) {
if (matcher.group() != null && !"".equals(matcher.group())) {
argExpressions.add(matcher.group().strip().endsWith(",") ?
- matcher.group().strip().substring(0, matcher.group().strip().length() - 1) :
- matcher.group().strip());
+ matcher.group().strip().substring(0, matcher.group().strip().length() - 1) :
+ matcher.group().strip());
}
}
if (functionInfo.arguments().length != 0) {
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/predicate/IsNotNullPredicate.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/predicate/IsNotNullPredicate.java
index d7c5331..774d9db 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/predicate/IsNotNullPredicate.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/predicate/IsNotNullPredicate.java
@@ -1,7 +1,7 @@
package io.github.xmljim.json.jsonpath.predicate;
+import io.github.xmljim.json.jsonpath.context.Accessor;
import io.github.xmljim.json.jsonpath.context.Context;
-import io.github.xmljim.json.jsonpath.filter.Accessor;
import io.github.xmljim.json.jsonpath.filter.Filter;
import io.github.xmljim.json.jsonpath.filter.FilterType;
import io.github.xmljim.json.jsonpath.predicate.expression.Expression;
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/predicate/LessThanOrEqualPredicate.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/predicate/LessThanOrEqualPredicate.java
index 9152b04..31be110 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/predicate/LessThanOrEqualPredicate.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/predicate/LessThanOrEqualPredicate.java
@@ -21,7 +21,7 @@ public boolean test(Context context) {
int size = leftSide().size(context);
List vals = leftSide().values(context);
if ((leftSide().size(context) == 1 && leftSide().getContextType(context).isNumeric())
- && (rightSide().size(context) == 1 && rightSide().getContextType(context).isNumeric())) {
+ && (rightSide().size(context) == 1 && rightSide().getContextType(context).isNumeric())) {
Number left = (Number) leftSide().getValue(context).orElse(0);
Number right = (Number) rightSide().getValue(context).orElse(-1);
diff --git a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/predicate/expression/FunctionExpression.java b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/predicate/expression/FunctionExpression.java
index a27a4a2..7701f2d 100644
--- a/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/predicate/expression/FunctionExpression.java
+++ b/jsonpath/src/main/java/io/github/xmljim/json/jsonpath/predicate/expression/FunctionExpression.java
@@ -1,18 +1,16 @@
package io.github.xmljim.json.jsonpath.predicate.expression;
+import io.github.xmljim.json.jsonpath.context.Context;
import io.github.xmljim.json.jsonpath.function.FunctionFactory;
import io.github.xmljim.json.jsonpath.function.JsonPathFunction;
-import io.github.xmljim.json.jsonpath.util.Global;
-import io.github.xmljim.json.jsonpath.context.Context;
import io.github.xmljim.json.jsonpath.util.DataType;
+import io.github.xmljim.json.jsonpath.util.Global;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
public class FunctionExpression extends CachedExpression {
private final JsonPathFunction function;
- private final ConcurrentHashMap> concurrentHashMap = new ConcurrentHashMap<>();
+ //private final ConcurrentHashMap> concurrentHashMap = new ConcurrentHashMap<>();
public FunctionExpression(String expression, Global global) {
super(expression, global);
diff --git a/jsonpath/src/test/java/io/github/xmljim/json/jsonpath/test/compiler/CompilerTest.java b/jsonpath/src/test/java/io/github/xmljim/json/jsonpath/test/compiler/CompilerTest.java
index 14f15a4..4ed2d5c 100644
--- a/jsonpath/src/test/java/io/github/xmljim/json/jsonpath/test/compiler/CompilerTest.java
+++ b/jsonpath/src/test/java/io/github/xmljim/json/jsonpath/test/compiler/CompilerTest.java
@@ -14,8 +14,8 @@
class CompilerTest extends JsonPathTestBase {
@Test
- @DisplayName("Given an expression with a root select and bracketed property key, then return a sequence" +
- "containing a RootPathOperator and a ChildPathOperator")
+ @DisplayName("Given an expression with a root select and bracketed property key, then return a sequence " +
+ "containing a RootPathOperator and a ChildPathOperator")
void testChildPathWithBrackets() {
String expression = "$['foo']";
FilterStream sequence = getFilterStream(expression);
@@ -27,7 +27,7 @@ void testChildPathWithBrackets() {
@Test
@DisplayName("Given an expression with a root selector and 'dot' property key, then return a sequence" +
- "containing a RootPathOperator and a ChildPathOperator")
+ "containing a RootPathOperator and a ChildPathOperator")
void testChildPathWithDot() {
String expression = "$.foo";
FilterStream sequence = getFilterStream(expression);
diff --git a/jsonpath/src/test/java/io/github/xmljim/json/jsonpath/test/filter/AccessorTest.java b/jsonpath/src/test/java/io/github/xmljim/json/jsonpath/test/filter/AccessorTest.java
index 39bbaf2..dc16a80 100644
--- a/jsonpath/src/test/java/io/github/xmljim/json/jsonpath/test/filter/AccessorTest.java
+++ b/jsonpath/src/test/java/io/github/xmljim/json/jsonpath/test/filter/AccessorTest.java
@@ -1,6 +1,6 @@
package io.github.xmljim.json.jsonpath.test.filter;
-import io.github.xmljim.json.jsonpath.filter.Accessor;
+import io.github.xmljim.json.jsonpath.context.Accessor;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
diff --git a/jsonpath/src/test/java/io/github/xmljim/json/jsonpath/test/function/FunctionTests.java b/jsonpath/src/test/java/io/github/xmljim/json/jsonpath/test/function/FunctionTests.java
index 3a23ddd..c8d0cce 100644
--- a/jsonpath/src/test/java/io/github/xmljim/json/jsonpath/test/function/FunctionTests.java
+++ b/jsonpath/src/test/java/io/github/xmljim/json/jsonpath/test/function/FunctionTests.java
@@ -11,7 +11,10 @@
import java.util.List;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
@DisplayName("Built-in Function Tests")
class FunctionTests extends JsonPathTestBase {
@@ -70,17 +73,17 @@ void testCountIfFunctionCompoundTest_GreaterThanThree() {
//now the ugly way:
JsonArray compoundArray = getCompoundTest();
List result = compoundArray.jsonValues().map(JsonElement::asJsonObject)
- .filter(jsonObject -> jsonObject.getValue("assignments").asJsonArray().jsonValues()
- .filter(assignment -> {
- JsonObject assigned = assignment.asJsonObject();
- return (assigned.getValue("doc_type_id").asNumber().intValue() == 19 &&
- assigned.getValue("doc_status").asString().equals("PROCESSED"));
- }).count() >= 3)
- .toList();
+ .filter(jsonObject -> jsonObject.getValue("assignments").asJsonArray().jsonValues()
+ .filter(assignment -> {
+ JsonObject assigned = assignment.asJsonObject();
+ return (assigned.getValue("doc_type_id").asNumber().intValue() == 19 &&
+ assigned.getValue("doc_status").asString().equals("PROCESSED"));
+ }).count() >= 3)
+ .toList();
assertEquals(array.size(), result.size());
assertEquals(result.get(0).value("id").orElseThrow(() -> new Exception("Bad Expected Value")),
- array.getValue(0).asJsonObject().value("id").orElseThrow());
+ array.getValue(0).asJsonObject().value("id").orElseThrow());
} catch (Exception e) {
fail(e);
@@ -96,17 +99,17 @@ void testCountIfFunctionCompoundTest_LessThanThree() {
//now the ugly way:
JsonArray compoundArray = getCompoundTest();
List result = compoundArray.jsonValues().map(JsonElement::asJsonObject)
- .filter(jsonObject -> jsonObject.getValue("assignments").asJsonArray().jsonValues()
- .filter(assignment -> {
- JsonObject assigned = assignment.asJsonObject();
- return (assigned.getValue("doc_type_id").asNumber().intValue() == 19 &&
- assigned.getValue("doc_status").asString().equals("PROCESSED"));
- }).count() < 3)
- .toList();
+ .filter(jsonObject -> jsonObject.getValue("assignments").asJsonArray().jsonValues()
+ .filter(assignment -> {
+ JsonObject assigned = assignment.asJsonObject();
+ return (assigned.getValue("doc_type_id").asNumber().intValue() == 19 &&
+ assigned.getValue("doc_status").asString().equals("PROCESSED"));
+ }).count() < 3)
+ .toList();
assertEquals(array.size(), result.size());
assertEquals(result.get(0).value("id").orElseThrow(() -> new Exception("Bad Expected Value")),
- array.getValue(0).asJsonObject().value("id").orElseThrow());
+ array.getValue(0).asJsonObject().value("id").orElseThrow());
} catch (Exception e) {
fail(e);
@@ -232,6 +235,9 @@ void testEndsWithFunction() {
expr = "$.teams.*[?(@.id == 'COL')].stadium.ends-with('Field')";
assertTrue((boolean) jsonPath.select(baseball, expr).get(0));
+ boolean endsWithField = jsonPath.selectValue(baseball, expr);
+ assertTrue(endsWithField);
+
} catch (Exception e) {
fail(e);
}
diff --git a/jsonpath/src/test/java/module-info.java b/jsonpath/src/test/java/module-info.java
index b5f6171..e70605f 100644
--- a/jsonpath/src/test/java/module-info.java
+++ b/jsonpath/src/test/java/module-info.java
@@ -19,4 +19,5 @@
opens io.github.xmljim.json.jsonpath.test.predicate.expression;
opens io.github.xmljim.json.jsonpath.test.function.node;
opens io.github.xmljim.json.jsonpath.test.filter;
+ opens io.github.xmljim.json.jsonpath.test.util;
}
\ No newline at end of file
diff --git a/mapper/pom.xml b/mapper/pom.xml
index afbbfb8..516577e 100644
--- a/mapper/pom.xml
+++ b/mapper/pom.xml
@@ -23,12 +23,14 @@
jsonfactory
${project.version}
+
io.github.xmljim.json
elementfactory
${project.version}
test
+
diff --git a/mapper/src/main/java/io/github/xmljim/json/mapper/AnnotationUtils.java b/mapper/src/main/java/io/github/xmljim/json/mapper/AnnotationUtils.java
index 3782172..dce8c55 100644
--- a/mapper/src/main/java/io/github/xmljim/json/mapper/AnnotationUtils.java
+++ b/mapper/src/main/java/io/github/xmljim/json/mapper/AnnotationUtils.java
@@ -13,7 +13,7 @@
import java.util.Map;
import java.util.Optional;
-interface AnnotationUtils {
+abstract class AnnotationUtils {
/**
* Find and return an Optional containing an Annotation
*
@@ -22,7 +22,7 @@ interface AnnotationUtils {
* @param classMember The class member (either a Field, Method or Class)
* @return an Optional containing the Annotation
*/
- static Optional findAnnotation(Class extends T> annotationClass, AnnotatedElement classMember) {
+ public static Optional findAnnotation(Class extends T> annotationClass, AnnotatedElement classMember) {
T annotation = null;
if (classMember.isAnnotationPresent(annotationClass)) {
@@ -32,7 +32,7 @@ static Optional findAnnotation(Class extends T> anno
return Optional.ofNullable(annotation);
}
- static Optional> getConvertToJson(AnnotatedElement element) {
+ public static Optional> getConvertToJson(AnnotatedElement element) {
ValueConverter> convert = null;
final Optional valueConverter = findAnnotation(ConvertValue.class, element);
@@ -46,7 +46,7 @@ static Optional> getConvertToJson(AnnotatedElement element) {
return Optional.ofNullable(convert);
}
- static Optional> getConvertToValue(AnnotatedElement element) {
+ public static Optional> getConvertToValue(AnnotatedElement element) {
ValueConverter> convert = null;
final Optional valueConverter = findAnnotation(ConvertValue.class, element);
@@ -59,11 +59,11 @@ static Optional> getConvertToValue(AnnotatedElement element) {
return Optional.ofNullable(convert);
}
- static boolean findJsonElementIgnore(AnnotatedElement element) {
+ public static boolean findJsonElementIgnore(AnnotatedElement element) {
return findAnnotation(JsonElement.class, element).map(JsonElement::ignore).orElse(false);
}
- static Optional findJsonElementKey(AnnotatedElement element) {
+ public static Optional findJsonElementKey(AnnotatedElement element) {
return findAnnotation(JsonElement.class, element).filter(a -> !"".equals(a.key())).map(JsonElement::key);
}
@@ -71,11 +71,11 @@ static Optional findJsonElementSetter(AnnotatedElement element) {
return findAnnotation(JsonElement.class, element).filter(a -> !"".equals(a.setterMethod())).map(JsonElement::setterMethod);
}
- static Optional findJsonElementGetter(AnnotatedElement element) {
+ public static Optional findJsonElementGetter(AnnotatedElement element) {
return findAnnotation(JsonElement.class, element).filter(a -> !"".equals(a.getterMethod())).map(JsonElement::getterMethod);
}
- static Optional> findConvertClass(AnnotatedElement element) {
+ public static Optional> findConvertClass(AnnotatedElement element) {
return findAnnotation(ConvertClass.class, element).map(ConvertClass::target);
}
}
diff --git a/mapper/src/main/java/io/github/xmljim/json/mapper/ClassMappingImpl.java b/mapper/src/main/java/io/github/xmljim/json/mapper/ClassMappingImpl.java
new file mode 100644
index 0000000..027de29
--- /dev/null
+++ b/mapper/src/main/java/io/github/xmljim/json/mapper/ClassMappingImpl.java
@@ -0,0 +1,265 @@
+package io.github.xmljim.json.mapper;
+
+import io.github.xmljim.json.factory.mapper.*;
+import io.github.xmljim.json.factory.model.ElementFactory;
+import io.github.xmljim.json.mapper.exception.JsonMapperException;
+import io.github.xmljim.json.model.JsonObject;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.stream.Stream;
+
+class ClassMappingImpl implements ClassMapping {
+
+
+ private final ClassConfig classConfig;
+
+ private boolean initialized;
+ private final Set ignoredKeys = new HashSet<>();
+
+ private Class> sourceClass;
+ private Class> targetClass;
+ private boolean isMemberClass;
+
+ private boolean isRecord;
+ private boolean isPublic;
+
+ private final List constructorKeys = new ArrayList<>();
+
+ private final MapperFactory mapperFactory;
+ private final Mapping mapping;
+
+ private final List memberMappings = new ArrayList<>();
+
+ public ClassMappingImpl(Mapping mapping, ClassConfig config) {
+ this.mapping = mapping;
+ this.classConfig = config;
+ this.mapperFactory = mapping.getMapperFactory();
+ this.sourceClass = config.getSourceClass();
+ this.targetClass = config.getTargetClass();
+ initialize();
+ }
+
+
+ @Override
+ public ClassConfig getClassConfig() {
+ return classConfig;
+ }
+
+ @Override
+ public Mapping getMapping() {
+ return this.mapping;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Class