Skip to content

Commit

Permalink
JSONSchema support cycle reference
Browse files Browse the repository at this point in the history
  • Loading branch information
wenshao committed Oct 5, 2023
1 parent ed7b039 commit 1d99790
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public abstract class JSONSchema {
this.description = description;
}

void addResolveTask(UnresolvedReference.ResolveTask task){
}

public static JSONSchema of(JSONObject input, Class objectClass) {
if (input == null || input.isEmpty()) {
return null;
Expand Down Expand Up @@ -448,7 +451,7 @@ public static JSONSchema of(JSONObject input, JSONSchema parent) {
refName = URLDecoder.decode(refName);
JSONSchema refSchema = defs.get(refName);
if (refSchema == null) {
refSchema = Any.NOT_ANY;
refSchema = new UnresolvedReference(refName);
}
return refSchema;
}
Expand Down Expand Up @@ -866,7 +869,8 @@ public enum Type {
OneOf,
AllOf,
AnyOf,
Any;
Any,
UnresolvedReference;

public static Type of(String typeStr) {
if (typeStr == null) {
Expand Down
22 changes: 22 additions & 0 deletions core/src/main/java/com/alibaba/fastjson2/schema/ObjectSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public final class ObjectSchema
final AnyOf anyOf;
final OneOf oneOf;

transient List<UnresolvedReference.ResolveTask> resolveTasks;

public ObjectSchema(JSONObject input) {
this(input, null);
}
Expand Down Expand Up @@ -72,6 +74,11 @@ public ObjectSchema(JSONObject input, JSONSchema root) {
JSONSchema schema = JSONSchema.of(entryValue, root == null ? this : root);
this.defs.put(entryKey, schema);
}
if (resolveTasks != null) {
for (UnresolvedReference.ResolveTask resolveTask : resolveTasks) {
resolveTask.resolve(this);
}
}
}

JSONObject properties = input.getJSONObject("properties");
Expand All @@ -88,6 +95,13 @@ public ObjectSchema(JSONObject input, JSONSchema root) {
schema = JSONSchema.of((JSONObject) entryValue, root == null ? this : root);
}
this.properties.put(entryKey, schema);
if (schema instanceof UnresolvedReference) {
String refName = ((UnresolvedReference) schema).refName;
UnresolvedReference.PropertyResolveTask task
= new UnresolvedReference.PropertyResolveTask(this.properties, entryKey, refName);
JSONSchema resolveRoot = root == null ? this : root;
resolveRoot.addResolveTask(task);
}
}
}

Expand Down Expand Up @@ -199,6 +213,14 @@ public ObjectSchema(JSONObject input, JSONSchema root) {
oneOf = oneOf(input, null);
}

@Override
void addResolveTask(UnresolvedReference.ResolveTask task) {
if (resolveTasks == null) {
resolveTasks = new ArrayList<>();
}
resolveTasks.add(task);
}

@Override
public Type getType() {
return Type.Object;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.alibaba.fastjson2.schema;

import java.util.Map;

public class UnresolvedReference
extends JSONSchema {
final String refName;
UnresolvedReference(String refName) {
super(null, null);
this.refName = refName;
}

@Override
public Type getType() {
return Type.UnresolvedReference;
}

@Override
public ValidateResult validate(Object value) {
return JSONSchema.SUCCESS;
}

abstract static class ResolveTask {
abstract void resolve(JSONSchema root);
}

static class PropertyResolveTask
extends ResolveTask {
final Map<String, JSONSchema> properties;
final String entryKey;
final String refName;

PropertyResolveTask(Map<String, JSONSchema> properties, String entryKey, String refName) {
this.properties = properties;
this.entryKey = entryKey;
this.refName = refName;
}

@Override
void resolve(JSONSchema root) {
Map<String, JSONSchema> defs = null;
if (root instanceof ObjectSchema) {
defs = ((ObjectSchema) root).defs;
} else if (root instanceof ArraySchema) {
defs = ((ArraySchema) root).defs;
}

if (defs == null) {
return;
}

JSONSchema refSchema = defs.get(refName);
if (refSchema != null) {
properties.put(entryKey, refSchema);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class Issue1766 {
@Test
Expand Down Expand Up @@ -37,5 +38,12 @@ public void test() {
JSONSchema person = schema.getDefs("person");
ArraySchema personList = (ArraySchema) schema.getDefs("personList");
assertSame(person, personList.getItemSchema());

assertTrue(
schema.validate(
JSON.parseObject("\n" +
"{\"family\":{\"name\":\"1\",\"children\":[{\"name\":\"2\"}]}}")
).isSuccess()
);
}
}

0 comments on commit 1d99790

Please sign in to comment.