1package com.example.yaml;
2
3import java.util.List;
4import java.util.Map;
5import java.util.Set;
6import java.util.HashSet;
7import java.util.ArrayList;
8
9public class YamlSchemaValidator {
10
11
12public List<ValidationError> validate(Object yamlData, YamlSchema schema) {
13List<ValidationError> errors = new ArrayList<>();
14validateRecursive(yamlData, schema.getRootSchema(), "", errors);
15return errors;
16}
17
18
19private void validateRecursive(Object data, SchemaNode schemaNode, String path, List<ValidationError> errors) {
20if (schemaNode == null) {
21
22errors.add(new ValidationError(path, "Schema definition error: missing node."));
23return;
24}
25
26
27if (!isTypeMatch(data, schemaNode.getType())) {
28errors.add(new ValidationError(path, "Expected type '" + schemaNode.getType() + "', but found '" + (data == null ? "null" : data.getClass().getSimpleName()) + "'."));
29return;
30}
31
32if (data == null) {
33
34
35return;
36}
37
38
39switch (schemaNode.getType()) {
40case "object":
41if (!(data instanceof Map)) { return; }
42Map<?, ?> dataMap = (Map<?, ?>) data;
43
44for (String requiredProp : schemaNode.getRequiredProperties()) {
45if (!dataMap.containsKey(requiredProp)) {
46errors.add(new ValidationError(path + "." + requiredProp, "Required property '" + requiredProp + "' is missing."));
47}
48}
49
50for (Map.Entry<?, ?> entry : dataMap.entrySet()) {
51String key = entry.getKey().toString();
52SchemaNode propertySchema = schemaNode.getPropertySchema(key);
53if (propertySchema != null) {
54validateRecursive(entry.getValue(), propertySchema, path + "." + key, errors);
55} else if (!schemaNode.isAllowAdditionalProperties()) {
56errors.add(new ValidationError(path + "." + key, "Unexpected property '" + key + "'."));
57}
58}
59break;
60case "array":
61if (!(data instanceof List)) { return; }
62List<?> dataList = (List<?>) data;
63SchemaNode itemsSchema = schemaNode.getItemsSchema();
64if (itemsSchema != null) {
65for (int i = 0; i < dataList.size(); i++) {
66validateRecursive(dataList.get(i), itemsSchema, path + "[" + i + "]", errors);
67}
68}
69
70break;
71case "string":
72
73break;
74case "integer":
75case "number":
76
77break;
78case "boolean":
79
80break;
81default:
82
83errors.add(new ValidationError(path, "Unknown schema type: '" + schemaNode.getType() + "'."));
84break;
85}
86}
87
88
89private boolean isTypeMatch(Object data, String schemaType) {
90if (data == null) return true;
91switch (schemaType) {
92case "object": return data instanceof Map;
93case "array": return data instanceof List;
94case "string": return data instanceof String;
95case "integer": return data instanceof Integer;
96case "number": return data instanceof Integer || data instanceof Double || data instanceof Float;
97case "boolean": return data instanceof Boolean;
98default: return false;
99}
100}
101
102
103
104
105public static class SchemaNode {
106private String type;
107private Set<String> requiredProperties = new HashSet<>();
108private Map<String, SchemaNode> properties = new java.util.HashMap<>();
109private SchemaNode itemsSchema;
110private boolean allowAdditionalProperties = false;
111
112public SchemaNode(String type) { this.type = type; }
113public String getType() { return type; }
114public void addRequiredProperty(String prop) { requiredProperties.add(prop); }
115public Set<String> getRequiredProperties() { return requiredProperties; }
116public void addProperty(String name, SchemaNode schema) { properties.put(name, schema); }
117public SchemaNode getPropertySchema(String name) { return properties.get(name); }
118public void setItemsSchema(SchemaNode itemsSchema) { this.itemsSchema = itemsSchema; }
119public SchemaNode getItemsSchema() { return itemsSchema; }
120public void setAllowAdditionalProperties(boolean allow) { allowAdditionalProperties = allow; }
121public boolean isAllowAdditionalProperties() { return allowAdditionalProperties; }
122}
123
124public static class YamlSchema {
125private SchemaNode rootSchema;
126public YamlSchema(SchemaNode root) { this.rootSchema = root; }
127public SchemaNode getRootSchema() { return rootSchema; }
128}
129
130public static class ValidationError {
131private String path;
132private String message;
133public ValidationError(String path, String message) { this.path = path; this.message = message; }
134public String getPath() { return path; }
135public String getMessage() { return message; }
136@Override public String toString() { return "ValidationError{path='" + path + "', message='" + message + "'}"; }
137}
138
139public static void main(String[] args) {
140
141}
142}