Home > front end >  mvn spring-boot:run "No primary or single public constructor found...TemplateLineItemInput"
mvn spring-boot:run "No primary or single public constructor found...TemplateLineItemInput"

Time:10-07

I've got an up-the-middle Spring Boot Lombok project that works like a champ from the IDE but errors strangely when I run it from the command line through mvn spring-boot:run. Its a pretty recent version Spring Boot...

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

Lombok is unremarkable and came from the Spring Initializr thing (https://start.spring.io/).

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

The JavaBean its complaining about is equally boring...

import lombok.Builder;
import lombok.Data;

import java.math.BigDecimal;

@Data
@Builder(toBuilder = true)
public class TemplateLineItemInput {
  private final String partMasterId;
  private final String partMasterIdPath;
  private final String actionType;
  private final BigDecimal actionQuantity;
}

The API of this Boot project is GraphQL but when I execute the following mutation from a mvn spring-boot:run invocation it always comes back as an error (nothing on the console...the framework is kicking it out somehow).

Request...

mutation createTemplateLineItem($tbomId: ID!) {
  createTemplateLineItem(
    tbomId: $tbomId
    input: {
      partMasterId: "2"
      partMasterIdPath: "808863036.1"
      actionType: "ADD"
      actionQuantity: "2"
    }) {
    ...TBomFrag
  }
}
...
{
  "partMasterId": "5025489768",
  "tbomId": "a4688d22-9d99-41a2-9777-6acc75b2aab9",
  "lineItemId": "9e460199-34fb-432c-b971-8cd8321d3283"
}

Response...
{
  "errors": [
    {
      "message": "No primary or single public constructor found for class aero.blue.ems.boa.domain.TemplateLineItemInput - and no default constructor found either",
      "locations": [
        {
          "line": 20,
          "column": 3
        }
      ],
      "path": [
        "createTemplateLineItem"
      ],
      "extensions": {
        "classification": "INTERNAL_ERROR"
      }
    }
  ],
  "data": {
    "createTemplateLineItem": null
  }
}

My spring-boot-maven-plugin is configured like...

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.5.4</version>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <configuration>
                            <classifier>exec</classifier>
                        </configuration>
                    </execution>
                    <execution>
                        <goals>
                            <goal>build-info</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

...also from Spring Initializr

When I run the Application from the IDE directly, no issue. The mutation works fine.

Is there something missing from my spring-boot:run config in the pom.xml or something? Did I have to clue the plugin into annotation processing? This is really confusing.

CodePudding user response:

Please,

Check the following config on section plugins at you pom.xml project, as following here:

<project>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>getting-started</artifactId>
    <!-- ... -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

For more information about, check this link: https://docs.spring.io/spring-boot/docs/2.5.4/maven-plugin/reference/htmlsingle/

CodePudding user response:

Ultimately this comes down to Lombok misconfiguration of my beans. The fix is to add the @AllArgsConstructor to the bean definition

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

import java.math.BigDecimal;

@Data
@Builder(toBuilder = true)
@AllArgsConstructor
public class TemplateLineItemInput {
  private final String partMasterId;
  private final String partMasterIdPath;
  private final String actionType;
  private final BigDecimal actionQuantity;
}

How we figured this out was to "Delombok" the Bean and look at the resulting code. This observation matched the error message; there was no public constructor.

  ...
  TemplateLineItemInput(String partMasterId, String partMasterIdPath, String actionType, BigDecimal actionQuantity) {
    this.partMasterId = partMasterId;
    this.partMasterIdPath = partMasterIdPath;
    this.actionType = actionType;
    this.actionQuantity = actionQuantity;
  }

Somehow (I still don't fully get why), the @Builder(toBuilder=true) annotation had Lombok producing a package private constructor. Jackson needed something public.

Adding the @AllArgsConstructor annotation made that constructor public and all is well.

  public TemplateLineItemInput(String partMasterId, String partMasterIdPath, String actionType, BigDecimal actionQuantity) {
    this.partMasterId = partMasterId;
    this.partMasterIdPath = partMasterIdPath;
    this.actionType = actionType;
    this.actionQuantity = actionQuantity;
  }

Delombok was the key.

  • Related