Решение состоит из нескольких частей:
- Во-первых, вам нужно знать все ключи json, которые не совпадают с полем в объекте json.
- Во-вторых, вам нужночтобы узнать доступные поля json для объектов, чтобы найти наиболее близкое совпадение с json-ключом с орфографической ошибкой.
- Наконец, вам нужен способ вычисления ближайших совпадений между несоответствующим ключом json и доступными полями json.
Вы можете получить все ключи данных JSON, которые не соответствуют ни одному из полей объекта JSON, используя @JsonAnySetter
, как предложено Шиванг Агарвал .
public static class MyParent {
@JsonProperty("a") protected String jsonA;
@JsonProperty("b") protected String jsonB;
// ignored by getJsonPropertyNames()
protected String internal1;
@JsonIgnore private Map<String, Object> additionalProperties = new HashMap<String, Object>();
@JsonAnyGetter public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
@JsonAnySetter public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
public static class MyChild extends MyParent {
@JsonProperty("jurisdiction") protected String jurisdiction;
// ignored by getJsonPropertyNames()
protected String internal2;
}
Вы можете получить все доступные поля JSON (отмеченные @JsonProperty
) из объекта, используя следующие методы:
private static Collection<String> getJsonPropertyNames(Object o) {
// might need checking if fields collide
// Eg:
// @JSONProperty String field1;
// @JSONProperty("field1") String fieldOne;
// maybe should be a Set?
List<String> fields = new ArrayList<>();
forAllFields(o, (f) -> {
JsonProperty jprop = f.getAnnotation(JsonProperty.class);
if (jprop != null) {
String fieldName = jprop.value();
if (fieldName == null) {
fieldName = f.getName();
}
fields.add(fieldName);
}
});
return fields;
}
/** For all fields of the given object, including its parent fields */
private static void forAllFields(Object o, Consumer<Field> consumer) {
Class<?> klass = o.getClass();
while (klass != null) {
for (Field f : klass.getDeclaredFields())
consumer.accept(f);
klass = klass.getSuperclass();
}
}
public static void main(String[] args) throws IOException {
for (String s : getJsonPropertyNames(new MyChild()))
System.out.println(s);
}
Наиболее похожие строки можно найти с помощью приведенного нижеметоды:
Я все еще хочу проверить мой метод stringEditDistance
еще немного, но пока он может работать достаточно хорошо.Я мог бы поработать над этим позже.
/** finds the nearest matching string from the options
* using the basic string edit distance where all operations cost 1 */
private static String findNearestMatch(String input, Iterable<String> options) {
String closestString = null;
int minDistance = Integer.MAX_VALUE;
for (String option : options) {
int distance = stringEditDistance(input, option, 1, 1, (a, b) -> 1);
if (distance < minDistance) {
minDistance = distance;
closestString = option;
}
}
return closestString;
}
/**
* NOTE: needs some editing and more testing.
*
* Returns the minimum cost to edit the input string into the target string using the given costs for
* operations.
*
* @param insertCost
* the cost to insert a character into the input to bring it closer to the target
* @param deleteCost
* the cost to delete a character from the input to bring it closer to the target
* @param replaceCostCalculator
* a function to calculate the cost to replace a character in the input to bring it close
* to the target
*/
public static int stringEditDistance(String input, String target, int insertCost, int deleteCost,
BiFunction<Character, Character, Integer> replaceCalculator) {
int[][] dp = new int[input.length() + 1][target.length() + 1];
for (int i = 0; i <= input.length(); i++)
dp[i][0] = i;
for (int j = 0; j <= target.length(); j++)
dp[0][j] = j;
for (int i = 0; i < input.length(); i++) {
char cInput = input.charAt(i);
for (int j = 0; j < target.length(); j++) {
char cTarget = target.charAt(j);
if (cInput == cTarget) {
dp[i + 1][j + 1] = dp[i][j];
} else {
int replace = dp[i][j] + replaceCalculator.apply(cInput, cTarget);
int insert = dp[i][j + 1] + insertCost;
int delete = dp[i + 1][j] + deleteCost;
int min = Math.min(replace, Math.min(insert, delete));
dp[i + 1][j + 1] = min;
}
}
}
return dp[input.length()][target.length()];
}
public static void main(String[] args) throws IOException {
// serialize a json object
// edit this json to test with other bad input keys
final String json = "{ \"a\" : \"1\", \"b\" : \"2\", \"jrdiction\" : \"3\" }";
MyChild child = new ObjectMapper().readerFor(MyChild.class).readValue(json);
// List<String> jsonProps = getJsonPropertyNames(child);
// create the list of jsonProps for yourself so you can edit and test easily
List<String> jsonProps = Arrays.asList("a", "b", "jurisdiction");
for (Entry<String, Object> e : child.getAdditionalProperties().entrySet()) {
String nearest = findNearestMatch(e.getKey(), jsonProps);
System.out.println(e.getKey() + " is closest to " + nearest);
}
}