Ousmane MBINTE
Ousmane MBINTE

Reputation: 742

Injection of CommandGateway not work in Quarkus using AxonIq

I have a microservice in Quarkus which implementing CQRS/Event sourcing using AxonIq Framework. I Already made it using Spring boot and everythings it's ok. I would like to migrate it in Quarkus but I have error during maven compilation probably because the Ioc. When CDI try to create the service I think he can inject Axon CommandGateway and QueryGateway.

[ERROR] Failed to execute goal io.quarkus.platform:quarkus-maven-plugin:2.7.1.Final:build (default) on project domain: Failed to build quarkus application: io.quarkus.builder.BuildExce
ption: Build failure: Build failed due to errors
[ERROR]         [error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: Found 2 deployment problems:   
[ERROR] [1] Unsatisfied dependency for type org.axonframework.Commandhandling.CommandGateway and qualifiers [@Default]
[ERROR]         - java member: com.omb.commands.MyAggregateCommandService().commandGateway
[ERROR]         - declared on CLASS bean [types=[com.omb.commands.MyAggregateCommandService, java.lang.Object], qualifiers=[@Default, @Any], target=com.omb.commands.MyAggregateCommandService]

Configuration

package com.omb..configuration;

import com.omb..MyAggregate;
import com.omb..commands.MyAggregateCommandService;
import com.omb..mongo.MongoMyAggregateProjector;
import com.omb..queries.MyAggregateQueryService;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoDatabase;
import org.axonframework.config.Configurer;
import org.axonframework.config.DefaultConfigurer;
import org.axonframework.eventsourcing.eventstore.EventStorageEngine;
import org.axonframework.extensions.mongo.DefaultMongoTemplate;
import org.axonframework.extensions.mongo.eventsourcing.tokenstore.MongoTokenStore;
import org.axonframework.serialization.xml.XStreamSerializer;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;

@ApplicationScoped
public class AxonConfiguration {

    @Produces
    public org.axonframework.config.Configuration getAxonConfiguration(MongoMyAggregateProjector MyAggregateProjector, MongoDatabase database, EventStorageEngine eventStorageEngine) {
        XStreamSerializer serializer = XStreamSerializer.defaultSerializer();

        Configurer configurer = DefaultConfigurer
                .defaultConfiguration()
                .configureAggregate(MyAggregate.class)
                .eventProcessing(conf -> conf
                        .registerTokenStore(config -> MongoTokenStore.builder()
                                .mongoTemplate(
                                        DefaultMongoTemplate.builder()
                                                // optionally choose collection names here
                                                .mongoDatabase(database)
                                                .build())
                                .serializer(serializer)
                                .build()))
                .registerEventHandler(conf -> MyAggregateProjector)
                .registerQueryHandler(conf -> MyAggregateProjector)
                .configureEmbeddedEventStore(conf -> eventStorageEngine);

        return configurer.start();
    }

    @Produces
    public MongoDatabase mongoDatabase(MongoClient client) {
        return client.getDatabase("MyAggregate");
    }

    @Produces
    @ApplicationScoped
    public MyAggregateQueryService queryService(org.axonframework.config.Configuration configuration) {
        return new MyAggregateQueryService(configuration.queryGateway());
    }

    @Produces
    @ApplicationScoped
    public MyAggregateCommandService commandService(org.axonframework.config.Configuration configuration) {
        return new MyAggregateCommandService(configuration.commandGateway());
    }
}

Service :

package com.omb..commands;

import com.omb..models.MyAggregateDTO;
import org.axonframework.commandhandling.gateway.CommandGateway;

import javax.enterprise.context.ApplicationScoped;
import java.util.concurrent.CompletableFuture;

@ApplicationScoped
public class MyAggregateCommandService {

    CommandGateway commandGateway;

    public MyAggregateCommandService(CommandGateway commandGateway) {
        this.commandGateway = commandGateway;
    }

    public CompletableFuture<String> createMyAggregate(final MyAggregateDTO MyAggregate) {
        return commandGateway.send(new CreateMyAggregateCommand(MyAggregate.id(), MyAggregate.name()));
    }

    public CompletableFuture<MyAggregateDTO> updateMyAggregate(final String MyAggregateId, final MyAggregateDTO MyAggregate) {
        if(MyAggregate.id().equals(MyAggregateId)) {
            return commandGateway.send(new UpdateMyAggregateCommand(MyAggregate.id(), MyAggregate.name()));
        } else {
            throw new IllegalArgumentException("Identifiers are not the same, does not update");
        }
    }
}

Controller :

package com.omb;

import com.omb..commands.MyAggregateCommandService;
import com.omb..models.MyAggregateDTO;

import javax.validation.Valid;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

@Path("/commands/MyAggregate")
public class MyAggregateCommandController {

    private MyAggregateCommandService MyAggregateCommandService;

    public MyAggregateCommandController(MyAggregateCommandService MyAggregateCommandService) {
        this.MyAggregateCommandService = MyAggregateCommandService;
    }

    @POST
    @Path("/create")
    public CompletableFuture<String> createMyAggregate(@Valid MyAggregateCreateInput MyAggregate) {
        MyAggregateDTO MyAggregateDTO = new MyAggregateDTO(UUID.randomUUID().toString(), MyAggregate.name());
        return MyAggregateCommandService.createMyAggregate(MyAggregateDTO);
    }

    @PUT
    @Path("/{MyAggregateId}")
    public CompletableFuture<MyAggregateDTO> updateMyAggregate(@PathParam("MyAggregateId") String MyAggregateId, MyAggregateDTO MyAggregate) {
        MyAggregateDTO MyAggregateDTO = new MyAggregateDTO(MyAggregate.id(), MyAggregate.name());
        return MyAggregateCommandService.updateMyAggregate(MyAggregateId,MyAggregateDTO);
    }

/*    @ExceptionHandler(value = Exception.class)
    public ResponseEntity<String> handle(Exception e) {
        return ResponseEntity.badRequest().body(e.getMessage());
    }*/
}

dependency

<dependency>
            <groupId>org.axonframework.extensions.mongo</groupId>
            <artifactId>axon-mongo</artifactId>
            <version>4.5</version>
        </dependency>
        <dependency>
            <groupId>org.axonframework</groupId>
            <artifactId>axon-test</artifactId>
            <scope>test</scope>
            <version>4.5.6</version>
        </dependency>
        <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-mongodb-panache</artifactId>
    </dependency>

    <dependency>
        <groupId>org.axonframework</groupId>
        <artifactId>axon-configuration</artifactId>
    </dependency>
    <dependency>
        <groupId>org.axonframework</groupId>
        <artifactId>axon-modelling</artifactId>
    </dependency>
    <dependency>
        <groupId>org.axonframework</groupId>
        <artifactId>axon-messaging</artifactId>
    </dependency>

        <!-- Quarkus -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-core</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-junit5</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-hibernate-validator</artifactId>
        </dependency>

Upvotes: 1

Views: 419

Answers (1)

jeanpic
jeanpic

Reputation: 541

I had the same issue, one of the reasons can be that your bean is brought by a dependency and to fix it you need to add an empty beans.xml in main/resources/META-INF in this dependency in order for Quarkus to discover the beans as indicated by the documentation

Relevant extract:

The bean archive is synthesized from:

  • the application classes,

  • dependencies that contain a beans.xml descriptor (content is ignored),

  • dependencies that contain a Jandex index - META-INF/jandex.idx,

  • dependencies referenced by quarkus.index-dependency in application.properties,

  • and Quarkus integration code.

Upvotes: 1

Related Questions