I can't speak to including element locators in a JSON file, as I follow the page object model and include all those in the java classes. However, reading test data from a JSON file is very easy. It's been a while since I've messed around with this, but I used JSON Simple (which I still use to generate JSON objects/files) and did something like this to read in the file:
protected JSONObject getDataFile(String dataFileName) {
String dataFilePath = "src/test/resources/";
JSONObject testObject = null;
try {
FileReader reader = new FileReader(dataFilePath + dataFileName);
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = (JSONObject) jsonParser.parse(reader);
testObject = (JSONObject) jsonObject;
} catch (Exception ex) {
ex.printStackTrace();
}
return testObject;
}
Once you have the JSON Object, JSON simple provides a few different ways to interact with it and get the values. I've played around with Gson a while back and I think that was fairly similar.
I don't know how your data file is/will be structured, but I had a key string that represented a test case name, and the value was a json object that contained other key-value pairs with the actual data and I fed that data to a TestNG data provider. If that is similar to your setup, I can share that code.
EDIT: Here is the method used by the @DataProvider
public Object[][] getTestScenarios(String dataFileName, String testCaseName) {
JSONArray testCase = (JSONArray) getDataFile(dataFileName).get(testCaseName);
List<JSONObject> testScenarioArray = new ArrayList<JSONObject>();
for (int i = 0; i < testCase.size(); i++) {
testScenarioArray.add((JSONObject) testCase.get(i));
}
Object[][] dataProviderArray = new Object[testScenarioArray.size()][];
for (int scenario = 0; scenario < testScenarioArray.size(); scenario++) {
String scenarioName = null;
if ((String) testScenarioArray.get(scenario).get("scenario") != null) {
scenarioName = (String) testScenarioArray.get(scenario).get("scenario");
} else {
scenarioName = "No scenario name specified";
};
dataProviderArray[scenario] = new Object[] { scenarioName, (JSONObject) testScenarioArray.get(scenario) };
}
return dataProviderArray;
}
The scenario name stuff could be removed, as I believe I only used that for logging or reporting, if I recall correctly. The reason I had it as a JSONArray and coded in this fashion is so a single test case could have an array with multiple scenarios with differing data. Didn't want the tests to have to care how many scenarios there were.