Skip to content

Commit

Permalink
Merge pull request #24 from Mohit-Sahu/develop
Browse files Browse the repository at this point in the history
sample-product json added as per the last suggestion
  • Loading branch information
sathishk committed Jan 19, 2024
2 parents 6c2fa6b + 8dee452 commit a579824
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 190 deletions.
196 changes: 59 additions & 137 deletions src/main/java/com/techatpark/sjson/JsonSchema.java
Original file line number Diff line number Diff line change
@@ -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.
* <p>
* It will return native java objects as given below based
* on JSON Data Type.
* Ref: https://www.w3schools.com/js/js_json_datatypes.asp
* <p>
* 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<String, Object> jsonMap) {
StringBuilder builder = new StringBuilder();
boolean isFirst = true;
builder.append("{");
for (Map.Entry<String, Object> 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<String, Object>)
value));
return jsonText((Map<String, Object>) value);
} else if (value instanceof List) {
builder.append(jsonText((Map<String, Object>) 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");
}


}
}
72 changes: 63 additions & 9 deletions src/test/java/com/techatpark/sjson/JsonSchemaTest.java
Original file line number Diff line number Diff line change
@@ -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<String, Object> 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<String, Object> nestedMap = new HashMap<>();
nestedMap.put("nestedKey1", "nestedValue1");

JsonSchema jsonSchema =
new JsonSchema(new FileReader("src/test/resources/schemas/product.json"));
Map<String, Object> jsonMap = new HashMap<>();
jsonMap.put("key1", "value1");
jsonMap.put("key2", nestedMap);

jsonSchema.read(new FileReader("src/test/resources/schemas/person.json"));
String expectedJson = "{\"key1\":\"value1\",\"key2\":{\"nestedKey1\":\"nestedValue1\"}}";
assertEquals(expectedJson, jsonSchema.jsonText(jsonMap));
}

jsonSchema.jsonText(new HashMap<>());
@Test
public void testJsonTextWithList() {
List<Object> list = Arrays.asList("item1", 123, true);

Map<String, Object> jsonMap = new HashMap<>();
jsonMap.put("key1", list);

String expectedJson = "{\"key1\":[\"item1\",123,true]}";
assertEquals(expectedJson, jsonSchema.jsonText(jsonMap));
}

@Test
public void testJsonTextWithSpecialCharacters() {
Map<String, Object> 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());
}
}
}
44 changes: 0 additions & 44 deletions src/test/resources/schemas/person.json

This file was deleted.

10 changes: 10 additions & 0 deletions src/test/resources/schemas/sample-product.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"firstName": "John",
"lastName": "Doe",
"age": 30,
"address": {
"street": "123 Main St",
"city": "Anytown",
"zipcode": "12345"
}
}

0 comments on commit a579824

Please sign in to comment.