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

How to instruct jandex to index a dependency jar? #1960

Closed
vtcosta opened this issue Nov 12, 2023 · 4 comments
Closed

How to instruct jandex to index a dependency jar? #1960

vtcosta opened this issue Nov 12, 2023 · 4 comments

Comments

@vtcosta
Copy link

vtcosta commented Nov 12, 2023

I am trying to run a multi module project where one of the modules has all the type definitions, and I also have a module with the application itself. It seems that jandex will only index classes of the application war file. Is there a way to instruct jandex to index a dependency jar?

I am using openliberty with SmallRye GraphQL 2.5.1 as dependency of my project. That means, I am not using the mpGraphQL-2.0 feature.

Here is the error:
SRVE0283E: Exception caught while initializing context: graphql.AssertException: type Xyz not found in schema

It seems quarkus has a configuration for this, as can be seen in the following issue:
quarkusio/quarkus#36688

@jmartisk
Copy link
Member

The index is passed to the schema builder via SchemaBuilder.build(): https://github.com/smallrye/smallrye-graphql/blob/2.5.0/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java#L85
It is a responsibility of the runtime (Quarkus, OpenLiberty...) to call it. If you're not using the integration provided by the runtime, you have to call it yourself somewhere.

For example, the WildFly GraphQL Feature pack uses the StartupListener class (https://github.com/smallrye/smallrye-graphql/blob/2.5.0/server/implementation-servlet/src/main/java/io/smallrye/graphql/entry/http/StartupListener.java) which automatically adds dependencies into the index before it passes the index to the SchemaBuilder.

@vtcosta
Copy link
Author

vtcosta commented Nov 14, 2023

I was using the smallrye-graphql-servlet in my project, and I didn't even know that it was made for WildFly. Now I understand why it has some dependencies on jboss logging.

Anyway, looking at the StartupListener you provided, it seems that it will scan the WEB-INF/lib folder and include all of jar files to the index. So, a packaged WAR file would work just fine.

The thing is, I am using OpenLiberty's dev mode do develop my aplication. This means that, instead of deploying a real WAR file, it creates a XML file that mimics the structure of the WAR file, pointing to resources somewhere else on the file system. An example can be seen below:

<archive>
    <dir sourceOnDisk="C:\app\app-service\src\main\webapp" targetInArchive="/"/>
    <dir sourceOnDisk="C:\app\app-service\target\classes" targetInArchive="/WEB-INF/classes"/>
    <archive targetInArchive="/WEB-INF/lib/app-model.jar">
        <dir sourceOnDisk="C:\app\app-model\target\classes" targetInArchive="/"/>
        <file sourceOnDisk="C:\app\app-model\target\tmp\META-INF\MANIFEST.MF" targetInArchive="/META-INF/MANIFEST.MF"/>
    </archive>
    <file sourceOnDisk="C:\Users\me\.m2\repository\com\fasterxml\jackson\dataformat\jackson-dataformat-toml\2.15.2\jackson-dataformat-toml-2.15.2.jar" targetInArchive="/WEB-INF/lib/jackson-dataformat-toml-2.15.2.jar"/>
    <file sourceOnDisk="C:\Users\me\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.15.2\jackson-databind-2.15.2.jar" targetInArchive="/WEB-INF/lib/jackson-databind-2.15.2.jar"/>
    <file sourceOnDisk="C:\Users\me\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.15.2\jackson-annotations-2.15.2.jar" targetInArchive="/WEB-INF/lib/jackson-annotations-2.15.2.jar"/>
    <file sourceOnDisk="C:\Users\me\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.15.2\jackson-core-2.15.2.jar" targetInArchive="/WEB-INF/lib/jackson-core-2.15.2.jar"/>
    ...
</archive>

As can be seen above, app-service is my application and app-model contains the model definitions (including GraphQL stuff). They are part o multi module maven project. You can notice that the app-model.jar points to the build directory of my project, instead of a real JAR file.

I then copied the StartupListener to my project (with the same package, so that the class loader would choose mine instead of the one in the dependecy), and made the following changes with success:

    public void contextInitialized(ServletContextEvent sce) {
            ...

            Set<String> libPaths = sce.getServletContext().getResourcePaths("WEB-INF/lib");
            warURLs.addAll(libPaths.stream()
                    .filter(p -> p.endsWith(".jar"))
                    .map(sce.getServletContext()::getRealPath)
                    .map(Paths::get)
                    .map(Path::toUri)
                    .map(this::toURL)
                    .collect(Collectors.toList()));

            ...
    }

    private URL toURL(URI uri) {
        try {
            return uri.toURL();
        } catch (MalformedURLException ex) {
            throw new RuntimeException(ex);
        }
    }

The getResourcePaths method will get all the elements in the XML whose targetInArchive tag starts with WEB-INF/lib. Then we use the getRealPath method to get the value of the tag sourceOnDisk.

The above solution would work for both cases, a real WAR deployment, and a fake XML deployment. Maybe you could integrate it with your project, with the necessary modifications that you may need, and remove the part where you traverse the WEB-INF/lib looking for files.

By the way, before working this out, I had tried to use the OpenLiberty mpGraphQL-2.0 feature, and it had the same problem while using dev mode. I guess their implementation is based on the one you provided.

@t1
Copy link
Collaborator

t1 commented Nov 14, 2023

So the mpGraphQL feature works in war-mode but not in dev-mode? If I got that right, maybe you should suggest your changes to the OpenLiberty project, as the dev-mode is OpenLiberty specific.
BTW: It should run an additional listener just fine, as long as it has the @WebListener annotation.

@vtcosta
Copy link
Author

vtcosta commented Nov 15, 2023

I decided not to use mpGraphQL feature of OpenLiberty because they use an old version of SmallRye GraphQL. Instead, I am using smallrye-graphql, smallrye-graphql-servlet and smallrye-graphql-ui-graphiql as maven dependencies. I've fixed the problem in dev mode for me. And I just wanted to share how I got it working, because I believe it's more container agnostic if you rely on container specific methods to find resources (getResourcePaths followed by getRealPath), instead of iterating over the filesystem.

I'll will probably report that on the OpenLiberty github as well.

Thanks for your help.

@vtcosta vtcosta closed this as completed Nov 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants