Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Defining grouping in swagger #4246

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,14 @@
*/
AdditionalPropertiesValue additionalProperties() default AdditionalPropertiesValue.USE_ADDITIONAL_PROPERTIES_ANNOTATION;

/**
* Specify one or more groups to link to a specific @RequestBody annotation.
* To define custom groups annotations for the sole purpose of using them as type-safe group arguments.
*
* @since 2.2.3
*/
Class<?>[] groups() default {};

enum AccessMode {
AUTO,
READ_ONLY,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,12 @@
**/
String ref() default "";

/**
* Specify one or more groups to link to a specific @Schema annotation.
* To define custom groups annotations for the sole purpose of using them as type-safe group arguments.
*
* @since 2.2.3
*/
Class<?>[] groups() default {};

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@
import com.fasterxml.jackson.databind.PropertyMetadata;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder;
import com.fasterxml.jackson.databind.introspect.*;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.util.Annotations;
import io.swagger.v3.core.converter.AnnotatedType;
Expand All @@ -43,6 +38,7 @@
import io.swagger.v3.oas.annotations.media.PatternProperty;
import io.swagger.v3.oas.annotations.media.SchemaProperties;
import io.swagger.v3.oas.annotations.media.SchemaProperty;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.media.ArraySchema;
Expand Down Expand Up @@ -181,6 +177,22 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
beanDesc = recurBeanDesc;
}

// use RequestBody annotation to customize and to define configuration to request body object and members
RequestBody requestBody = null;
if(annotatedType != null && annotatedType.getCtxAnnotations() != null){
Optional<Annotation> annotationOptional = Arrays.stream(annotatedType.getCtxAnnotations()).filter(annotation -> annotation instanceof RequestBody).findFirst();
if(annotationOptional.isPresent()){
requestBody = (RequestBody) annotationOptional.get();
}
}

// allocating RequestBody groups
Class<?>[] groups = null;
if(requestBody != null && requestBody.groups() != null) {
groups = requestBody.groups();
} else if (annotatedType != null && annotatedType.getParent() != null && annotatedType.getParent().getGroups() != null) {
groups = annotatedType.getParent().getGroups();
}

String name = annotatedType.getName();
if (StringUtils.isBlank(name)) {
Expand All @@ -195,6 +207,11 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context

name = decorateModelName(annotatedType, name);

// Changing current Schema name to new name fitting for model grouping to make models unique per group
if(name != null && groups != null && groups.length >0) {
name = name.concat("_").concat(Arrays.stream(groups).map(Class::getSimpleName).collect(Collectors.joining("_")));
}

// if we have a ref we don't consider anything else
if (resolvedSchemaAnnotation != null &&
StringUtils.isNotEmpty(resolvedSchemaAnnotation.ref())) {
Expand Down Expand Up @@ -508,6 +525,11 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
}
}

// setting current Schema groups if exists
if(model != null && groups != null && groups.length >0 ) {
model.setGroups(groups);
}

if (!type.isContainerType() && StringUtils.isNotBlank(name)) {
// define the model here to support self/cyclic referencing of models
context.defineModel(name, model, annotatedType, null);
Expand Down Expand Up @@ -577,7 +599,7 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context

PropertyMetadata md = propDef.getMetadata();

if (member != null && !ignore(member, xmlAccessorTypeAnnotation, propName, propertiesToIgnore, propDef)) {
if (member != null && !ignore(member, xmlAccessorTypeAnnotation, propName, propertiesToIgnore, propDef, model)) {

List<Annotation> annotationList = new ArrayList<>();
for (Annotation a : member.annotations()) {
Expand Down Expand Up @@ -1023,7 +1045,7 @@ protected void _addEnumProps(Class<?> propClass, Schema property) {
}

protected boolean ignore(final Annotated member, final XmlAccessorType xmlAccessorTypeAnnotation, final String propName, final Set<String> propertiesToIgnore) {
return ignore (member, xmlAccessorTypeAnnotation, propName, propertiesToIgnore, null);
return ignore (member, xmlAccessorTypeAnnotation, propName, propertiesToIgnore, null, null);
}

protected boolean hasHiddenAnnotation(Annotated annotated) {
Expand All @@ -1033,7 +1055,15 @@ protected boolean hasHiddenAnnotation(Annotated annotated) {
);
}

protected boolean ignore(final Annotated member, final XmlAccessorType xmlAccessorTypeAnnotation, final String propName, final Set<String> propertiesToIgnore, BeanPropertyDefinition propDef) {
private boolean hasGroupAnnotation(Annotated annotated, Schema model) {
if (model != null && model.getGroups() != null && model.getGroups().length != 0) {
io.swagger.v3.oas.annotations.media.Schema schema = annotated.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class);
return !(schema != null && schema.groups() != null && Arrays.asList(schema.groups()).stream().filter(annotatedClass -> Arrays.asList(model.getGroups()).stream().filter(modelClass -> annotatedClass.equals(modelClass)).findFirst().isPresent()).findFirst().isPresent());
}
return false;
}

protected boolean ignore(final Annotated member, final XmlAccessorType xmlAccessorTypeAnnotation, final String propName, final Set<String> propertiesToIgnore, BeanPropertyDefinition propDef, Schema model) {
if (propertiesToIgnore.contains(propName)) {
return true;
}
Expand All @@ -1043,18 +1073,21 @@ protected boolean ignore(final Annotated member, final XmlAccessorType xmlAccess
if (hasHiddenAnnotation(member)) {
return true;
}
if (hasGroupAnnotation(member, model)) {
return true;
}

if (propDef != null) {
if (propDef.hasGetter() && hasHiddenAnnotation(propDef.getGetter())) {
if (propDef.hasGetter() && (hasHiddenAnnotation(propDef.getGetter()) || hasGroupAnnotation(propDef.getGetter(), model))) {
return true;
}
if (propDef.hasSetter() && hasHiddenAnnotation(propDef.getSetter())) {
if (propDef.hasSetter() && (hasHiddenAnnotation(propDef.getSetter()) || hasGroupAnnotation(propDef.getGetter(), model))) {
return true;
}
if (propDef.hasConstructorParameter() && hasHiddenAnnotation(propDef.getConstructorParameter())) {
if (propDef.hasConstructorParameter() && (hasHiddenAnnotation(propDef.getConstructorParameter()) || hasGroupAnnotation(propDef.getGetter(), model))) {
return true;
}
if (propDef.hasField() && hasHiddenAnnotation(propDef.getField())) {
if (propDef.hasField() && (hasHiddenAnnotation(propDef.getField()) || hasGroupAnnotation(propDef.getGetter(), model))) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1792,6 +1792,15 @@ public AdditionalPropertiesValue additionalProperties() {
}
return patch.additionalProperties();
}

@Override
public Class<?>[] groups() {
if ((master.groups() != null || patch.groups() == null) && (master.groups().length > 0 || (patch.groups() != null && patch.groups().length == 0))) {
return master.groups();
}
return patch.groups();

}
};

return (io.swagger.v3.oas.annotations.media.Schema)schema;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ public Schema specVersion(SpecVersion specVersion) {
@OpenAPI31
private Boolean booleanSchemaValue;

/**
* @since 2.2.3
*
* when set, this represents the groups which the schema is created from if any
*/
@JsonIgnore
private Class<?>[] groups;

/**
*
* @since 2.2.0 (OpenAPI 3.1.0)
Expand Down Expand Up @@ -2169,5 +2177,29 @@ public Schema booleanSchemaValue(Boolean booleanSchemaValue) {
this.booleanSchemaValue = booleanSchemaValue;
return this;
}
/**
*
* @since 2.2.3
*/
public Class<?>[] getGroups() {
return groups;
}

/**
*
* @since 2.2.3
*/
public void setGroups(Class<?>[] groups) {
this.groups = groups;
}

/**
*
* @since 2.2.3
*/
public Schema groups(Class<?>[] groups) {
this.groups = groups;
return this;
}
}