#Spring found multiple beans

1 messages · Page 1 of 1 (latest)

severe cape
#

I have an issue where when I want to run my spring boot application I get told that "Parameter 0 of constructor in my.project.fooController requires a single bean, but 2 were found:

  • fooController: defined in file: [path/to/file/fooController]
  • my.project.fooController: defined in file: [path/to/file/fooController]"

I don't know how to fix this issue, since both are legit the same file. But I can provide some more information about my setup.
I want to use openApiGenerator in my project, so it generates the api and models from the openApi spec.
The generator creates an fooApi, fooApiController and fooApiDelegate.
I then proceeded to create the fooController class, which implements the fooApiDelegate and override the functions.
However now I have the issue that spring thinks I have 2 beans for some reason, even tho it's only 1. I can't even annotate the class with @Primary because like I said, it's the same class and therefor both would be annotated with @Primary.

vocal beaconBOT
#

<@&1004656351647117403> please have a look, thanks.

spare mural
#

can you share the class and full console log please peepo_heart

severe cape
#

Hmmm, it will take a bit because I have to change the code to be not work related.

spare mural
#

yeah I see

#

it makes it hard to help though

severe cape
#

So full log will be rough

spare mural
#

well then at least the related log

severe cape
#

NODDERS just give me a moment

sour grotto
#

A tad knackered, but two things that spring to mind without code: look into which packages are scanned/@Qualifier.

severe cape
severe cape
#

I think this should work.
This is part of my build.gradle.kts```
// OpenAPI Generator Config
tasks.named<org.openapitools.generator.gradle.plugin.tasks.GenerateTask>("openApiGenerate") {
dependsOn(cleanGenerated)
generatorName.set("spring")
inputSpec.set(file("src/main/resources/apiV1.yaml").absolutePath)
outputDir.set(layout.buildDirectory.dir("generated").get().asFile.absolutePath)
apiPackage.set("com.example.project.api.v1.controller")
invokerPackage.set("com.example.project.api.v1.invoker")
modelPackage.set("com.example.project.api.v1.model")
configOptions.set(
mapOf(
"delegatePattern" to "true",
"useSpringBoot3" to "true",
"dateLibrary" to "java8",
"useTags" to "true",
"useBeanValidation" to "true", // For bean validation
"useLombokAnnotations" to "true" // Optional, if lombok is used in the project
)
)

// Additional annotations
additionalProperties.set(
    mapOf(
        "fieldAnnotations" to "@JsonProperty"
    )
)

typeMappings.set(
    mapOf(
        "DateTime" to "java.time.OffsetDateTime",
        "UUID" to "java.util.UUID"
    )
)

}

val cleanGenerated by tasks.registering(Delete::class) {
delete(layout.buildDirectory.dir("generated"))
}

sourceSets {
main {
java {
setSrcDirs(listOf("src/main/java", "generated/src/main/java"))
}
}
}

#

Here is my controller:

java
package com.example.project.api.v1.controller;

import java.time.OffsetDateTime;
import java.util.List;
import java.util.UUID;

import com.example.project.api.v1.model.Incident;
import com.example.project.api.v1.model.Update;
import com.example.project.api.v1.service.IncidentService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
public class IncidentController implements IncidentsApiDelegate {

    private final IncidentService incidentService;

    @Override
    public ResponseEntity<Update> addUpdateToIncident(UUID incidentId, Update update) {
        Update savedUpdate = incidentService.addUpdateToIncident(incidentId, update);
        return ResponseEntity.status(HttpStatus.CREATED).body(savedUpdate);
    }

    @Override
    public ResponseEntity<Incident> createIncident(Incident incident) {
        Incident savedIncident = incidentService.saveIncident(incident);
        return ResponseEntity.status(HttpStatus.CREATED).body(savedIncident);
    }

    @Override
    public ResponseEntity<Void> deleteIncident(UUID incidentId) {
        return (incidentService.deleteIncident(incidentId) ? ResponseEntity.noContent() : ResponseEntity.notFound()).build();
    }

    @Override
    public ResponseEntity<Incident> getIncidentById(UUID incidentId) {
        Incident incident = incidentService.getIncidentById(incidentId);
        return incident != null ? ResponseEntity.ok(incident) : ResponseEntity.notFound().build();
    }

    @Override
    public ResponseEntity<List<Incident>> getIncidents(
            @RequestParam(required = false) UUID tenantId,
            @RequestParam(required = false) UUID serviceId,
            @RequestParam(required = false) UUID componentGroupId,
            @RequestParam(required = false) UUID componentId,
            @RequestParam(required = false) UUID status,
            @RequestParam(required = false) OffsetDateTime startDate,
            @RequestParam(required = false) OffsetDateTime endDate
    ) {
        List<Incident> incidents = incidentService.getAllIncidents(tenantId, serviceId, componentGroupId, componentId, status, startDate, endDate);
        return ResponseEntity.ok(incidents);
    }

    @Override
    public ResponseEntity<Incident> updateIncident(UUID incidentId, Incident incidentDetails) {
        Incident updatedIncident = incidentService.updateIncident(incidentId, incidentDetails);
        return updatedIncident != null ? ResponseEntity.ok(updatedIncident) : ResponseEntity.notFound().build();
    }
}
vocal beaconBOT
# severe cape Here is my controller: ``` java package com.example.project.api.v1.controller; ...

Detected code, here are some useful tools:

Formatted code
javapackage com.example.project.api.v1.controller;

import java.time.OffsetDateTime;
import java.util.List;
import java.util.UUID;
import com.example.project.api.v1.model.Incident;
import com.example.project.api.v1.model.Update;
import com.example.project.api.v1.service.IncidentService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
public class IncidentController implements IncidentsApiDelegate {
  private final IncidentService incidentService;
  @Override
  public ResponseEntity<Update> addUpdateToIncident(UUID incidentId, Update update) {
    Update savedUpdate = incidentService.addUpdateToIncident(incidentId, update);
    return ResponseEntity.status(HttpStatus.CREATED).body(savedUpdate);
  }
  @Override
  public ResponseEntity<Incident> createIncident(Incident incident) {
    Incident savedIncident = incidentService.saveIncident(incident);
    return ResponseEntity.status(HttpStatus.CREATED).body(savedIncident);
  }
  @Override
  public ResponseEntity<Void> deleteIncident(UUID incidentId) {
    return (incidentService.deleteIncident(incidentId) ? ResponseEntity.noContent() : ResponseEntity.notFound()).build();
  }
  @Override
  public ResponseEntity<Incident> getIncidentById(UUID incidentId) {
    Incident incident = incidentService.getIncidentById(incidentId);
    return incident != null  ? ResponseEntity.ok(incident) : ResponseEntity.notFound().build();
  }
  @Override
  public ResponseEntity<List<Incident>> getIncidents(@RequestParam(required = false) UUID tenantId, @RequestParam(required = false) UUID serviceId, @RequestParam(required = false) UUID componentGroupId, @RequestParam(required = false) UUID componentId, @RequestParam(required = false) UUID status, @RequestParam(required = false) OffsetDateTime startDate, @RequestParam(required = false) OffsetDateTime endDate) {
    List<Incident> incidents = incidentService.getAllIncidents(tenantId, serviceId, componentGroupId, componentId, status, startDate, endDate);
    return ResponseEntity.ok(incidents);
  }
  @Override
  public ResponseEntity<Incident> updateIncident(UUID incidentId, Incident incidentDetails) {
    Incident updatedIncident = incidentService.updateIncident(incidentId, incidentDetails);
    return updatedIncident != null  ? ResponseEntity.ok(updatedIncident) : ResponseEntity.notFound().build();
  }
}
severe cape
#

My Model class:

package com.example.project.api.v1.model;

import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.format.annotation.DateTimeFormat;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
import jakarta.validation.Valid;
import jakarta.validation.constraints.*;
import io.swagger.v3.oas.annotations.media.Schema;

import java.util.*;
import jakarta.annotation.Generated;

@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2024-07-08T18:26:05.045089+02:00[Europe/Berlin]", comments = "Generator version: 7.7.0")
@jakarta.persistence.Entity 
@jakarta.persistence.Table(name = "incidents")
public class Incident {

    @jakarta.persistence.Id 
    @jakarta.persistence.Column(name = "id")
    private java.util.UUID id;

    @jakarta.persistence.Column(name = "tenant_id")
    private java.util.UUID tenantId;

    @jakarta.persistence.Column(name = "service_id")
    private java.util.UUID serviceId;

    @jakarta.persistence.Column(name = "component_group_id")
    private java.util.UUID componentGroupId;

    @jakarta.persistence.Column(name = "component_id")
    private java.util.UUID componentId;

    @jakarta.persistence.Column(name = "status")
    private java.util.UUID status;

    @jakarta.persistence.Column(name = "start")
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    private java.time.OffsetDateTime start;

    @jakarta.persistence.Column(name = "end")
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    private java.time.OffsetDateTime end;

    public Incident id(java.util.UUID id) {
        this.id = id;
        return this;
    }
// getters, setters and more...
vocal beaconBOT
# severe cape My Model class: ``` package com.example.project.api.v1.model; import java.util...

Detected code, here are some useful tools:

Formatted code
package com.example.project.api.v1.model;

import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.format.annotation.DateTimeFormat;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
import jakarta.validation.Valid;
import jakarta.validation.constraints. * ;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util. * ;
import jakarta.annotation.Generated;

@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2024-07-08T18:26:05.045089+02:00[Europe/Berlin]", comments = "Generator version: 7.7.0") @jakarta
.persistence.Entity@jakarta
.persistence.Table(name = "incidents") public class Incident {
  @jakarta
  .persistence.Id@jakarta
  .persistence.Column(name = "id") private java.util.UUID id;
  @jakarta
  .persistence.Column(name = "tenant_id") private java.util.UUID tenantId;
  @jakarta
  .persistence.Column(name = "service_id") private java.util.UUID serviceId;
  @jakarta
  .persistence.Column(name = "component_group_id") private java.util.UUID componentGroupId;
  @jakarta
  .persistence.Column(name = "component_id") private java.util.UUID componentId;
  @jakarta
  .persistence.Column(name = "status") private java.util.UUID status;
  @jakarta
  .persistence.Column(name = "start") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) private java.time.OffsetDateTime start;
  @jakarta
  .persistence.Column(name = "end") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) private java.time.OffsetDateTime end;
  public Incident id(java.util.UUID id) {
    this .id = id;
    return this ;
  }
  // getters, setters and more...
vocal beaconBOT
severe cape
#

The delegate:

package com.example.project.api.v1.controller;

import org.springframework.format.annotation.DateTimeFormat;
import com.example.project.api.v1.model.Incident;
import com.example.project.api.v1.model.Update;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.multipart.MultipartFile;

import jakarta.validation.constraints.*;
import jakarta.validation.Valid;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import jakarta.annotation.Generated;

/**
* A delegate to be called by the {@link IncidentsApiController}}.
* Implement this interface with a {@link org.springframework.stereotype.Service} annotated class.
*/

@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2024-07-08T18:26:05.045089+02:00[Europe/Berlin]", comments = "Generator version: 7.7.0")
public interface IncidentsApiDelegate {

    default Optional < NativeWebRequest > getRequest() {
        return Optional.empty();
    }

    /**
     * POST /incidents/{incidentId}/updates : Add an update to an incident
     *
     * @param incidentId  (required)
     * @param update  (required)
     * @return Update added successfully (status code 201)
     *         or Invalid input (status code 400)
     *         or Incident not found (status code 404)
     * @see IncidentsApi#addUpdateToIncident
     */
    default ResponseEntity < Update > addUpdateToIncident(java.util.UUID incidentId,

            Update update) {
// more pointless code
vocal beaconBOT
# severe cape The delegate: ``` package com.example.project.api.v1.controller; import org.spr...

Detected code, here are some useful tools:

Formatted code
package com.example.project.api.v1.controller;

import org.springframework.format.annotation.DateTimeFormat;
import com.example.project.api.v1.model.Incident;
import com.example.project.api.v1.model.Update;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.multipart.MultipartFile;
import jakarta.validation.constraints. * ;
import jakarta.validation.Valid;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import jakarta.annotation.Generated;

/**
 * A delegate to be called by the {@link IncidentsApiController}}.
 * Implement this interface with a {@link org.springframework.stereotype.Service} annotated class.
 */
 
 @Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2024-07-08T18:26:05.045089+02:00[Europe/Berlin]", comments = "Generator version: 7.7.0")
 public interface IncidentsApiDelegate {
 
 default Optional < NativeWebRequest > getRequest() {
 return Optional.empty();
 }
 
 /**
 * POST /incidents/{incidentId}/updates : Add an update to an incident
 *
 * @param incidentId  (required)
 * @param update  (required)
 * @return Update added successfully (status code 201)
 *         or Invalid input (status code 400)
 *         or Incident not found (status code 404)
 * @see IncidentsApi#addUpdateToIncident
 */
default ResponseEntity<Update> addUpdateToIncident(java.util.UUID incidentId, Update update) {
  // more pointless code
severe cape
#

Error would be the following:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.example.project.api.v1.controller.SampleApiController required a single bean, but 2 were found:
    - sampleController: defined in file [C:\Path\To\Your\Project\build\classes\java\main\com\example\project\api\v1\controller\SampleController.class]
    - com.example.project.api.v1.controller.SampleController: defined in file [C:\Path\To\Your\Project\build\classes\java\main\com\example\project\api\v1\controller\SampleController.class]

This may be due to missing parameter name information

Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
#

@spare mural @sour grotto There u go. Is that sufficient?

severe cape
#

I think I found a hint. I noticed that I have 2 spring boot applications. 1 made by me and 1 additional is generated for some reason. I would assume that both register the same class as bean and therefor I get the issue

severe cape
#

Ok, for test purposes i deleted the generated openApiGeneratorApplication class and since then my program works. However since it automatically gets generated I still have an issue. I would need to figure out how to delete it after the generation task is done

severe cape
#

added the file removal to the openApiGenerate task. Now it works 👍