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

Read PathItem and PathItemOperation annotations #1869

Merged
merged 1 commit into from
Jun 10, 2024
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 @@ -46,7 +46,7 @@ public String getRef() {
@Override
public void setRef(String ref) {
if (ref != null && !ref.contains("/")) {
ref = ReferenceType.PATH_ITEMS.referenceOf(ref);
ref = ReferenceType.PATH_ITEM.referenceOf(ref);
}
this.ref = ref;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public Components read(AnnotationInstance annotation) {
components.setHeaders(headerIO().readMap(annotation.value(PROP_HEADERS)));
components.setLinks(linkIO().readMap(annotation.value(PROP_LINKS)));
components.setParameters(parameterIO().readMap(annotation.value(PROP_PARAMETERS)));
components.setPathItems(pathItemIO().readMap(annotation.value(PROP_PATH_ITEMS)));
components.setRequestBodies(requestBodyIO().readMap(annotation.value(PROP_REQUEST_BODIES)));
components.setResponses(apiResponseIO().readMap(annotation.value(PROP_RESPONSES)));
components.setSchemas(schemaIO().readMap(annotation.value(PROP_SCHEMAS)));
Expand Down
12 changes: 6 additions & 6 deletions core/src/main/java/io/smallrye/openapi/runtime/io/IOContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ public class IOContext<V, A extends V, O extends V, AB, OB> {
private OpenAPIDefinitionIO<V, A, O, AB, OB> openApiDefinitionIO = new OpenAPIDefinitionIO<>(this);
private OperationIO<V, A, O, AB, OB> operationIO = new OperationIO<>(this);
private CallbackOperationIO<V, A, O, AB, OB> callbackOperationIO = new CallbackOperationIO<>(this);
private PathItemIO<V, A, O, AB, OB> pathItemIO = new PathItemIO<>(this, operationIO);
private PathItemIO<V, A, O, AB, OB> pathItemCallbackIO = new PathItemIO<>(this, callbackOperationIO);
private PathItemOperationIO<V, A, O, AB, OB> pathItemOperationIO = new PathItemOperationIO<>(this);
private PathItemIO<V, A, O, AB, OB> pathItemIO = new PathItemIO<>(this);
private PathsIO<V, A, O, AB, OB> pathsIO = new PathsIO<>(this);
private CallbackIO<V, A, O, AB, OB> callbackIO = new CallbackIO<>(this);
private ExtensionIO<V, A, O, AB, OB> extensionIO = new ExtensionIO<>(this);
Expand Down Expand Up @@ -122,12 +122,12 @@ public OperationIO<V, A, O, AB, OB> operationIO() {
return operationIO;
}

public PathItemIO<V, A, O, AB, OB> pathItemIO() {
return pathItemIO;
public PathItemOperationIO<V, A, O, AB, OB> pathItemOperationIO() {
return pathItemOperationIO;
}

public PathItemIO<V, A, O, AB, OB> pathItemCallbackIO() {
return pathItemCallbackIO;
public PathItemIO<V, A, O, AB, OB> pathItemIO() {
return pathItemIO;
}

public PathsIO<V, A, O, AB, OB> pathsIO() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,12 @@ public OperationIO<V, A, O, AB, OB> operationIO() {
return context.operationIO();
}

public PathItemIO<V, A, O, AB, OB> pathItemIO() {
return context.pathItemIO();
public PathItemOperationIO<V, A, O, AB, OB> pathItemOperationIO() {
return context.pathItemOperationIO();
}

public PathItemIO<V, A, O, AB, OB> pathItemCallbackIO() {
return context.pathItemCallbackIO();
public PathItemIO<V, A, O, AB, OB> pathItemIO() {
return context.pathItemIO();
}

public PathsIO<V, A, O, AB, OB> pathsIO() {
Expand Down
4 changes: 4 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 @@ -7,6 +7,8 @@
import org.eclipse.microprofile.openapi.annotations.ExternalDocumentation;
import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.PathItem;
import org.eclipse.microprofile.openapi.annotations.PathItemOperation;
import org.eclipse.microprofile.openapi.annotations.callbacks.Callback;
import org.eclipse.microprofile.openapi.annotations.callbacks.CallbackOperation;
import org.eclipse.microprofile.openapi.annotations.callbacks.Callbacks;
Expand Down Expand Up @@ -88,6 +90,8 @@ public static DotName containerOf(DotName repeatable) {
public static final DotName OPERATION = create(Operation.class);
public static final DotName PARAMETER = create(Parameter.class);
public static final DotName PARAMETERS = create(Parameters.class);
public static final DotName PATH_ITEM = create(PathItem.class);
public static final DotName PATH_ITEM_OPERATION = create(PathItemOperation.class);
public static final DotName REQUEST_BODY = create(RequestBody.class);
public static final DotName REQUEST_BODY_SCHEMA = create(RequestBodySchema.class);
public static final DotName SCHEMA = create(Schema.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public OpenAPI read(AnnotationInstance annotation) {
openApi.setSecurity(
securityIO().readRequirements(annotation.value(PROP_SECURITY), annotation.value(PROP_SECURITY_SETS)));
openApi.setExternalDocs(extDocIO().read(annotation.value(PROP_EXTERNAL_DOCS)));
openApi.setWebhooks(pathItemIO().readMap(annotation.value(PROP_WEBHOOKS)));
openApi.setComponents(componentsIO().read(annotation.value(PROP_COMPONENTS)));
openApi.setExtensions(extensionIO().readExtensible(annotation));

Expand Down
47 changes: 37 additions & 10 deletions core/src/main/java/io/smallrye/openapi/runtime/io/PathItemIO.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
import java.util.Set;
import java.util.stream.Collectors;

import org.eclipse.microprofile.openapi.annotations.callbacks.CallbackOperation;
import org.eclipse.microprofile.openapi.models.Operation;
import org.eclipse.microprofile.openapi.models.PathItem;
import org.eclipse.microprofile.openapi.models.PathItem.HttpMethod;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationValue;

import io.smallrye.openapi.api.models.PathItemImpl;

Expand All @@ -27,21 +29,48 @@ public class PathItemIO<V, A extends V, O extends V, AB, OB> extends MapModelIO<
.map(String::toLowerCase)
.collect(Collectors.toSet());

private final OperationIO<V, A, O, AB, OB> operationIO;
// Annotation properties
private static final String PROP_OPERATIONS = "operations";

public PathItemIO(IOContext<V, A, O, AB, OB> context, OperationIO<V, A, O, AB, OB> operationIO) {
super(context, null, Names.create(PathItem.class));
this.operationIO = operationIO;
public PathItemIO(IOContext<V, A, O, AB, OB> context) {
super(context, Names.PATH_ITEM, Names.create(PathItem.class));
}

@Override
public PathItem read(AnnotationInstance annotation) {
throw new UnsupportedOperationException("@PathItem annotation does not exist");
IoLogging.logger.singleAnnotation("@PathItem");
PathItem pathItem = new PathItemImpl();

pathItem.setRef(ReferenceType.PATH_ITEM.refValue(annotation));
pathItem.setDescription(value(annotation, PROP_DESCRIPTION));
pathItem.setSummary(value(annotation, PROP_SUMMARY));
pathItem.setServers(serverIO().readList(annotation.value(PROP_SERVERS)));
pathItem.setParameters(parameterIO().readList(annotation.value(PROP_PARAMETERS)));

Optional.ofNullable(annotation.value(PROP_OPERATIONS))
.map(AnnotationValue::asNestedArray)
.ifPresent(annotations -> readOperationsInto(pathItem, annotations, pathItemOperationIO()));

pathItem.setExtensions(extensionIO().readExtensible(annotation));
return pathItem;
}

public PathItem read(AnnotationInstance[] annotations) {
/**
* Convert an array of {@link CallbackOperation} annotations into a {@code PathItem}.
*
* @param annotations the {@code CallbackOperation} annotation instances
* @return the path item
*/
public PathItem readCallbackOperations(AnnotationInstance[] annotations) {
PathItem pathItem = new PathItemImpl();

readOperationsInto(pathItem, annotations, callbackOperationIO());

return pathItem;
}

private void readOperationsInto(PathItem pathItem, AnnotationInstance[] annotations,
OperationIO<V, A, O, AB, OB> operationIO) {
Arrays.stream(annotations)
.filter(annotation -> Objects.nonNull(value(annotation, "method")))
.forEach(annotation -> {
Expand All @@ -50,8 +79,6 @@ public PathItem read(AnnotationInstance[] annotations) {
operation.setExtensions(extensionIO().readExtensible(annotation));
pathItem.setOperation(HttpMethod.valueOf(method.toUpperCase(Locale.ROOT)), operation);
});

return pathItem;
}

@Override
Expand All @@ -67,7 +94,7 @@ public PathItem readObject(O node) {
.filter(entry -> OPERATION_PROPS.contains(entry.getKey()))
.forEach(entry -> {
HttpMethod method = HttpMethod.valueOf(entry.getKey().toUpperCase(Locale.ROOT));
Operation operation = operationIO.readValue(entry.getValue());
Operation operation = operationIO().readValue(entry.getValue());
pathItem.setOperation(method, operation);
});

Expand All @@ -90,7 +117,7 @@ private OB write(PathItem model, OB node) {

model.getOperations()
.forEach(
(method, operation) -> setIfPresent(node, method.name().toLowerCase(), operationIO.write(operation)));
(method, operation) -> setIfPresent(node, method.name().toLowerCase(), operationIO().write(operation)));

setIfPresent(node, PROP_PARAMETERS, parameterIO().write(model.getParameters()));
setIfPresent(node, PROP_SERVERS, serverIO().write(model.getServers()));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package io.smallrye.openapi.runtime.io;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

import org.eclipse.microprofile.openapi.models.Operation;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationValue;

import io.smallrye.openapi.api.models.OperationImpl;
import io.smallrye.openapi.runtime.util.ModelUtil;

public class PathItemOperationIO<V, A extends V, O extends V, AB, OB> extends OperationIO<V, A, O, AB, OB> {

public PathItemOperationIO(IOContext<V, A, O, AB, OB> context) {
super(context, Names.PATH_ITEM_OPERATION);
}

@Override
public Operation read(AnnotationInstance annotation) {
IoLogging.logger.singleAnnotation("@PathItemOperation");
Operation operation = new OperationImpl();

operation.setTags(processTags(annotation.value(PROP_TAGS)));
operation.setSummary(value(annotation, PROP_SUMMARY));
operation.setDescription(value(annotation, PROP_DESCRIPTION));
operation.setExternalDocs(extDocIO().read(annotation.value(PROP_EXTERNAL_DOCS)));
operation.setOperationId(value(annotation, PROP_OPERATION_ID));
operation.setParameters(parameterIO().readList(annotation.value(PROP_PARAMETERS)));
operation.setRequestBody(requestBodyIO().read(annotation.value(PROP_REQUEST_BODY)));
operation.setResponses(apiResponsesIO().read(annotation.value(PROP_RESPONSES)));
operation.setCallbacks(callbackIO().readMap(annotation.value(PROP_CALLBACKS)));
operation.setDeprecated(value(annotation, PROP_DEPRECATED));
operation.setSecurity(securityIO().readRequirements(
annotation.value(PROP_SECURITY),
annotation.value(PROP_SECURITY_SETS)));
operation.setServers(serverIO().readList(annotation.value(PROP_SERVERS)));
operation.setExtensions(extensionIO().readExtensible(annotation));

return operation;
}

private List<String> processTags(AnnotationValue tagAnnotations) {
return Optional.ofNullable(tagAnnotations)
.map(AnnotationValue::asNestedArray)
.map(this::processTags)
.orElse(null);
}

/**
* Read an array of {@code Tag} annotations, collecting the names and adding any new definitions to the top-level OpenAPI
* object.
*
* @param tagAnnotations the annotations
* @return the list of tag names
*/
private List<String> processTags(AnnotationInstance[] tagAnnotations) {
Set<String> tagNames = new LinkedHashSet<>();

tagIO().readList(tagAnnotations)
.stream()
.filter(tag -> Objects.nonNull(tag.getName()))
.forEach(tag -> {
tagNames.add(tag.getName());
ModelUtil.addTag(scannerContext().getOpenApi(), tag);
});

tagIO().readReferences(tagAnnotations).forEach(tagNames::add);

return new ArrayList<>(tagNames);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public enum ReferenceType {
PARAMETER("parameters"),
EXAMPLE("examples"),
REQUEST_BODY("requestBodies"),
PATH_ITEMS("pathItems");
PATH_ITEM("pathItems");

private static final Pattern COMPONENT_KEY_PATTERN = Pattern.compile("^[a-zA-Z0-9\\.\\-_]+$");
public static final String PROP_ANNOTATION = "ref";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.DotName;

import io.smallrye.openapi.api.models.PathItemImpl;
import io.smallrye.openapi.api.models.callbacks.CallbackImpl;
import io.smallrye.openapi.runtime.io.IOContext;
import io.smallrye.openapi.runtime.io.IoLogging;
Expand All @@ -20,6 +21,7 @@ public class CallbackIO<V, A extends V, O extends V, AB, OB> extends MapModelIO<

private static final String PROP_OPERATIONS = "operations";
private static final String PROP_CALLBACK_URL_EXPRESSION = "callbackUrlExpression";
private static final String PROP_PATH_ITEM_REF = "pathItemRef";

public CallbackIO(IOContext<V, A, O, AB, OB> context) {
super(context, Names.CALLBACK, DotName.createSimple(Callback.class));
Expand All @@ -31,9 +33,15 @@ public Callback read(AnnotationInstance annotation) {
Callback callback = new CallbackImpl();
callback.setRef(ReferenceType.CALLBACK.refValue(annotation));

Optional.ofNullable(this.<String> value(annotation, PROP_PATH_ITEM_REF))
.map(ReferenceType.PATH_ITEM::referenceOf)
.ifPresent(ref -> callback.addPathItem(
value(annotation, PROP_CALLBACK_URL_EXPRESSION),
new PathItemImpl().ref(ref)));

Optional.ofNullable(value(annotation, PROP_OPERATIONS))
.map(AnnotationInstance[].class::cast)
.map(pathItemCallbackIO()::read)
.map(pathItemIO()::readCallbackOperations)
.ifPresent(pathItem -> callback.addPathItem(
value(annotation, PROP_CALLBACK_URL_EXPRESSION),
pathItem));
Expand All @@ -53,7 +61,7 @@ public Callback readObject(O node) {
.filter(not(ExtensionIO::isExtension))
.filter(not(this::isReference))
.filter(property -> jsonIO().isObject(property.getValue()))
.map(property -> entry(property.getKey(), pathItemCallbackIO().readValue(property.getValue())))
.map(property -> entry(property.getKey(), pathItemIO().readValue(property.getValue())))
.forEach(pathItem -> callback.addPathItem(pathItem.getKey(), pathItem.getValue()));

extensionIO().readMap(node).forEach(callback::addExtension);
Expand All @@ -69,7 +77,7 @@ public Optional<O> write(Callback model) {
} else {
Optional.ofNullable(model.getPathItems())
.ifPresent(items -> items
.forEach((key, value) -> setIfPresent(node, key, pathItemCallbackIO().write(value))));
.forEach((key, value) -> setIfPresent(node, key, pathItemIO().write(value))));

setAllIfPresent(node, extensionIO().write(model));
}
Expand Down
16 changes: 16 additions & 0 deletions core/src/main/java/io/smallrye/openapi/runtime/io/tags/TagIO.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.smallrye.openapi.runtime.io.tags;

import static java.util.stream.Collectors.toList;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
Expand Down Expand Up @@ -47,6 +49,20 @@ public List<String> readReferences(AnnotationTarget target) {
return Stream.concat(tagsRefs, tagRefs).collect(Collectors.toList());
}

public List<String> readReferences(AnnotationInstance[] annotations) {
return Optional.ofNullable(annotations)
.map(Arrays::asList)
.map(this::readReferences)
.orElse(null);
}

public List<String> readReferences(Collection<AnnotationInstance> annotations) {
return annotations.stream()
.map(a -> this.<String> value(a, PROP_REF))
.filter(Objects::nonNull)
.collect(toList());
}

public List<Tag> readList(AnnotationTarget target) {
return readList(getRepeatableAnnotations(target));
}
Expand Down
Loading