Skip to content

Commit

Permalink
Add support for minProperties and maxProperties (fabric8io#5836)
Browse files Browse the repository at this point in the history
  • Loading branch information
baloo42 committed Oct 22, 2024
1 parent 0f0ec70 commit b5a3b93
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import com.fasterxml.jackson.module.jsonSchema.types.ArraySchema;
import com.fasterxml.jackson.module.jsonSchema.types.ArraySchema.Items;
import com.fasterxml.jackson.module.jsonSchema.types.NumberSchema;
import com.fasterxml.jackson.module.jsonSchema.types.ObjectSchema;
import com.fasterxml.jackson.module.jsonSchema.types.ObjectSchema.SchemaAdditionalProperties;
import com.fasterxml.jackson.module.jsonSchema.types.ReferenceSchema;
Expand Down Expand Up @@ -215,6 +217,18 @@ void collectValidationRules(BeanProperty beanProperty, List<V> validationRules)
.ifPresent(ann -> Stream.of(ann.value()).map(this::from).forEach(validationRules::add));
}

private Optional<Long> findMinInSizeAnnotation(BeanProperty beanProperty) {
return ofNullable(beanProperty.getAnnotation(Size.class))
.map(Size::min)
.filter(v -> v > 0);
}

private Optional<Long> findMaxInSizeAnnotation(BeanProperty beanProperty) {
return ofNullable(beanProperty.getAnnotation(Size.class))
.map(Size::max)
.filter(v -> v < Long.MAX_VALUE);
}

class PropertyMetadata {

private boolean required;
Expand All @@ -229,6 +243,8 @@ class PropertyMetadata {
private Long maxLength;
private Long minItems;
private Long maxItems;
private Long minProperties;
private Long maxProperties;
private boolean nullable;
private String format;
private List<V> validationRules = new ArrayList<>();
Expand All @@ -253,44 +269,43 @@ public PropertyMetadata(JsonSchema value, BeanProperty beanProperty) {
StringSchema stringSchema = value.asStringSchema();
// only set if ValidationSchemaFactoryWrapper is used

pattern = ofNullable(stringSchema.getPattern())
.or(() -> ofNullable(beanProperty.getAnnotation(Pattern.class)).map(Pattern::value))
.orElse(null);

maxLength = ofNullable(stringSchema.getMaxLength())
.map(Integer::longValue)
.or(() -> ofNullable(beanProperty.getAnnotation(Size.class))
.map(Size::max)
.filter(v -> v < Long.MAX_VALUE))
.orElse(null);
minLength = ofNullable(stringSchema.getMinLength())
.map(Integer::longValue)
.or(() -> ofNullable(beanProperty.getAnnotation(Size.class))
.map(Size::min)
.filter(v -> v > 0))
.orElse(null);
} else if(value.isNumberSchema() || value.isIntegerSchema()){
pattern = ofNullable(beanProperty.getAnnotation(Pattern.class)).map(Pattern::value)
.or(() -> ofNullable(stringSchema.getPattern()))
.orElse(null);
minLength = findMinInSizeAnnotation(beanProperty)
.or(() -> ofNullable(stringSchema.getMinLength()).map(Integer::longValue))
.orElse(null);
maxLength = findMaxInSizeAnnotation(beanProperty)
.or(() -> ofNullable(stringSchema.getMaxLength()).map(Integer::longValue))
.orElse(null);
} else if (value.isNumberSchema()) {
NumberSchema numberSchema = value.asNumberSchema();
// minimum and maximum are only allowed on number and integer types
ofNullable(beanProperty.getAnnotation(Max.class)).ifPresent(a -> {
max = a.value();
if (!a.inclusive()) {
exclusiveMaximum = true;
}
});
ofNullable(beanProperty.getAnnotation(Min.class)).ifPresent(a -> {
min = a.value();
if (!a.inclusive()) {
exclusiveMinimum = true;
}
});
ofNullable(beanProperty.getAnnotation(Max.class)).ifPresent(a -> {
max = a.value();
if (!a.inclusive()) {
exclusiveMaximum = true;
}
});
} else if (value.isArraySchema()) {
maxItems = ofNullable(beanProperty.getAnnotation(Size.class))
.map(Size::max)
.filter(v -> v < Long.MAX_VALUE)
ArraySchema arraySchema = value.asArraySchema();
minItems = findMinInSizeAnnotation(beanProperty)
.or(() -> ofNullable(arraySchema.getMinItems()).map(Integer::longValue))
.orElse(null);
maxItems = findMaxInSizeAnnotation(beanProperty)
.or(() -> ofNullable(arraySchema.getMaxItems()).map(Integer::longValue))
.orElse(null);
minItems = ofNullable(beanProperty.getAnnotation(Size.class))
.map(Size::min)
.filter(v -> v > 0)
} else if (value.isObjectSchema()) {
// TODO: Could be also applied only on Maps instead of "all the rest"
minProperties = findMinInSizeAnnotation(beanProperty)
.orElse(null);
maxProperties = findMaxInSizeAnnotation(beanProperty)
.orElse(null);
}

Expand All @@ -316,7 +331,7 @@ public void updateSchema(T schema) {
}
}
if (nullable) {
schema.setNullable(nullable);
schema.setNullable(true);
}
schema.setMaximum(max);
schema.setExclusiveMaximum(exclusiveMaximum);
Expand All @@ -329,6 +344,9 @@ public void updateSchema(T schema) {
schema.setMinItems(minItems);
schema.setMaxItems(maxItems);

schema.setMinProperties(minProperties);
schema.setMaxProperties(maxProperties);

schema.setPattern(pattern);
schema.setFormat(format);
if (preserveUnknownFields) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public interface KubernetesJSONSchemaProps {

void setMaxItems(Long max);

void setMinProperties(Long min);

void setMaxProperties(Long max);

void setPattern(String pattern);

void setFormat(String format);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import lombok.Data;

import java.util.List;
import java.util.Map;

@Data
public class ValidationSpec {
Expand All @@ -36,6 +37,7 @@ public class ValidationSpec {
private ValidationOnDoublePrim onDoublePrim;
private ValidationOnString onString;
private ValidationOnList onList;
private ValidationOnMap onMap;

@Data
static class ValidationOnInteger {
Expand Down Expand Up @@ -204,4 +206,14 @@ static class ValidationOnList {
private List<String> minItems1maxItems3;
}

@Data
static class ValidationOnMap {
@Size(min = 1)
private Map<String, String> minItems1;
@Size(max = 1)
private Map<String, String> maxItems1;
@Size(min = 1, max = 3)
private Map<String, String> minItems1maxItems3;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,25 @@ spec:
minimum: 1.0
type: "integer"
type: "object"
onMap:
properties:
maxItems1:
additionalProperties:
type: "string"
maxProperties: 1
type: "object"
minItems1:
additionalProperties:
type: "string"
minProperties: 1
type: "object"
minItems1maxItems3:
additionalProperties:
type: "string"
maxProperties: 3
minProperties: 1
type: "object"
type: "object"
onString:
properties:
maxLength1:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.fabric8.generator.annotation;

import java.lang.annotation.ElementType;
Expand Down

0 comments on commit b5a3b93

Please sign in to comment.