-
Notifications
You must be signed in to change notification settings - Fork 138
Description
In version 2.4.1, VisitorContext was added, which keeps track of visited JavaTypes in a static HashSet, with static methods to add to and get from the static HashSet. Because of this, if you use SchemaFactoryWrapper to generate json schema multiple times during a given run of the JVM, you may get references along the lines of "$ref" : "urn:jsonschema:test:JsonSchemaTest:Bar" when no such id exists in the json schema document generated. To make matters worse, because VisitorContext is all static, there's no way to work around the problem.
here's a quick test case that produces the issue:
package test;
import java.io.StringWriter;
import org.junit.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper;
public class JsonSchemaTest {
class Foo {
private String fooProp1;
private int fooProp2;
private Bar fooProp3;
public String getFooProp1() {
return fooProp1;
}
public void setFooProp1(String fooProp1) {
this.fooProp1 = fooProp1;
}
public int getFooProp2() {
return fooProp2;
}
public void setFooProp2(int fooProp2) {
this.fooProp2 = fooProp2;
}
public Bar getFooProp3() {
return fooProp3;
}
public void setFooProp3(Bar fooProp3) {
this.fooProp3 = fooProp3;
}
}
class Bar {
private String barProp1;
private int barProp2;
public String getBarProp1() {
return barProp1;
}
public void setBarProp1(String barProp1) {
this.barProp1 = barProp1;
}
public int getBarProp2() {
return barProp2;
}
public void setBarProp2(int barProp2) {
this.barProp2 = barProp2;
}
}
class Qwer {
private String qwerProp1;
private Bar qwerProp2;
public String getQwerProp1() {
return qwerProp1;
}
public void setQwerProp1(String qwerProp1) {
this.qwerProp1 = qwerProp1;
}
public Bar getQwerProp2() {
return qwerProp2;
}
public void setQwerProp2(Bar qwerProp2) {
this.qwerProp2 = qwerProp2;
}
}
@Test
public void testSchemaGeneration() throws Exception {
printJsonSchema(Foo.class);
printJsonSchema(Qwer.class);
}
private void printJsonSchema(Class<?> clazz) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
SchemaFactoryWrapper visitor = new SchemaFactoryWrapper();
mapper.acceptJsonFormatVisitor(
mapper.constructType(
clazz), visitor);
StringWriter sr = new StringWriter();
mapper.writeValue(sr, visitor.finalSchema());
System.out.println(sr.toString());
}
}
output:
{
"type" : "object",
"id" : "urn:jsonschema:test:JsonSchemaTest:Foo",
"properties" : {
"fooProp3" : {
"type" : "object",
"id" : "urn:jsonschema:test:JsonSchemaTest:Bar",
"properties" : {
"barProp1" : {
"type" : "string"
},
"barProp2" : {
"type" : "integer"
}
}
},
"fooProp2" : {
"type" : "integer"
},
"fooProp1" : {
"type" : "string"
}
}
}
{
"type" : "object",
"id" : "urn:jsonschema:test:JsonSchemaTest:Qwer",
"properties" : {
"qwerProp2" : {
"type" : "object",
"$ref" : "urn:jsonschema:test:JsonSchemaTest:Bar"
},
"qwerProp1" : {
"type" : "string"
}
}
}
Note that the second object in the output is incomplete."$ref" : "urn:jsonschema:test:JsonSchemaTest:Bar" refers to an id from the prior schema generation operation that got statically cached.