diff --git a/src/main/java/com/techatpark/sjson/JsonSchema.java b/src/main/java/com/techatpark/sjson/JsonSchema.java index f6a2f62..e4423b1 100644 --- a/src/main/java/com/techatpark/sjson/JsonSchema.java +++ b/src/main/java/com/techatpark/sjson/JsonSchema.java @@ -1,183 +1,105 @@ package com.techatpark.sjson; -import com.techatpark.sjson.util.NumberParser; - - - -import java.io.IOException; -import java.io.Reader; - import java.io.IOException; import java.io.Reader; import java.util.List; import java.util.Map; +import java.util.StringJoiner; /** - * Json Schema that represents the schema document. - * Ref: https://json-schema.org/specification + * Represents a JSON schema document. Provides functionality to serialize + * Java objects to JSON strings. */ -public class JsonSchema { +public final class JsonSchema { /** - * @param reader file reader for json schema + * Constructor for JsonSchema. */ - public JsonSchema(final Reader reader) { - + public JsonSchema() { + // Constructor logic if any } /** - * Reads JSON as a Java Object. - *

- * It will return native java objects as given below based - * on JSON Data Type. - * Ref: https://www.w3schools.com/js/js_json_datatypes.asp - *

- * string - java.lang.String - * number - java.lang.Number - * object - java.util.Map - * array - java.util.List - * boolean - java.lang.Boolean - * null - null + * Reads JSON from a Reader and converts it into a Java Object. + * This method is not yet implemented. * - * @param reader - file reader for json data - * @return object - * @throws IOException - throws io exception + * @param reader the Reader to read JSON data from + * @return Object representation of the read JSON + * @throws IOException if an I/O error occurs */ public Object read(final Reader reader) throws IOException { - return null; + throw new UnsupportedOperationException("Not yet implemented"); } /** - * Get Json text for the Map. + * Converts a Map into its JSON string representation. * - * @param jsonMap - * @return jsonText + * @param jsonMap the Map representing the JSON object + * @return the JSON string representation of the Map */ public String jsonText(final Map jsonMap) { - StringBuilder builder = new StringBuilder(); - boolean isFirst = true; - builder.append("{"); - for (Map.Entry entry : jsonMap.entrySet()) { - if (isFirst) { - isFirst = false; - } else { - builder.append(","); - } - // Create Key enclosed with " - builder.append("\"") - .append(escapeJsonTxt(entry.getKey())) - .append("\":"); // Create Key value separator - - Object value = entry.getValue(); + StringJoiner joiner = new StringJoiner(",", "{", "}"); + jsonMap.forEach((final String key, final Object value) -> + joiner.add(formatEntry(key, value))); + return joiner.toString(); + } - valueText(builder, value); - } - return builder.append("}").toString(); + /** + * Formats a key-value pair into a JSON entry. + * + * @param key the key in the map + * @param value the value corresponding to the key + * @return formatted JSON entry + */ + private String formatEntry(final String key, final Object value) { + return String.format("\"%s\":%s", escapeJson(key), valueToJson(value)); } /** - * Create Value in according to the Type. + * Converts a value to its JSON representation. * - * @param builder - * @param value + * @param value the value to convert + * @return JSON representation of the value */ - private void valueText(final StringBuilder builder, final Object value) { + private String valueToJson(final Object value) { if (value == null) { - builder.append("null"); + return "null"; } else if (value instanceof String) { - processString(builder, (String) value); + return "\"" + escapeJson((String) value) + "\""; } else if (value instanceof Map) { - builder.append(jsonText((Map) - value)); + return jsonText((Map) value); } else if (value instanceof List) { - builder.append(jsonText((Map) value)); + return listToJson((List) value); } else { - builder.append(value); + return value.toString(); } } - /** - * Process String. + * Converts a list to its JSON array representation. * - * @param builder - * @param value + * @param list the list to convert + * @return JSON array representation of the list */ - private void processString(final StringBuilder builder, - final String value) { - builder.append("\"") - .append(escapeJsonTxt(value)) - .append("\""); + private String listToJson(final List list) { + StringJoiner sj = new StringJoiner(",", "[", "]"); + list.forEach(obj -> sj.add(valueToJson(obj))); + return sj.toString(); } /** - * Escape JSON Text. - * Escape quotes, \, /, \r, \n, \b, \f, \t - * and other control characters (U+0000 through U+001F). - * @param s - * @return escapeJsonTxt - */ - private String escapeJsonTxt(final String s) { - if (s == null) { - return null; - } - StringBuilder sb = new StringBuilder(); - escape(s, sb); - return sb.toString(); - } - - /** - * Escape Text. - * @param s - Must not be null. - * @param sb + * Escapes special characters in a JSON string. + * + * @param text the string to escape + * @return escaped JSON string */ - private void escape(final String s, final StringBuilder sb) { - final int len = s.length(); - for (int i = 0; i < len; i++) { - char ch = s.charAt(i); - switch (ch) { - case '"': - sb.append("\\\""); - break; - case '\\': - sb.append("\\\\"); - break; - case '\b': - sb.append("\\b"); - break; - case '\f': - sb.append("\\f"); - break; - case '\n': - sb.append("\\n"); - break; - case '\r': - sb.append("\\r"); - break; - case '\t': - sb.append("\\t"); - break; - case '/': - sb.append("\\/"); - break; - default: - //Reference: http://www.unicode.org/versions/Unicode5.1.0/ - if ((ch >= '\u0000' && ch <= '\u001F') - || (ch >= '\u007F' && ch <= '\u009F') - || (ch >= '\u2000' && ch <= '\u20FF')) { - String ss = Integer.toHexString(ch); - sb.append("\\u"); - for (int k = 0; k < NumberParser.NUMBER_FOUR - - ss.length(); k++) { - sb.append('0'); - } - sb.append(ss.toUpperCase()); - } else { - sb.append(ch); - } - } - } + private String escapeJson(final String text) { + return text.replace("\\", "\\\\") + .replace("\"", "\\\"") + .replace("\b", "\\b") + .replace("\f", "\\f") + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\t", "\\t"); } - - -} \ No newline at end of file +} diff --git a/src/test/java/com/techatpark/sjson/JsonSchemaTest.java b/src/test/java/com/techatpark/sjson/JsonSchemaTest.java index 03fd358..54fb012 100644 --- a/src/test/java/com/techatpark/sjson/JsonSchemaTest.java +++ b/src/test/java/com/techatpark/sjson/JsonSchemaTest.java @@ -1,22 +1,76 @@ package com.techatpark.sjson; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.FileReader; -import java.io.IOException; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; +import java.util.Map; -class JsonSchemaTest { +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class JsonSchemaTest { + + private JsonSchema jsonSchema; + + @BeforeEach + public void setUp() { + jsonSchema = new JsonSchema(); + } + + @Test + public void testJsonTextWithSimpleMap() { + Map jsonMap = new HashMap<>(); + jsonMap.put("key1", "value1"); + jsonMap.put("key2", 123); + + String expectedJson = "{\"key1\":\"value1\",\"key2\":123}"; + assertEquals(expectedJson, jsonSchema.jsonText(jsonMap)); + } @Test - void read() throws IOException { + public void testJsonTextWithNestedMap() { + Map nestedMap = new HashMap<>(); + nestedMap.put("nestedKey1", "nestedValue1"); - JsonSchema jsonSchema = - new JsonSchema(new FileReader("src/test/resources/schemas/product.json")); + Map jsonMap = new HashMap<>(); + jsonMap.put("key1", "value1"); + jsonMap.put("key2", nestedMap); - jsonSchema.read(new FileReader("src/test/resources/schemas/sample-product.json")); + String expectedJson = "{\"key1\":\"value1\",\"key2\":{\"nestedKey1\":\"nestedValue1\"}}"; + assertEquals(expectedJson, jsonSchema.jsonText(jsonMap)); + } - jsonSchema.jsonText(new HashMap<>()); + @Test + public void testJsonTextWithList() { + List list = Arrays.asList("item1", 123, true); + + Map jsonMap = new HashMap<>(); + jsonMap.put("key1", list); + + String expectedJson = "{\"key1\":[\"item1\",123,true]}"; + assertEquals(expectedJson, jsonSchema.jsonText(jsonMap)); + } + + @Test + public void testJsonTextWithSpecialCharacters() { + Map jsonMap = new HashMap<>(); + jsonMap.put("key1", "value \"1\""); + jsonMap.put("key2", "line\nbreak"); + + String expectedJson = "{\"key1\":\"value \\\"1\\\"\",\"key2\":\"line\\nbreak\"}"; + assertEquals(expectedJson, jsonSchema.jsonText(jsonMap)); + } + + @Test + public void testReadMethodNotImplemented() { + Exception exception = assertThrows(UnsupportedOperationException.class, () -> { + jsonSchema.read(null); + }); + String expectedMessage = "Not yet implemented"; + assertEquals(expectedMessage, exception.getMessage()); } -} \ No newline at end of file +}