EnumSet Use and Configuration #303
-
I am having an issue with jsonschema output when using an enumset and its unclear if its an Option Setting or something else. e.g., MyEnum = {"OPTION1","OPTION2","OPTION3"} private final EnumSet myProperty = EnumSet.of(MyEnum.OPTION1, MyEnum.OPTION3);
The expectation would only contain Option 1 and Option 3. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
Hi @dalucasPeraton, There are a couple of configuration options for enums in general. But you're expecting instance data to be considered, which is not supported out of the box for this kind of non-static variable. |
Beta Was this translation helpful? Give feedback.
-
For completeness' sake, this is what it could look like: public class EnumSetExample303 {
public static void main(String[] args) throws JsonProcessingException {
SchemaGeneratorConfigBuilder builder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON);
builder.forFields()
.withCustomDefinitionProvider(new EnumSetFieldDefinitionProvider());
JsonNode jsonSchema = new SchemaGenerator(builder.build()).generateSchema(SchemaTarget.class);
System.out.println(jsonSchema.toPrettyString());
}
static class SchemaTarget {
private final EnumSet<MyEnum> enumSet = EnumSet.of(MyEnum.ONE, MyEnum.THREE);
public EnumSet<MyEnum> getEnumSet() {
return this.enumSet;
}
}
private static enum MyEnum {
ONE, TWO, THREE;
}
private static class EnumSetFieldDefinitionProvider implements CustomPropertyDefinitionProvider<FieldScope> {
@Override
public CustomPropertyDefinition provideCustomSchemaDefinition(FieldScope scope, SchemaGenerationContext context) {
if (!scope.isFinal() || scope.getType().getErasedType() != EnumSet.class
|| (scope.isPrivate() && (!scope.hasGetter() || scope.findGetter().isPrivate()))) {
return null;
}
ResolvedType declaringType = scope.getDeclaringType();
Optional<RawConstructor> paramLessConstructor = declaringType.getConstructors().stream()
.filter(constructor -> constructor.getRawMember().getParameterCount() == 0)
.findFirst();
if (!paramLessConstructor.isPresent()) {
return null;
}
try {
Object declaringInstance = paramLessConstructor.get().getRawMember().newInstance();
Object enumSetInstance = scope.isPrivate()
? scope.findGetter().getRawMember().invoke(declaringInstance)
: scope.getMember().getRawMember().get(declaringInstance);
ObjectNode fieldSchema = context.createStandardDefinition(scope, this);
ObjectNode setItemSchema = fieldSchema.with(context.getKeyword(SchemaKeyword.TAG_ITEMS));
setItemSchema.remove(context.getKeyword(SchemaKeyword.TAG_CONST));
ArrayNode enumPropertyArray = setItemSchema.withArray(context.getKeyword(SchemaKeyword.TAG_ENUM));
enumPropertyArray.removeAll();
((EnumSet<?>) enumSetInstance).forEach(enumValue -> enumPropertyArray.add(enumValue.toString()));
return new CustomPropertyDefinition(fieldSchema);
} catch (Exception ex) {
// inaccessible constructor (e.g. a private one)
ex.printStackTrace();
return null;
}
}
}
} This produces: {
"$schema" : "https://json-schema.org/draft/2020-12/schema",
"type" : "object",
"properties" : {
"enumSet" : {
"type" : "array",
"items" : {
"enum" : [ "ONE", "THREE" ],
"type" : "string"
}
}
}
} That begs the question though, why you'd have a |
Beta Was this translation helpful? Give feedback.
For completeness' sake, this is what it could look like: