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

FISH-161 OpenAPI Class Data Reading using HK2 Class Model API #4758

Merged
merged 10 commits into from
Jul 6, 2020
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) [2018] Payara Foundation and/or its affiliates. All rights reserved.
* Copyright (c) [2018-2020] Payara Foundation and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
Expand Down Expand Up @@ -39,9 +39,8 @@
*/
package fish.payara.microprofile.openapi.api.processor;

import org.eclipse.microprofile.openapi.models.OpenAPI;

import fish.payara.microprofile.openapi.impl.config.OpenApiConfiguration;
import org.eclipse.microprofile.openapi.models.OpenAPI;

/**
* A processor accepts an {@link OpenAPI} object, and returns a new model after
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) [2018] Payara Foundation and/or its affiliates. All rights reserved.
* Copyright (c) [2018-2020] Payara Foundation and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
Expand Down Expand Up @@ -41,6 +41,7 @@

import org.eclipse.microprofile.openapi.models.OpenAPI;
import org.eclipse.microprofile.openapi.models.Operation;
import org.glassfish.hk2.classmodel.reflect.Type;

/**
* The context in which a class object is being visited. For example, if a
Expand All @@ -67,7 +68,19 @@ public interface ApiContext {

/**
* @param type any class, not null
* @return true, if the give type is a known type in this context, else false
* @return true, if the give type is a known type in this context, else
* false
*/
boolean isApplicationType(Class<?> type);
}
boolean isApplicationType(String type);

/**
* @param type any class, not null
* @return type, if the give type is a known type in this context, else null
*/
Type getType(String type);
jbee marked this conversation as resolved.
Show resolved Hide resolved

/**
* @return the application class loader
*/
ClassLoader getApplicationClassLoader();
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) [2018] Payara Foundation and/or its affiliates. All rights reserved.
* Copyright (c) [2018-2020] Payara Foundation and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
Expand Down Expand Up @@ -39,131 +39,94 @@
*/
package fish.payara.microprofile.openapi.api.visitor;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;

import javax.ws.rs.Consumes;
import javax.ws.rs.CookieParam;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.PATCH;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;

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.callbacks.Callback;
import org.eclipse.microprofile.openapi.annotations.callbacks.Callbacks;
import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
import org.eclipse.microprofile.openapi.annotations.extensions.Extensions;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameters;
import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement;
import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirements;
import org.eclipse.microprofile.openapi.annotations.security.SecurityScheme;
import org.eclipse.microprofile.openapi.annotations.security.SecuritySchemes;
import org.eclipse.microprofile.openapi.annotations.servers.Server;
import org.eclipse.microprofile.openapi.annotations.servers.Servers;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.eclipse.microprofile.openapi.annotations.tags.Tags;
import org.glassfish.hk2.classmodel.reflect.AnnotatedElement;
import org.glassfish.hk2.classmodel.reflect.AnnotationModel;
import org.glassfish.hk2.classmodel.reflect.MethodModel;

public interface ApiVisitor {

/**
* Generic representation of each of these functions.
*/
@FunctionalInterface
interface VisitorFunction<A extends Annotation, E extends AnnotatedElement> {
void apply(A annotation, E element, ApiContext context);
interface VisitorFunction<AnnotationModel, E extends AnnotatedElement> {
void apply(AnnotationModel annotation, E element, ApiContext context);
}

// JAX-RS annotations

void visitGET(GET get, Method element, ApiContext context);
void visitGET(AnnotationModel get, MethodModel element, ApiContext context);

void visitPOST(POST post, Method element, ApiContext context);
void visitPOST(AnnotationModel post, MethodModel element, ApiContext context);

void visitPUT(PUT put, Method element, ApiContext context);
void visitPUT(AnnotationModel put, MethodModel element, ApiContext context);

void visitDELETE(DELETE delete, Method element, ApiContext context);
void visitDELETE(AnnotationModel delete, MethodModel element, ApiContext context);

void visitHEAD(HEAD head, Method element, ApiContext context);
void visitHEAD(AnnotationModel head, MethodModel element, ApiContext context);

void visitOPTIONS(OPTIONS options, Method element, ApiContext context);
void visitOPTIONS(AnnotationModel options, MethodModel element, ApiContext context);

void visitPATCH(PATCH patch, Method element, ApiContext context);
void visitPATCH(AnnotationModel patch, MethodModel element, ApiContext context);

void visitProduces(Produces produces, AnnotatedElement element, ApiContext context);
void visitProduces(AnnotationModel produces, AnnotatedElement element, ApiContext context);

void visitConsumes(Consumes produces, AnnotatedElement element, ApiContext context);
void visitConsumes(AnnotationModel produces, AnnotatedElement element, ApiContext context);

void visitQueryParam(QueryParam param, AnnotatedElement element, ApiContext context);
void visitQueryParam(AnnotationModel param, AnnotatedElement element, ApiContext context);

void visitPathParam(PathParam param, AnnotatedElement element, ApiContext context);
void visitPathParam(AnnotationModel param, AnnotatedElement element, ApiContext context);

void visitFormParam(FormParam param, AnnotatedElement element, ApiContext context);
void visitFormParam(AnnotationModel param, AnnotatedElement element, ApiContext context);

void visitHeaderParam(HeaderParam param, AnnotatedElement element, ApiContext context);
void visitHeaderParam(AnnotationModel param, AnnotatedElement element, ApiContext context);

void visitCookieParam(CookieParam param, AnnotatedElement element, ApiContext context);
void visitCookieParam(AnnotationModel param, AnnotatedElement element, ApiContext context);

// OpenAPI annotations

void visitOpenAPI(OpenAPIDefinition definition, AnnotatedElement element, ApiContext context);
void visitOpenAPI(AnnotationModel definition, AnnotatedElement element, ApiContext context);

void visitSchema(Schema schema, AnnotatedElement element, ApiContext context);
void visitSchema(AnnotationModel schema, AnnotatedElement element, ApiContext context);

void visitExtension(Extension extension, AnnotatedElement element, ApiContext context);
void visitExtension(AnnotationModel extension, AnnotatedElement element, ApiContext context);

void visitExtensions(Extensions extensions, AnnotatedElement element, ApiContext context);
void visitExtensions(AnnotationModel extensions, AnnotatedElement element, ApiContext context);

void visitOperation(Operation operation, AnnotatedElement element, ApiContext context);
void visitOperation(AnnotationModel operation, AnnotatedElement element, ApiContext context);

void visitCallback(Callback callback, AnnotatedElement element, ApiContext context);
void visitCallback(AnnotationModel callback, AnnotatedElement element, ApiContext context);

void visitCallbacks(Callbacks callbacks, AnnotatedElement element, ApiContext context);
void visitCallbacks(AnnotationModel callbacks, AnnotatedElement element, ApiContext context);

void visitRequestBody(RequestBody requestBody, AnnotatedElement element, ApiContext context);
void visitRequestBody(AnnotationModel requestBody, AnnotatedElement element, ApiContext context);

void visitAPIResponse(APIResponse apiResponse, AnnotatedElement element, ApiContext context);
void visitAPIResponse(AnnotationModel apiResponse, AnnotatedElement element, ApiContext context);

void visitAPIResponses(APIResponses apiResponses, AnnotatedElement element, ApiContext context);
void visitAPIResponses(AnnotationModel apiResponses, AnnotatedElement element, ApiContext context);

void visitParameter(Parameter parameter, AnnotatedElement element, ApiContext context);
void visitParameter(AnnotationModel parameter, AnnotatedElement element, ApiContext context);

void visitParameters(Parameters parameters, AnnotatedElement element, ApiContext context);
void visitParameters(AnnotationModel parameters, AnnotatedElement element, ApiContext context);

void visitExternalDocumentation(ExternalDocumentation externalDocs, AnnotatedElement element, ApiContext context);
void visitExternalDocumentation(AnnotationModel externalDocs, AnnotatedElement element, ApiContext context);

void visitServer(Server server, AnnotatedElement element, ApiContext context);
void visitServer(AnnotationModel server, AnnotatedElement element, ApiContext context);

void visitServers(Servers servers, AnnotatedElement element, ApiContext context);
void visitServers(AnnotationModel servers, AnnotatedElement element, ApiContext context);

void visitTag(Tag tag, AnnotatedElement element, ApiContext context);
void visitTag(AnnotationModel tag, AnnotatedElement element, ApiContext context);

void visitTags(Tags tags, AnnotatedElement element, ApiContext context);
void visitTags(AnnotationModel tags, AnnotatedElement element, ApiContext context);

void visitSecurityScheme(SecurityScheme securityScheme, AnnotatedElement element, ApiContext context);
void visitSecurityScheme(AnnotationModel securityScheme, AnnotatedElement element, ApiContext context);

void visitSecuritySchemes(SecuritySchemes securitySchemes, AnnotatedElement element, ApiContext context);
void visitSecuritySchemes(AnnotationModel securitySchemes, AnnotatedElement element, ApiContext context);

void visitSecurityRequirement(SecurityRequirement securityRequirement, AnnotatedElement element,
void visitSecurityRequirement(AnnotationModel securityRequirement, AnnotatedElement element,
ApiContext context);

void visitSecurityRequirements(SecurityRequirements securityRequirements, AnnotatedElement element,
void visitSecurityRequirements(AnnotationModel securityRequirements, AnnotatedElement element,
ApiContext context);

}
Original file line number Diff line number Diff line change
Expand Up @@ -218,44 +218,6 @@ private static String getContextRoot(ApplicationInfo appInfo) {
return appInfo.getMetaData(WebBundleDescriptorImpl.class).getContextRoot();
}

/**
* @param archive the archive to read from.
* @param appClassLoader the classloader to use to load the classes.
* @return a list of all loadable classes in the archive.
*/
private static Set<Class<?>> getClassesFromArchive(ReadableArchive archive, ClassLoader appClassLoader) {
return Collections.list(archive.entries()).stream()
// Only use the classes
.filter(x -> x.endsWith(".class"))
// Remove the WEB-INF/classes and return the proper class name format
.map(x -> x.replaceAll("WEB-INF/classes/", "").replace("/", ".").replace(".class", ""))
// Attempt to load the classes
.map(x -> {
Class<?> loadedClass = null;
// Attempt to load the class, ignoring any errors
try {
loadedClass = appClassLoader.loadClass(x);
} catch (Throwable t) {
}
try {
loadedClass = Class.forName(x);
} catch (Throwable t) {
}
// If the class can be loaded, check that everything in the class also can
if (loadedClass != null) {
try {
loadedClass.getDeclaredFields();
loadedClass.getDeclaredMethods();
} catch (Throwable t) {
return null;
}
}
return loadedClass;
})
// Don't return null classes
.filter(x -> x != null).collect(toSet());
}

private class OpenApiMapping {

private final ApplicationInfo appInfo;
Expand Down Expand Up @@ -284,12 +246,10 @@ private OpenAPI buildDocument() throws OpenAPIBuildException {
try {
String contextRoot = getContextRoot(appInfo);
List<URL> baseURLs = getServerURL(contextRoot);
ReadableArchive archive = appInfo.getSource();
Set<Class<?>> classes = getClassesFromArchive(archive, appInfo.getAppClassLoader());

openapi = new ModelReaderProcessor().process(openapi, appConfig);
openapi = new FileProcessor(appInfo.getAppClassLoader()).process(openapi, appConfig);
openapi = new ApplicationProcessor(classes).process(openapi, appConfig);
openapi = new ApplicationProcessor(appInfo).process(openapi, appConfig);
openapi = new BaseProcessor(baseURLs).process(openapi, appConfig);
openapi = new FilterProcessor().process(openapi, appConfig);
} catch (Throwable t) {
Expand Down
Loading