Skip to content

Commit

Permalink
Support for readers and filters to access the Jandex index
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Edgar <[email protected]>
  • Loading branch information
MikeEdgar committed May 17, 2023
1 parent 03ddf6e commit 5b7a92f
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.io.UncheckedIOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.eclipse.microprofile.openapi.OASFilter;
import org.eclipse.microprofile.openapi.OASModelReader;
import org.eclipse.microprofile.openapi.models.OpenAPI;
import org.jboss.jandex.Index;
import org.jboss.jandex.IndexView;

import io.smallrye.openapi.api.OpenApiConfig;
Expand Down Expand Up @@ -71,8 +76,8 @@ public static OpenAPI bootstrap(OpenApiConfig config, IndexView index, ClassLoad
}
// Filter and model
if (config != null && classLoader != null) {
OpenApiDocument.INSTANCE.modelFromReader(modelFromReader(config, classLoader));
OpenApiDocument.INSTANCE.filter(getFilter(config, classLoader));
OpenApiDocument.INSTANCE.modelFromReader(modelFromReader(config, classLoader, index));
OpenApiDocument.INSTANCE.filter(getFilter(config, classLoader, index));
}

OpenApiDocument.INSTANCE.initialize();
Expand Down Expand Up @@ -169,39 +174,88 @@ public static OpenAPI modelFromAnnotations(OpenApiConfig config, ClassLoader loa
* @param config OpenApiConfig
* @param loader ClassLoader
* @return OpenApiImpl created from OASModelReader
*
* @deprecated use {@linkplain #modelFromReader(OpenApiConfig, ClassLoader, IndexView)} instead
*/
@Deprecated
public static OpenAPI modelFromReader(OpenApiConfig config, ClassLoader loader) {
String readerClassName = config.modelReader();
if (readerClassName == null) {
return null;
}
try {
Class<?> c = loader.loadClass(readerClassName);
OASModelReader reader = (OASModelReader) c.getDeclaredConstructor().newInstance();
return reader.buildModel();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
throw new OpenApiRuntimeException(e);
return modelFromReader(config, loader, Index.of(Collections.emptyList()));
} catch (IOException e) {
// Not actually possible since the collection passed to `Index#of` is empty
throw new UncheckedIOException(e);
}
}

/**
* Instantiate the configured {@link OASModelReader} and invoke it. If no reader is configured,
* then return null. If a class is configured but there is an error either instantiating or invoking
* it, a {@link OpenApiRuntimeException} is thrown.
*
* @param config OpenApiConfig
* @param loader ClassLoader
* @param index an IndexView to be provided to the filter when accepted via its constructor
* @return OpenApiImpl created from OASModelReader
*/
public static OpenAPI modelFromReader(OpenApiConfig config, ClassLoader loader, IndexView index) {
OASModelReader reader = newInstance(config.modelReader(), loader, index);
return reader != null ? reader.buildModel() : null;
}

/**
* Instantiate the {@link OASFilter} configured by the app.
*
* @param config OpenApiConfig
* @param loader ClassLoader
* @return OASFilter instance retrieved from loader
*
* @deprecated use {@linkplain #getFilter(OpenApiConfig, ClassLoader, IndexView)} instead
*/
@Deprecated
public static OASFilter getFilter(OpenApiConfig config, ClassLoader loader) {
String filterClassName = config.filter();
if (filterClassName == null) {
try {
return getFilter(config, loader, Index.of(Collections.emptyList()));
} catch (IOException e) {
// Not actually possible since the collection passed to `Index#of` is empty
throw new UncheckedIOException(e);
}
}

/**
* Instantiate the {@link OASFilter} configured by the application.
*
* @param config OpenApiConfig
* @param loader ClassLoader
* @param index an IndexView to be provided to the filter when accepted via its constructor
* @return OASFilter instance retrieved from loader
*/
public static OASFilter getFilter(OpenApiConfig config, ClassLoader loader, IndexView index) {
return newInstance(config.filter(), loader, index);
}

@SuppressWarnings("unchecked")
static <T> T newInstance(String className, ClassLoader loader, IndexView index) {
if (className == null) {
return null;
}

Class<T> klazz = uncheckedCall(() -> (Class<T>) loader.loadClass(className));

return Arrays.stream(klazz.getDeclaredConstructors())
.filter(OpenApiProcessor::acceptsIndexView)
.findFirst()
.map(ctor -> uncheckedCall(() -> (T) ctor.newInstance(index)))
.orElseGet(() -> uncheckedCall(() -> klazz.getDeclaredConstructor().newInstance()));
}

private static boolean acceptsIndexView(Constructor<?> ctor) {
return ctor.getParameterCount() == 1 && IndexView.class.equals(ctor.getParameterTypes()[0]);
}

private static <T> T uncheckedCall(Callable<T> callable) {
try {
Class<?> c = loader.loadClass(filterClassName);
return (OASFilter) c.getDeclaredConstructor().newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
return callable.call();
} catch (Exception e) {
throw new OpenApiRuntimeException(e);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,23 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UncheckedIOException;
import java.util.Collection;
import java.util.Optional;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;

import org.apache.commons.io.output.ByteArrayOutputStream;
import org.eclipse.microprofile.config.ConfigProvider;
import org.eclipse.microprofile.openapi.models.OpenAPI;
import org.jboss.arquillian.container.spi.client.deployment.DeploymentDescription;
import org.jboss.arquillian.container.spi.event.container.BeforeDeploy;
import org.jboss.arquillian.core.api.annotation.Observes;
import org.jboss.jandex.DotName;
import org.jboss.jandex.Index;
import org.jboss.jandex.IndexWriter;
import org.jboss.jandex.Indexer;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ArchivePaths;
Expand Down Expand Up @@ -114,7 +117,7 @@ private static void generateOpenAPI(final WebArchive war) {
ClassLoader contextClassLoader = currentThread().getContextClassLoader();

Optional<OpenAPI> annotationModel = ofNullable(modelFromAnnotations(openApiConfig, contextClassLoader, index));
Optional<OpenAPI> readerModel = ofNullable(modelFromReader(openApiConfig, contextClassLoader));
Optional<OpenAPI> readerModel = ofNullable(modelFromReader(openApiConfig, contextClassLoader, index));
Optional<OpenAPI> staticFileModel = Stream.of(modelFromFile(openApiConfig, war, "/META-INF/openapi.json", JSON),
modelFromFile(openApiConfig, war, "/META-INF/openapi.yaml", YAML),
modelFromFile(openApiConfig, war, "/META-INF/openapi.yml", YAML))
Expand All @@ -128,7 +131,7 @@ private static void generateOpenAPI(final WebArchive war) {
annotationModel.ifPresent(document::modelFromAnnotations);
readerModel.ifPresent(document::modelFromReader);
staticFileModel.ifPresent(document::modelFromStaticFile);
document.filter(getFilter(openApiConfig, contextClassLoader));
document.filter(getFilter(openApiConfig, contextClassLoader, index));
document.initialize();
OpenAPI openAPI = document.get();

Expand All @@ -139,6 +142,13 @@ private static void generateOpenAPI(final WebArchive war) {
// Ignore
}

try (ByteArrayOutputStream indexOut = new ByteArrayOutputStream()) {
new IndexWriter(indexOut).write(index);
war.addAsManifestResource(new ByteArrayAsset(indexOut.toByteArray()), "jandex.idx");
} catch (IOException e) {
throw new UncheckedIOException(e);
}

document.reset();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static io.smallrye.openapi.runtime.io.Format.JSON;
import static io.smallrye.openapi.runtime.io.Format.YAML;

import java.io.InputStream;
import java.net.URL;
import java.util.Map;
import java.util.Optional;
Expand All @@ -17,6 +18,8 @@
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.eclipse.microprofile.openapi.models.OpenAPI;
import org.jboss.jandex.IndexReader;
import org.jboss.jandex.IndexView;
import org.jboss.resteasy.spi.ResteasyDeployment;

import io.smallrye.openapi.api.OpenApiConfig;
Expand Down Expand Up @@ -72,15 +75,21 @@ private Optional<OpenAPI> readOpenApiFile(final ServletContext servletContext, f
return Optional.empty();
}

final IndexView index;

try (InputStream indexStream = servletContext.getResourceAsStream("/META-INF/jandex.idx")) {
index = new IndexReader(indexStream).read();
}

final OpenApiDocument document = OpenApiDocument.INSTANCE;

try (OpenApiStaticFile staticFile = new OpenApiStaticFile(resource.openStream(), format)) {
Config config = ConfigProvider.getConfig();
OpenApiConfig openApiConfig = OpenApiConfig.fromConfig(config);
document.reset();
document.config(openApiConfig);
document.filter(OpenApiProcessor.getFilter(openApiConfig, Thread.currentThread().getContextClassLoader()));
document.modelFromStaticFile(
io.smallrye.openapi.runtime.OpenApiProcessor.modelFromStaticFile(openApiConfig, staticFile));
document.filter(OpenApiProcessor.getFilter(openApiConfig, Thread.currentThread().getContextClassLoader(), index));
document.modelFromStaticFile(OpenApiProcessor.modelFromStaticFile(openApiConfig, staticFile));
document.initialize();
return Optional.of(document.get());
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ private OpenApiDocument generateSchema(

OpenAPI staticModel = generateStaticModel(openApiConfig, resourcesSrcDirs);
OpenAPI annotationModel = generateAnnotationModel(index, openApiConfig, SmallryeOpenApiTask.class.getClassLoader());
OpenAPI readerModel = OpenApiProcessor.modelFromReader(openApiConfig, classLoader);
OpenAPI readerModel = OpenApiProcessor.modelFromReader(openApiConfig, classLoader, index);

OpenApiDocument document = OpenApiDocument.INSTANCE;

Expand All @@ -146,7 +146,7 @@ private OpenApiDocument generateSchema(
addingModelDebug("static", staticModel);
document.modelFromStaticFile(staticModel);
}
document.filter(OpenApiProcessor.getFilter(openApiConfig, classLoader));
document.filter(OpenApiProcessor.getFilter(openApiConfig, classLoader, index));
document.initialize();

return document;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ private OpenApiDocument generateSchema(IndexView index) throws IOException, Depe

OpenAPI staticModel = generateStaticModel(openApiConfig);
OpenAPI annotationModel = generateAnnotationModel(index, openApiConfig, classLoader);
OpenAPI readerModel = OpenApiProcessor.modelFromReader(openApiConfig, classLoader);
OpenAPI readerModel = OpenApiProcessor.modelFromReader(openApiConfig, classLoader, index);

OpenApiDocument document = OpenApiDocument.newInstance();

Expand All @@ -304,7 +304,7 @@ private OpenApiDocument generateSchema(IndexView index) throws IOException, Depe
if (staticModel != null) {
document.modelFromStaticFile(staticModel);
}
document.filter(OpenApiProcessor.getFilter(openApiConfig, classLoader));
document.filter(OpenApiProcessor.getFilter(openApiConfig, classLoader, index));
document.initialize();

return document;
Expand Down

0 comments on commit 5b7a92f

Please sign in to comment.