25

First of all, I have a multi-module maven hierarchy like that:

├── project (parent pom.xml)
│   ├── service
│   ├── api-library

So now to the problem:

I am writing a JAX-RS Endpoint in the service module which uses classes in the api-library.
When I start quarkus, I am getting this warning:

13:01:18,784 WARN  [io.qua.dep.ste.ReflectiveHierarchyStep] Unable to properly register the hierarchy of the following classes for reflection as they are not in the Jandex index:
- com.example.Fruit
- com.example.Car
Consider adding them to the index either by creating a Jandex index for your dependency or via quarkus.index-dependency properties.

This two classes com.example.Fruit and com.example.Car are located in the api-library module.

So I think I need to add them to the Jandex index-dependency in the application.properties.

But how can I add Jandex index-dependencies into quarkus?

Emre Isik
  • 456
  • 6
  • 12

3 Answers3

29

Quarkus automatically indexes the main module but, when you have additional modules containing CDI beans, entities, objects serialized as JSON, you need to explicitly index them.

There are a couple of different (easy to implement) options to do so.

Using the Jandex Maven plugin

Just add the following to the additional module pom.xml:

<build>
  <plugins>
    <plugin>
      <groupId>org.jboss.jandex</groupId>
      <artifactId>jandex-maven-plugin</artifactId>
      <version>1.0.8</version>
      <executions>
        <execution>
          <id>make-index</id>
          <goals>
            <goal>jandex</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

It's the most beneficial option if your dependency is external to your project and you want to build the index once and for all.

Using the Gradle Jandex plugin

If you are using Gradle, there is a third party plugin allowing to generate a Jandex index: https://github.com/kordamp/jandex-gradle-plugin .

Adding an empty META-INF/beans.xml

If you add an empty META-INF/beans.xml file in the additional module src/main/resources, the classes will also be indexed.

The classes will be indexed by Quarkus itself.

Indexing other dependencies

If you can't modify the dependency (think of a third-party dependency, for instance), you can still index it by adding an entry to your application.properties:

quarkus.index-dependency.<name>.group-id=
quarkus.index-dependency.<name>.artifact-id=
quarkus.index-dependency.<name>.classifier=(this one is optional)

with <name> being a name you choose to identify your dependency.

Guillaume Smet
  • 7,702
  • 13
  • 21
  • 2
    Yes, I used the empty `beans.xml` method and it worked perfectly. – Emre Isik Apr 04 '19 at 11:26
  • And i want to mention that it also scans and finds endpoints in the other module. And also hibernate validation annotations are recognized :) Before adding the jandex index it doesn't recognize JAX-RS beans in other modules. – Emre Isik Apr 04 '19 at 11:29
  • 4
    It would be very helpful to have this information in the Quarkus User Guide. – Harald Wellmann Apr 04 '19 at 13:19
  • Would it perhaps make sense to add a dependency to Jandex `2.1.1.Final` to the `jandex-maven-plugin` until https://github.com/wildfly/jandex-maven-plugin/pull/13 lands and the plugin is bumped? – geoand Apr 04 '19 at 14:25
  • I faced this issue today trying to run the `quarkus-quickstarts/hibernate-orm-resteasy`. It only worked adding the `Jandex` Plugin in the `pom.xml`. Adding `beans.xml` does not solve... – Rafael Soares - tuelho May 07 '19 at 13:36
  • Very useful, *Indexing other dependencies* for me; I had the entities in a external project and when adding the properties to the application.properties it worked wonderfully. – Harold Castillo Jun 23 '19 at 03:32
  • 4
    What of us using Gradle? Could you post an equivalent to the Maven code? `beans.xml` doesn't work for me either – Snappawapa Jun 26 '19 at 03:02
  • "If you add an empty META-INF/beans.xml file in your src/main/resources, the classes will also be indexed." #morejavaDIVoodoo But I'll take it. Thanks! – granadaCoder Oct 21 '19 at 20:32
  • "the classes will also be indexed." which classes you mean? The classes from **your** project or the classes from 3rd party libs? If you mean **your** classes, no `beans.xml` is needed. If you mean 3rd party classes, the latter does not work for me: If I put `META-INF/beans.xml`, 3rd party libs are **NOT** scanned: https://stackoverflow.com/questions/59080009/quarkus-cannot-index-classes-with-beans-xml – nimo23 Nov 29 '19 at 11:51
  • If you want to scan for components, the `META-INF/beans.xml` resource must **not** be added to the main application but to each jar. This cannot be easily done with typical dependencies (libraries). – nimo23 Dec 08 '19 at 22:16
  • @nimo23 We are only talking here about external modules so, yes, adding it to the main module won't work. It's a marker for your external modules. For external jars, see the other option with `quarkus.index-dependency`. Everything is carefully explained in my answer. – Guillaume Smet Dec 08 '19 at 22:50
  • I added dependencies by `quarkus.index-dependency`, a lot of those are registered successfully by quarkus, however, not all - there are still dependencies under the list of `Unable to properly register the hierarchy of the..` when compiling. Why? Are there any restrictions of dependencies which are resolvable? – nimo23 Dec 08 '19 at 23:18
  • Using the last method, should match the class name of the object you're trying to inject from your 3rd party library? I'm still getting `UnsatisfiedResolutionException: Unsatisfied dependency for type and qualifiers [@Default]` after updating application.properties. – cs_pupil Oct 15 '20 at 22:39
  • Adding empty beans.xml does work. anyone has any idea how does that works ! – Mehdi Benmesssaoud Feb 02 '21 at 14:52
1

Edit (11/02/2020)

Now in my microservices I am extensively using the targets property from RegisterForReflection annotation. This is the property explanation according to the documentation:

/**
 * Alternative classes that should actually be registered for reflection instead of the current class.
 *
 * This allows for classes in 3rd party libraries to be registered without modification or writing an
 * extension. If this is set then the class it is placed on is not registered for reflection, so this should
 * generally just be placed on an empty class that is not otherwise used.
 */

This works fine on quarkus based projects and can handle the basic cases when you want to register a handful POJOs for reflection. The RegisterForReflection annotation will register the POJO by himself, but will not going to register the return types from POJO's methods.

More advanced way is to use @AutomaticFeature annotation as described here. I am using it with Reflections Library and with custom made utility wrapper: ReflectUtils

Now I can do more complex tasks:

@AutomaticFeature
@RegisterForReflection(targets = {
        com.hotelbeds.hotelapimodel.auto.convert.json.DateSerializer.class,
        TimeDeserializer.class,
        DateSerializer.class,
        TimeSerializer.class,
        RateSerializer.class,
})
public class HotelBedsReflection implements Feature {
    public static Logger log = Utils.findLogger(Reflections.class);

    @Override
    public void beforeAnalysis(BeforeAnalysisAccess access) {
        ReflectUtils.registerPackage(LanguagesRQ.class.getPackage().getName(), Object.class);
        ReflectUtils.registerPackage(AvailabilityRQ.class.getPackage().getName(), Object.class);
        ReflectUtils.registerPackage(Occupancy.class.getPackage().getName(), Object.class);
    }
}

Initial Answer

I've tried to add Jandex index, to add beans.xml and also to Indexing other dependencies as described in @emre-işık answer, however my third party class (EpAutomationRs) wasn't registered for reflection in native mode. So I've ended up with quick and dirty solution for registering it (see below). I've created an unused REST JSON endpoint which returns the class.

/**
 * the purpose of this method is to register for reflection EpAutomationRs class
 *
 * @return
 */
@GET
@Path(GET_EMPTY_RS)
@Produces(MediaType.APPLICATION_JSON)
public EpAutomationRs entry() {
    return new EpAutomationRs();
}
Community
  • 1
  • 1
Triphon Penakov
  • 154
  • 1
  • 5
  • Please add a little explanation of what's going on in your solution. Thanks. – ejderuby Aug 07 '19 at 17:46
  • Done. In order to register the class for reflection I've created a fake REST endpoint in my project which return the class. – Triphon Penakov Aug 08 '19 at 19:29
  • Did you add the `@RegisterForReflection` annotation to your class? – Guillaume Smet Oct 22 '19 at 07:05
  • One more thing to clarify - I've tried to add the `@RegisterForReflection` annotation and it failed, but nevertheless even if it was succeeded I will have to add the entire quarkus-core dependency to my third party library. IMO - quarkus specific annotations should be added in separate module instead of quarkus-core. – Triphon Penakov Oct 29 '19 at 14:04
0

For gradle users, you can use this plugin in the build.gradle of the module you depend on.

tellisnz
  • 498
  • 4
  • 10