diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..54ca2d7fdaaeed4de60fccca63277f766cb2e0dc
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+# Created by .ignore support plugin (hsz.mobi)
+JsonFileCompare.iml
+target/
diff --git a/README.md b/README.md
index 5d60fdafc2b353057b7a483bb898d5d9892792fa..339f177b96b045c4d78a01975e0884a0f5a4f501 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,15 @@
# JsonFileCompare
+### Find missing key in Target json file
+
+```
+mvn package
+```
+
+可以在target下找到JsonFileCompare-exec.jar
+
+ ```java
+java -cp JsonFileCompare-exec.jar JsonFileCompare /xxx/locale-zh_TW.json /xxx/locale-zh_CN.json /xxx/locale-en_US.json
+```
+
+P.S 第一個參數為基準的json, 後面為要找出缺少key的目標檔案
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c1b7e26b5cc16a5db0060b9d2f5906411bf4c090
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,47 @@
+
+
+ 4.0.0
+ org.ylhealth
+ JsonFileCompare
+ 0.0.1
+ jar
+
+
+ 1.8
+ 1.8
+
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.9.7
+
+
+
+
+
+
+
+ maven-assembly-plugin
+
+
+ package
+
+ single
+
+
+
+
+
+ jar-with-dependencies
+
+ JsonFileCompare-exec
+ false
+
+
+
+
+
diff --git a/src/main/java/JsonFileCompare.java b/src/main/java/JsonFileCompare.java
new file mode 100644
index 0000000000000000000000000000000000000000..9cd4440826ab5d03c90c95b21acf431e7f5b0598
--- /dev/null
+++ b/src/main/java/JsonFileCompare.java
@@ -0,0 +1,89 @@
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class JsonFileCompare {
+
+ public static void main(String[] args) {
+
+
+ try {
+ ObjectMapper objectMapper = new ObjectMapper();
+ Path originPath = Paths.get(args[0]);
+ JsonNode twJson = objectMapper.readTree(new String(Files.readAllBytes(originPath)));
+ Set originSet = new HashSet<>();
+ addKeys("", twJson, originSet, new ArrayList<>());
+
+ IntStream.range(1, args.length).forEach(i -> findMissingKeys(Paths.get(args[i]), originSet));
+
+ } catch (Exception e) {
+ System.err.println(args[0] + " is not exists or not json files.");
+ System.exit(1);
+ }
+ }
+
+ public static void addKeys(String currentPath, JsonNode jsonNode, Set set, List suffix) {
+ if (jsonNode.isObject()) {
+ ObjectNode objectNode = (ObjectNode) jsonNode;
+ Iterator> iter = objectNode.fields();
+ String pathPrefix = currentPath.isEmpty() ? "" : currentPath + "-";
+
+ while (iter.hasNext()) {
+ Map.Entry entry = iter.next();
+ addKeys(pathPrefix + entry.getKey(), entry.getValue(), set, suffix);
+ }
+ } else if (jsonNode.isArray()) {
+ ArrayNode arrayNode = (ArrayNode) jsonNode;
+
+ for (int i = 0; i < arrayNode.size(); i++) {
+ suffix.add(i + 1);
+ addKeys(currentPath, arrayNode.get(i), set, suffix);
+
+ if (i + 1 < arrayNode.size()) {
+ suffix.remove(arrayNode.size() - 1);
+ }
+ }
+
+ } else if (jsonNode.isValueNode()) {
+ if (currentPath.contains("-")) {
+ for (int i = 0; i < suffix.size(); i++) {
+ currentPath += "-" + suffix.get(i);
+ }
+ }
+ set.add(currentPath);
+ }
+ }
+
+ public static void findMissingKeys(Path targetPath, Set originSet) {
+ if (!targetPath.toFile().exists()) return;
+ try {
+ Set targetSet = new HashSet<>();
+ ObjectMapper objectMapper = new ObjectMapper();
+ JsonNode json = objectMapper.readTree(new String(Files.readAllBytes(targetPath)));
+ addKeys("", json, targetSet, new ArrayList<>());
+
+ Set missingKey =
+ originSet
+ .parallelStream()
+ .filter(key -> !targetSet.contains(key))
+ .collect(Collectors.toSet());
+ if (!missingKey.isEmpty()) {
+ System.err.println("Missing Key on " + targetPath.toString());
+ System.err.println("Missing Keys: ");
+ missingKey.stream().sorted().forEach(System.err::println);
+ System.exit(1);
+ }
+ } catch (Exception e) {
+ System.err.println(targetPath.toString() + " is not json files.");
+ System.exit(1);
+ }
+ }
+}