Skip to content
Merged
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 @@ -9,6 +9,9 @@
*/
public class KotlinConstants {

public static final DotName METADATA = DotName
.createSimple("kotlin.Metadata");

public static final DotName CONTINUATION = DotName
.createSimple("kotlin.coroutines.Continuation");

Expand Down
29 changes: 29 additions & 0 deletions core/src/main/java/io/smallrye/openapi/runtime/io/Names.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,35 @@ public static DotName containerOf(DotName repeatable) {
return repeatContainers.get(repeatable);
}

/**
* Create componentized {@link DotName} instances for the given collection of
* names. The results will be returned in a map, keyed by the input element from
* which each entry was derived.
*/
public static Map<String, DotName> componentize(Collection<String> names) {
Map<DotName, DotName> workingSet = new HashMap<>();
Map<String, DotName> results = new HashMap<>();

for (String name : names) {
String[] elements = name.split("\\.");
DotName current = null;

for (String element : elements) {
current = DotName.createComponentized(current, element);

if (workingSet.containsKey(current)) {
current = workingSet.get(current);
} else {
workingSet.put(current, current);
}
}

results.put(name, current);
}

return results;
}

public static final DotName OPENAPI_DEFINITION = createIndexable(OpenAPIDefinition.class);
public static final DotName API_RESPONSE = createIndexable(APIResponse.class);
public static final DotName API_RESPONSES = createIndexable(APIResponses.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import io.smallrye.openapi.runtime.scanner.dataobject.AnnotationTargetProcessor;
import io.smallrye.openapi.runtime.scanner.dataobject.AugmentedIndexView;
import io.smallrye.openapi.runtime.scanner.dataobject.DataObjectDeque;
import io.smallrye.openapi.runtime.scanner.dataobject.DataObjectDeque.PathEntry;
import io.smallrye.openapi.runtime.scanner.dataobject.IgnoreResolver;
import io.smallrye.openapi.runtime.scanner.dataobject.TypeResolver;
import io.smallrye.openapi.runtime.scanner.spi.AnnotationScannerContext;
Expand Down Expand Up @@ -281,14 +282,7 @@ private void depthFirstGraphSearch() {
reference);

processClassAnnotations(currentSchema, currentClass);

// Handle fields
properties.values()
.stream()
.filter(resolver -> !resolver.isIgnored())
.forEach(resolver -> AnnotationTargetProcessor.process(context, objectStack, resolver,
currentPathEntry));

processProperties(currentPathEntry, properties);
processInheritance(currentPathEntry);
}
}
Expand Down Expand Up @@ -327,6 +321,14 @@ private void processClassAnnotations(Schema schema, ClassInfo classInfo) {
}
}

private void processProperties(PathEntry currentPathEntry, Map<String, TypeResolver> properties) {
for (TypeResolver resolver : properties.values()) {
if (!resolver.isIgnored()) {
AnnotationTargetProcessor.process(context, objectStack, resolver, currentPathEntry);
}
}
}

private void processInheritance(DataObjectDeque.PathEntry currentPathEntry) {
ClassInfo currentClass = currentPathEntry.getClazz();
Schema currentSchema = currentPathEntry.getSchema();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,36 +111,33 @@ public Map<ClassInfo, MethodInfo> ancestry(MethodInfo method) {
Map<ClassInfo, MethodInfo> ancestry = new LinkedHashMap<>();

for (ClassInfo classInfo : chain.keySet()) {
ancestry.put(classInfo, null);

classInfo.methods()
.stream()
.filter(m -> !m.isSynthetic())
.filter(m -> isSameSignature(method, m))
.findFirst()
.ifPresent(m -> ancestry.put(classInfo, m));

interfaces(classInfo)
.stream()
.filter(type -> !TypeUtil.knownJavaType(type.name()))
.map(this::getClass)
.filter(Objects::nonNull)
.map(iface -> {
if (!saveOverride(method, classInfo, ancestry)) {
ancestry.put(classInfo, null);
}

for (Type ifaceType : interfaces(classInfo)) {
if (!TypeUtil.knownJavaType(ifaceType.name())) {
ClassInfo iface = getClass(ifaceType);

if (!saveOverride(method, iface, ancestry)) {
ancestry.put(iface, null);
return iface;
})
.flatMap(iface -> iface.methods().stream())
.filter(m -> isSameSignature(method, m))
.forEach(m -> ancestry.put(m.declaringClass(), m));
}
}
}
}

return ancestry;
}

private static boolean isSameSignature(MethodInfo m1, MethodInfo m2) {
return Objects.equals(m1.name(), m2.name())
&& m1.parametersCount() == m2.parametersCount()
&& Objects.equals(m1.parameterTypes(), m2.parameterTypes());
private static boolean saveOverride(MethodInfo searchMethod, ClassInfo clazz, Map<ClassInfo, MethodInfo> results) {
MethodInfo classMethod = clazz.method(searchMethod);

if (classMethod != null && !classMethod.isSynthetic()) {
results.put(clazz, classMethod);
return true;
}

return false;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -539,49 +539,23 @@ public static Map<String, TypeResolver> getAllFields(AnnotationScannerContext co
Map<ClassInfo, Type> chain = index.inheritanceChain(leafKlazz, leaf);
Map<String, TypeResolver> properties = new LinkedHashMap<>();
Deque<Map<String, Type>> stack = new ArrayDeque<>();
boolean skipPropertyScan = false;
boolean skipScan = false;
List<ClassInfo> descendants = new ArrayList<>(chain.size());

for (Map.Entry<ClassInfo, Type> entry : chain.entrySet()) {
ClassInfo currentClass = entry.getKey();
Type currentType = entry.getValue();
maybeAddResolutionParams(stack, currentType, currentClass);

if (skipPropertyScan || (!currentType.equals(leaf) && TypeUtil.isAllOf(context, leafKlazz, currentType))
|| TypeUtil.knownJavaType(currentClass.name())) {
/*
* Do not attempt to introspect fields of Java/JDK types or if the @Schema
* annotation indicates the use of a `ref` for superclass fields.
*/
skipPropertyScan = true;
skipScan = skipCheck(skipScan, context, leaf, leafKlazz, currentType, currentClass);

if (skipScan) {
continue;
}

// Store all field properties
JandexUtil.fields(context, currentClass)
.stream()
.filter(TypeResolver::acceptField)
.filter(field -> field.name().chars().allMatch(Character::isJavaIdentifierPart))
.forEach(field -> scanField(context, properties, field, stack, reference, descendants));

methods(context, currentClass)
.stream()
.filter(TypeResolver::acceptMethod)
.filter(method -> method.name().chars().allMatch(Character::isJavaIdentifierPart))
.forEach(method -> scanMethod(context, properties, method, stack, reference, descendants));

index.interfaces(currentClass)
.stream()
.filter(type -> !TypeUtil.knownJavaType(type.name()))
.map(type -> {
ClassInfo clazz = index.getClass(type);
maybeAddResolutionParams(stack, type, clazz);
return clazz;
})
.filter(Objects::nonNull)
.flatMap(clazz -> methods(context, clazz).stream())
.filter(method -> method.name().chars().allMatch(Character::isJavaIdentifierPart))
.forEach(method -> scanMethod(context, properties, method, stack, reference, descendants));
maybeAddResolutionParams(stack, currentType, currentClass);
scanFields(context, currentClass, properties, stack, reference, descendants);
scanMethods(context, currentClass, properties, stack, reference, descendants);
scanInterfaces(context, currentClass, properties, stack, reference, descendants);

descendants.add(currentClass);
}
Expand All @@ -605,6 +579,63 @@ private static void maybeAddResolutionParams(Deque<Map<String, Type>> stack, Typ
}
}

private static boolean skipCheck(boolean skip, AnnotationScannerContext context, Type leafType,
ClassInfo leafKlazz,
Type currentType,
ClassInfo currentClass) {
if (skip || (!currentType.equals(leafType) && TypeUtil.isAllOf(context, leafKlazz, currentType))
|| TypeUtil.knownJavaType(currentClass.name())) {
/*
* Do not attempt to introspect fields of Java/JDK types or if the @Schema
* annotation indicates the use of a `ref` for superclass fields.
*/
skip = true;
}

return skip;
}

private static void scanFields(AnnotationScannerContext context, ClassInfo currentClass,
Map<String, TypeResolver> properties, Deque<Map<String, Type>> stack, AnnotationTarget reference,
List<ClassInfo> descendants) {
for (FieldInfo field : JandexUtil.fields(context, currentClass)) {
if (acceptField(field) && field.name().chars().allMatch(Character::isJavaIdentifierPart)) {
scanField(context, properties, field, stack, reference, descendants);
}
}
}

private static void scanMethods(AnnotationScannerContext context, ClassInfo currentClass,
Map<String, TypeResolver> properties, Deque<Map<String, Type>> stack, AnnotationTarget reference,
List<ClassInfo> descendants) {
for (MethodInfo method : methods(context, currentClass)) {
if (acceptMethod(method) && method.name().chars().allMatch(Character::isJavaIdentifierPart)) {
scanMethod(context, properties, method, stack, reference, descendants);
}
}
}

private static void scanInterfaces(AnnotationScannerContext context, ClassInfo currentClass,
Map<String, TypeResolver> properties, Deque<Map<String, Type>> stack, AnnotationTarget reference,
List<ClassInfo> descendants) {
AugmentedIndexView index = context.getAugmentedIndex();

for (Type type : index.interfaces(currentClass)) {
if (!TypeUtil.knownJavaType(type.name())) {
ClassInfo clazz = index.getClass(type);
maybeAddResolutionParams(stack, type, clazz);

if (clazz != null) {
for (MethodInfo method : methods(context, clazz)) {
if (method.name().chars().allMatch(Character::isJavaIdentifierPart)) {
scanMethod(context, properties, method, stack, reference, descendants);
}
}
}
}
}
}

private static List<MethodInfo> methods(AnnotationScannerContext context, ClassInfo currentClass) {
if (context.getConfig().sortedPropertiesEnable()) {
return currentClass.methods();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -78,7 +77,6 @@ public abstract class AbstractParameterProcessor {
protected final AnnotationScannerContext scannerContext;
protected final String contextPath;
protected final IndexView index;
protected final Function<AnnotationInstance, Parameter> readerFunction;
protected final Optional<BeanValidationScanner> beanValidationScanner;
protected final ClassInfo resourceClass;
protected final MethodInfo resourceMethod;
Expand Down Expand Up @@ -114,13 +112,11 @@ public abstract class AbstractParameterProcessor {

protected AbstractParameterProcessor(AnnotationScannerContext scannerContext,
String contextPath,
Function<AnnotationInstance, Parameter> reader,
ClassInfo resourceClass,
MethodInfo resourceMethod) {
this.scannerContext = scannerContext;
this.contextPath = contextPath;
this.index = scannerContext.getIndex();
this.readerFunction = reader;
this.beanValidationScanner = scannerContext.getBeanValidationScanner();
this.resourceClass = resourceClass;
this.resourceMethod = resourceMethod;
Expand Down Expand Up @@ -300,7 +296,7 @@ protected void reset() {
matrixParams.clear();
}

protected ResourceParameters process() {
public ResourceParameters process() {

ResourceParameters parameters = new ResourceParameters();

Expand Down Expand Up @@ -397,6 +393,10 @@ protected void processFinalize(ClassInfo resourceClass, MethodInfo resourceMetho
parameters.setFormBodyContent(getFormBodyContent());
}

public void updateFormBodyContent(ResourceParameters parameters) {
parameters.setFormBodyContent(getFormBodyContent());
}

/**
* Generate the paths for the provided annotation target, either a class or a method.
* Add the name of any discovered matrix parameters.
Expand Down Expand Up @@ -1265,11 +1265,11 @@ List<String> methodPaths(MethodInfo method) {
protected abstract List<String> pathsOf(AnnotationTarget target);

protected boolean isReadableParameterAnnotation(DotName name) {
return Names.PARAMETER.equals(name) && readerFunction != null;
return Names.PARAMETER.equals(name);
}

protected void readParameterAnnotation(AnnotationInstance annotation, boolean overriddenParametersOnly) {
Parameter oaiParam = readerFunction.apply(annotation);
Parameter oaiParam = scannerContext.io().parameterIO().read(annotation);

if (oaiParam.getRef() != null) {
Parameter commonParam = ModelUtil.dereference(scannerContext.getOpenApi(), oaiParam);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public interface AnnotationScanner {

public boolean isDeleteMethod(final MethodInfo method);

public boolean containsScannerAnnotations(List<AnnotationInstance> instances,
public boolean containsScannerAnnotations(Collection<AnnotationInstance> instances,
List<AnnotationScannerExtension> extensions);

// Allow runtimes to set the context root path
Expand Down Expand Up @@ -977,7 +977,7 @@ default Type getRequestBodyParameterClassType(final AnnotationScannerContext con
.filter(position -> !isFrameworkContextType(methodParams.get(position)))
.filter(position -> !isPathParameter(context, method.parameterName(position), params))
.filter(position -> {
List<AnnotationInstance> annotations = context.annotations().getMethodParameterAnnotations(method,
Collection<AnnotationInstance> annotations = context.annotations().getMethodParameterAnnotations(method,
position);
return annotations.isEmpty() || !containsScannerAnnotations(annotations, context.getExtensions());
})
Expand All @@ -988,7 +988,7 @@ default Type getRequestBodyParameterClassType(final AnnotationScannerContext con

default void setRequestBodyConstraints(AnnotationScannerContext context, RequestBody requestBody, MethodInfo method,
Type requestBodyType) {
List<AnnotationInstance> paramAnnotations = context.annotations().getMethodParameterAnnotations(method,
Collection<AnnotationInstance> paramAnnotations = context.annotations().getMethodParameterAnnotations(method,
requestBodyType);
Optional<BeanValidationScanner> constraintScanner = context.getBeanValidationScanner();

Expand Down
Loading