Group Member: Kaiqin Chen, Ruiyan Ma
echo "Compiling json.jar..."
cd /Users/chenkaiqin/Documents/GitHub/SWE262P-project/src/main/java
javac org/json/*.java
jar cfv json-java.jar org/json/*.class
find . -name '*.class' -delete
echo "Compile a program that uses the jar"
javac -cp .:json-java.jar Test.java
echo "Run the Test file"
java Test
-
add two more function
public static JSONObject toJSONObject(Reader reader, JSONPointer path) {} private static boolean parseMile2(XMLTokener x, JSONObject context, String name, XMLParserConfiguration config, String stopKey) {}
-
Create two global value to track the process
// global values for milestone2 task1 static boolean pathFind = false; static int reachIndex = -1; // this is for JSONArray, example books/2 // global values for milestone2 task2 static boolean replacePathFind = false; static int replaceIndex = -1; static boolean hasReplaced = false; //make sure only replace once
-
Function details can be found in the XML.java
- Simple idea for Task1 is when we found the close tag for stopWord, we immediately stop the recursion by set
pathFind
toTrue
- Simple idea fro Task2 is when we found the replace token's close tag, we give
replacePathFind
toTrue
, so that in the next recursion will replace the JSONObject, and we usehasReplaced
to make sure that replace element only happen once. For this task, we do not break the recursion.
- Simple idea for Task1 is when we found the close tag for stopWord, we immediately stop the recursion by set
We create 4 tests.
# Path: "/contact/address"
{"address":{"zipcode":92611,"street":"Ave of Nowhere"}}
-----------------------
# Path: "/contact/address/street"
Given replacement: {"street":"Ave of the Arts"}
{"contact":{"nick":"Crista","address":{"zipcode":92611,"street":"Ave of the Arts"},"name":"Crista Lopes"}}
-----------------------
# Path: "/employee/contact/1"
{"nick":"KC","address":{"zipcode":92614,"street":"Irvine"},"name":"Chen"}
-----------------------
# Path: "/contact/address/street/2"
# for the last one we have not figure how to fix it with JSONArray, we might do it in the future update
Given replacement: {"street":"Ave of the Arts"}
{"employee":{"contact":[{"nick":"Crista","address":{"zipcode":92611,"street":["Ave of the Arts","Ave of Two","Ave of Three"]},"name":"Crista Lopes"},{"nick":"KC","address":{"zipcode":92614,"street":"Irvine"},"name":"Chen"}]}}
For the task1, we manage to stop recursive when we find the sub object, we think it save a lot of time. For example, if you try to find the first object in 1000 object, with milestone2 we only need to go the first object and return and with milestone1 we need to recursively go through all the object.
Add an overloaded static method to the XML class with the signature.
- Add two more function
public static JSONObject toJSONObject(Reader reader, Function keyTransformer) {}
private static boolean parseMile3(XMLTokener x, JSONObject context, String name, XMLParserConfiguration config, Function keyTransformer) {}
parseMile3
function is built based on the originalparse
function. We just need to apply thekeyTransformer
function every time whenparse
function try to useaccumulate
method to expand the result. For example, we change the line1 to line2. In this way, we can make sure everyTag
orTagName
will be applied by thekeyTransformer
function.
context.accumulate(config.getcDataTagName(), string);
context.accumulate((String) keyTransformer.apply(config.getcDataTagName()), string);
In the milestone3, we began to utilize Junit
as our test tool.
@Test
public void testMileStone3Fun1() throws FileNotFoundException {
File file = new File("./src/books.xml");
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
Function<String, String> func = x -> "swe_262P_"+x;
JSONObject jobj = XML.toJSONObject(br,func);
System.out.println(jobj.toString(2));
}
@Test
public void testMileStone3Fun2() throws FileNotFoundException {
File file = new File("./src/books.xml");
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
Function<String, String> func = x -> new StringBuilder(x).reverse().toString();
JSONObject jobj = XML.toJSONObject(br,func);
System.out.println(jobj.toString(2));
}
We will try to rewrite milestone2's unit test in the future with Junit
to maintain the consistency.
We think for the milestone3 we did a lot of improvement in the performance. For this mission, we always need to traverse the whole XML. However, in milestone1, we need to do it twice. First we traverse to get the XML to JSON, and then the client need do another traverse to change the key.
In the milestone3, by using of Functions provided by JAVA 8 and the lambda expressions, we made the reverse only happen once. For detail implementation, we built our function on the top of the original parse function with little adjustments.
We think JSONObject
as a tree not a HashMap
. When we want to traverse a tree, we do it recursively
In detail, we have to deal with several questions.
-
What attributes are required for this node?
-
What are the params of the recursive function?
-
When should we add the node into list?
-
What should we do with
JSONArray
Object?...
Step by step, we break the challenge into small pieces to solve the problem by create a new class named JSONNode
and two new methods in JSONObject.java
file called toStream()
and addAllNodes()
public Stream<JSONNode> toStream() {}
private List<JSONNode> addAllNodes(String p, JSONObject jb, ArrayList<JSONNode> nodes) {}
We begin to use assertTrue
to test our function. We write out test cases in /test/java/MilestoneTest.java
public void testMileStone4() {}
When we turn a JSONObject
into a Stream
Object, we open a whole new world for the object. Because once it turned, it can utilize all the APIs in Stream
, for example, map
, filter
, collector
, flatmap
, foreach
etc.
We implement asynchronous methods with Java Future
. When the asynchronous task is created, a Java Future
object is returned. And use ExecutorService to submit the tasks.
static ExecutorService executorService = Executors.newSingleThreadExecutor();
public static Future<JSONObject> toJSONObjectM5(Reader reader, Function keyTransformer) {
Future<JSONObject> objectFuture = executorService.submit(() -> {
return XML.toJSONObject(reader, keyTransformer);
});
executorService.shutdown();
return objectFuture;
}
public static Future<JSONObject> toJSONObjectM5(Reader reader) {
Future<JSONObject> objectFuture = executorService.submit(() -> {
return XML.toJSONObject(reader);
});
executorService.shutdown();
return objectFuture;
}
static ExecutorService pool = Executors.newCachedThreadPool();
public static void toJSONObjectAsync(Reader reader, Function f, Function exp) throws ExecutionException, InterruptedException {
pool.execute(() -> {
try {
System.out.println("Start processing " + Thread.currentThread().getName());
JSONObject obj = toJSONObject(reader);
f.apply(obj);
System.out.println("Done processing " + Thread.currentThread().getName());
} catch (Exception e) {
exp.apply(e);
}
});
}
We try to use Thread Pools to solve this asynchronous problem. We know that there might be Deadlock, Thread Leakage and Resource Thrashing problem. The cons is that we don't know when the task will end.
public void testAsyncJSONKeyTransform() throws Exception {}
public void testAsyncJSON() throws Exception {}
public void testAsyncJSONKeyTransformWithJSONException() throws Exception{}
public void testAsyncJSONWithWriter() throws Exception {}
public void testJSONObjectAsync() throws Exception {}
public void testJSONObjectAsyncWithTwo() throws Exception {}
public void testJSONObjectAsyncWithException() throws Exception {}
In Java, when we declare a field static
, exactly a single copy of that field is created and shared among all instances of that class. We creates an Executor
that uses a single worker thread operating off an unbounded queue.