Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,13 @@ public String getParameterName() {
}

@Override
@Nullable
public Method getMethod() {
return delegate.getMethod();
}

@Override
@Nullable
public Constructor<?> getConstructor() {
return delegate.getConstructor();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ Schema calculateSchema(Components components, ParameterInfo parameterInfo, Reque
Annotation[] paramAnnotations = getParameterAnnotations(methodParameter);
TypeAndTypeAnnotations resolved = resolveTypeAndTypeAnnotationsForParameter(methodParameter);
Type type = resolved.type();
Annotation[] typeAnnotations = resolved.typeAnnotations();
Annotation[] typeAnnotations = resolved.typeAnnotations().toArray(Annotation[]::new);
Annotation[] mergedAnnotations =
Stream.concat(
Arrays.stream(paramAnnotations),
Expand Down Expand Up @@ -439,7 +439,7 @@ private TypeAndTypeAnnotations resolveTypeAndTypeAnnotationsForParameter(MethodP
&& delegatingMethodParameter.getField() != null) {
AnnotatedType annotated = delegatingMethodParameter.getField().getAnnotatedType();
Type type = GenericTypeResolver.resolveType(annotated.getType(), methodParameter.getContainingClass());
return new TypeAndTypeAnnotations(type, annotationsFromAnnotatedTypeArguments(annotated));
return new TypeAndTypeAnnotations(type, Arrays.asList(annotationsFromAnnotatedTypeArguments(annotated)));
}

Type type = GenericTypeResolver.resolveType(methodParameter.getGenericParameterType(), methodParameter.getContainingClass());
Expand All @@ -449,17 +449,17 @@ private TypeAndTypeAnnotations resolveTypeAndTypeAnnotationsForParameter(MethodP
&& type == String.class) {
Class<?> restored = KotlinInlineParameterResolver.resolveInlineType(methodParameter, type);
return restored != null
? new TypeAndTypeAnnotations(restored, restored.getAnnotations())
: new TypeAndTypeAnnotations(type, new Annotation[0]);
? new TypeAndTypeAnnotations(restored, Arrays.asList(restored.getAnnotations()))
: new TypeAndTypeAnnotations(type, new ArrayList<>());
}

return new TypeAndTypeAnnotations(type, methodParameter.getParameterType().getAnnotations());
return new TypeAndTypeAnnotations(type, Arrays.asList(methodParameter.getParameterType().getAnnotations()));
}

/**
* Pair of resolved Java type and type annotations merged with parameter annotations for {@code extractSchema}.
*/
private record TypeAndTypeAnnotations(Type type, Annotation[] typeAnnotations) {
private record TypeAndTypeAnnotations(Type type, List<Annotation> typeAnnotations) {
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,9 @@ private void setPathItemOperation(PathItem pathItemObject, String method, Operat
case TRACE_METHOD -> pathItemObject.trace(operation);
case HEAD_METHOD -> pathItemObject.head(operation);
case OPTIONS_METHOD -> pathItemObject.options(operation);
default -> { }
default -> {
// best effort with regard to supported operations
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,17 @@ public boolean fieldNullable(Field field) {
}

// @Nullable/@NotNull
Boolean ann = nullableFromAnnotations(field);
if (ann != null) return ann;
Optional<Boolean> ann = nullableFromAnnotations(field);
if (ann.isPresent()) {
return ann.get();
}

// Kotlin nullability
if (kotlinUtilsOptional.isPresent() && isKotlinDeclaringClass(field)) {
Boolean kotlin = kotlinNullability(field);
if (kotlin != null) return kotlin;
Optional<Boolean> kotlin = kotlinNullability(field);
if (kotlin.isPresent()) {
return kotlin.get();
}
}

return JAVA_FIELD_NULLABLE_DEFAULT;
Expand Down Expand Up @@ -204,17 +208,15 @@ public boolean fieldRequired(Field field, io.swagger.v3.oas.annotations.media.Sc
// Kotlin logic
if (kotlinUtilsOptional.isPresent() && isKotlinDeclaringClass(field)) {
if (fieldNullable(field)) return false;
Boolean hasDefault = kotlinConstructorParamIsOptional(field);
if (Boolean.TRUE.equals(hasDefault)) return false;
return true;
}
return kotlinConstructorParamIsOptional(field)
.map(isOptional -> !isOptional)
.orElse(true);
}

// Jackson @JsonProperty(required = true)
JsonProperty jp = getJsonProperty(field);
if (jp != null && jp.required()) return true;

return false;
}
return jp != null && jp.required();
}

/**
* Apply validations to schema. the annotation order effects the result of the
Expand Down Expand Up @@ -376,15 +378,15 @@ private static List<Class<? extends Annotation>> findOverrides(Annotation annota
* @param field the field
* @return the boolean
*/
private static Boolean nullableFromAnnotations(Field field) {
if (hasNullableAnnotation(field)) return true;
if (hasNotNullAnnotation(field)) return false;
private static Optional<Boolean> nullableFromAnnotations(Field field) {
if (hasNullableAnnotation(field)) return Optional.of(true);
if (hasNotNullAnnotation(field)) return Optional.of(false);
Method getter = findGetter(field);
if (getter != null) {
if (hasNullableAnnotation(getter)) return true;
if (hasNotNullAnnotation(getter)) return false;
if (hasNullableAnnotation(getter)) return Optional.of(true);
if (hasNotNullAnnotation(getter)) return Optional.of(false);
}
return null;
return Optional.empty();
}

/**
Expand Down Expand Up @@ -579,15 +581,13 @@ public static void fixOAS31ExclusiveConstraints(Schema<?> schema) {
return;
}
if (schema.getSpecVersion().equals(SpecVersion.V31)) {
if (schema.getExclusiveMaximumValue() != null && schema.getMaximum() != null) {
if (schema.getMaximum().compareTo(schema.getExclusiveMaximumValue()) == 0) {
schema.setMaximum(null);
}
if (schema.getExclusiveMaximumValue() != null && schema.getMaximum() != null
&& schema.getMaximum().compareTo(schema.getExclusiveMaximumValue()) == 0) {
schema.setMaximum(null);
}
if (schema.getExclusiveMinimumValue() != null && schema.getMinimum() != null) {
if (schema.getMinimum().compareTo(schema.getExclusiveMinimumValue()) == 0) {
schema.setMinimum(null);
}
if (schema.getExclusiveMinimumValue() != null && schema.getMinimum() != null &&
schema.getMinimum().compareTo(schema.getExclusiveMinimumValue()) == 0) {
schema.setMinimum(null);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
package org.springdoc.core.utils;

import java.lang.reflect.Field;
import java.util.Optional;

import kotlin.jvm.JvmClassMappingKt;
import kotlin.reflect.KClass;
Expand All @@ -46,6 +47,9 @@
*/
public class SpringDocKotlinUtils {

public SpringDocKotlinUtils() {
}

/**
* Is kotlin declaring class boolean.
*
Expand All @@ -64,19 +68,18 @@ static boolean isKotlinDeclaringClass(Field f) {
* @param f the f
* @return the boolean
*/
private static Boolean kotlinMarkedNullableFallback(Field f) {
private static Optional<Boolean> kotlinMarkedNullableFallback(Field f) {
try {
KClass<?> kClass = JvmClassMappingKt.getKotlinClass(f.getDeclaringClass());
for (Object pObj : KClasses.getMemberProperties((KClass<Object>) kClass)) {
KProperty1<?, ?> p = (KProperty1<?, ?>) pObj;
if (p.getName().equals(f.getName())) {
return p.getReturnType().isMarkedNullable();
for (KProperty1<?, ?> pObj : KClasses.getMemberProperties(kClass)) {
if (pObj.getName().equals(f.getName())) {
return Optional.of(pObj.getReturnType().isMarkedNullable());
}
}
} catch (Exception ignored) {
// best-effort only
}
return null;
return Optional.empty();
}

/**
Expand All @@ -85,21 +88,21 @@ private static Boolean kotlinMarkedNullableFallback(Field f) {
* @param f the f
* @return the boolean
*/
static Boolean kotlinConstructorParamIsOptional(Field f) {
static Optional<Boolean> kotlinConstructorParamIsOptional(Field f) {
try {
KClass<?> kClass = JvmClassMappingKt.getKotlinClass(f.getDeclaringClass());
KFunction<?> primary = KClasses.getPrimaryConstructor(kClass);
if (primary != null) {
for (KParameter p : primary.getParameters()) {
if (f.getName().equals(p.getName())) {
return p.isOptional();
return Optional.of(p.isOptional());
}
}
}
} catch (Exception ignored) {
// best-effort only
}
return null;
return Optional.empty();
}

/**
Expand All @@ -108,12 +111,12 @@ static Boolean kotlinConstructorParamIsOptional(Field f) {
* @param field the field
* @return the boolean
*/
static Boolean kotlinNullability(Field field) {
if (!isKotlinDeclaringClass(field)) return null;
static Optional<Boolean> kotlinNullability(Field field) {
if (!isKotlinDeclaringClass(field)) return Optional.empty();

KProperty<?> prop = ReflectJvmMapping.getKotlinProperty(field);
if (prop != null) {
return prop.getReturnType().isMarkedNullable();
return Optional.of(prop.getReturnType().isMarkedNullable());
}

return kotlinMarkedNullableFallback(field);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,9 @@ public static void fixNullOnlyAdditionalProperties(Schema<?> schema) {
if (additionalProperties instanceof Schema<?> addPropSchema) {
boolean isNullOnlyType = false;
Set<String> types = addPropSchema.getTypes();
if (types != null && types.size() == 1 && types.contains("null")) {
isNullOnlyType = true;
}
else if (types == null && "null".equals(addPropSchema.getType())) {
boolean onlyNullTypeOAS31 = types != null && types.size() == 1 && types.contains("null");
boolean onlyNullTypeOAS30 = types == null && "null".equals(addPropSchema.getType());
if (onlyNullTypeOAS31 || onlyNullTypeOAS30) {
isNullOnlyType = true;
}
if (isNullOnlyType && addPropSchema.get$ref() == null
Expand All @@ -214,7 +213,7 @@ else if (types == null && "null".equals(addPropSchema.getType())) {
}
}
if (schema.getProperties() != null) {
schema.getProperties().values().forEach(prop -> fixNullOnlyAdditionalProperties((Schema<?>) prop));
schema.getProperties().values().forEach(SpringDocUtils::fixNullOnlyAdditionalProperties);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
*/
public class ScalarConstants {

private ScalarConstants() {
}

/**
* The constant SCALAR_DEFAULT_PATH.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
package org.springdoc.ui;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springdoc.core.properties.SwaggerUiConfigProperties;

Expand Down Expand Up @@ -185,10 +187,10 @@ private PathPattern parsePattern(String pattern) {
* @param patterns the patterns to match.
* @param locations the locations to use.
*/
protected record SwaggerResourceHandlerConfig(boolean cacheResources, String[] patterns, String[] locations) {
protected record SwaggerResourceHandlerConfig(boolean cacheResources, List<String> patterns, List<String> locations) {

private SwaggerResourceHandlerConfig(boolean cacheResources) {
this(cacheResources, new String[]{}, new String[]{});
this(cacheResources, new ArrayList<>(), new ArrayList<>());
}

/**
Expand All @@ -199,7 +201,15 @@ private SwaggerResourceHandlerConfig(boolean cacheResources) {
* @return the updated config.
*/
public SwaggerResourceHandlerConfig setPatterns(String... patterns) {
return new SwaggerResourceHandlerConfig(cacheResources, patterns, locations);
return new SwaggerResourceHandlerConfig(cacheResources, Arrays.asList(patterns), locations);
}

/**
*
* @return String array of patterns
*/
public String[] patternsArray() {
return patterns.toArray(new String[0]);
}

/**
Expand All @@ -210,7 +220,15 @@ public SwaggerResourceHandlerConfig setPatterns(String... patterns) {
* @return the updated config.
*/
public SwaggerResourceHandlerConfig setLocations(String... locations) {
return new SwaggerResourceHandlerConfig(cacheResources, patterns, locations);
return new SwaggerResourceHandlerConfig(cacheResources, patterns, Arrays.asList(locations));
}

/**
*
* @return String array of locations
*/
public String[] locationsArray() {
return locations.toArray(new String[0]);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ protected void addSwaggerResourceHandlers(ResourceHandlerRegistry registry, Swag
* @param handlerConfig the swagger handler config.
*/
protected void addSwaggerResourceHandler(ResourceHandlerRegistry registry, SwaggerResourceHandlerConfig handlerConfig) {
ResourceHandlerRegistration handlerRegistration = registry.addResourceHandler(handlerConfig.patterns());
handlerRegistration.addResourceLocations(handlerConfig.locations());
ResourceHandlerRegistration handlerRegistration = registry.addResourceHandler(handlerConfig.patternsArray());
handlerRegistration.addResourceLocations(handlerConfig.locationsArray());

ResourceChainRegistration chainRegistration;
if (handlerConfig.cacheResources()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ protected void addSwaggerResourceHandlers(ResourceHandlerRegistry registry, Swag
* @param handlerConfig the swagger handler config.
*/
protected void addSwaggerResourceHandler(ResourceHandlerRegistry registry, SwaggerResourceHandlerConfig handlerConfig) {
ResourceHandlerRegistration handlerRegistration = registry.addResourceHandler(handlerConfig.patterns());
handlerRegistration.addResourceLocations(handlerConfig.locations());
ResourceHandlerRegistration handlerRegistration = registry.addResourceHandler(handlerConfig.patternsArray());
handlerRegistration.addResourceLocations(handlerConfig.locationsArray());

ResourceChainRegistration chainRegistration;
if (handlerConfig.cacheResources()) {
Expand Down
Loading