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

Java generation from CustomResourceDefinition yaml: field names containing dots, whitespace or quotes lead to compile error #4823

Closed
christiangebhard opened this issue Feb 1, 2023 · 3 comments · Fixed by #4824
Assignees
Milestone

Comments

@christiangebhard
Copy link

Describe the bug

If a CRD file contains a field with a name that contains a dot or a whitespace, the generated classes are not compiling.
I found this sanitize method, which seems to be responsible for cleaning the field names before creating the classes, but the cases dot/whitespace/quotes are not covered there.

Fabric8 Kubernetes Client version

6.4.1

Steps to reproduce

  1. create a maven project with the following files:

    • pom.xml
        <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>org.example</groupId>
          <artifactId>property-dot-space</artifactId>
          <version>1.0-SNAPSHOT</version>
      
          <properties>
              <maven.compiler.source>11</maven.compiler.source>
              <maven.compiler.target>11</maven.compiler.target>
              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
          </properties>
      
          <dependencies>
              <dependency>
                  <groupId>io.fabric8</groupId>
                  <artifactId>kubernetes-client</artifactId>
                  <version>6.4.1</version>
              </dependency>
              <dependency>
                  <groupId>io.fabric8</groupId>
                  <artifactId>generator-annotations</artifactId>
                  <version>6.4.1</version>
              </dependency>
          </dependencies>
      
          <build>
              <plugins>
      
                  <plugin>
                      <groupId>io.fabric8</groupId>
                      <artifactId>java-generator-maven-plugin</artifactId>
                      <version>6.4.1</version>
                      <executions>
                          <execution>
                              <goals>
                                  <goal>generate</goal>
                              </goals>
                              <id>crd-generator</id>
                          </execution>
                      </executions>
                      <configuration>
                          <source>${project.basedir}/src/main/resources</source>
                      </configuration>
                  </plugin>
              </plugins>
          </build>
      
      </project>
      
    • src/main/java/org/example/Main.java
      package org.example;
      
        public class Main {
            public static void main(String[] args) {
                System.out.println("Hello world!");
            }
        }
      
    • src/main/resources/example-crd-dot.yaml
      apiVersion: apiextensions.k8s.io/v1
      kind: CustomResourceDefinition
      metadata:
        name: dotdummies.example.com
      spec:
        group: example.com
        versions:
          - name: v1
            served: true
            storage: true
            schema:
              openAPIV3Schema:
                type: object
                properties:
                  spec:
                    type: object
                    properties:
                      with.dot:
                        type: string
        scope: Namespaced
        names:
          plural: dotdummies
          singular: dotdummy
          kind: DotDummy
      
    • src/main/resources/example-crd-quote.yaml
      apiVersion: apiextensions.k8s.io/v1
      kind: CustomResourceDefinition
      metadata:
        name: quotedummies.example.com
      spec:
        group: example.com
        versions:
          - name: v1
            served: true
            storage: true
            schema:
              openAPIV3Schema:
                type: object
                properties:
                  spec:
                    type: object
                    properties:
                      with'quote:
                        type: string
        scope: Namespaced
        names:
          plural: quotedummies
          singular: quotedummy
          kind: QuoteDummy
      
    • src/main/resources/example-crd-space.yaml
      apiVersion: apiextensions.k8s.io/v1
      kind: CustomResourceDefinition
      metadata:
        name: spacedummies.example.com
      spec:
        group: example.com
        versions:
          - name: v1
            served: true
            storage: true
            schema:
              openAPIV3Schema:
                type: object
                properties:
                  spec:
                    type: object
                    properties:
                      with space:
                        type: string
        scope: Namespaced
        names:
          plural: spacedummies
          singular: spacedummy
          kind: SpaceDummy
      
  2. run mvn clean compile

Current behavior

  • build fails with the following output (paths anonymized):
    [INFO] Scanning for projects...
    [INFO] 
    [INFO] -------------------< org.example:property-dot-space >-------------------
    [INFO] Building property-dot-space 1.0-SNAPSHOT
    [INFO] --------------------------------[ jar ]---------------------------------
    [INFO] 
    [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ property-dot-space ---
    [INFO] Deleting /exampleprojectpath/property-dot-space/target
    [INFO] 
    [INFO] --- java-generator-maven-plugin:6.4.1:generate (crd-generator) @ property-dot-space ---
    [INFO] 
    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ property-dot-space ---
    [INFO] Using 'UTF-8' encoding to copy filtered resources.
    [INFO] Copying 3 resources
    [INFO] 
    [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ property-dot-space ---
    [INFO] Changes detected - recompiling the module!
    [INFO] Compiling 7 source files to /exampleprojectpath/property-dot-space/target/classes
    [INFO] -------------------------------------------------------------
    [ERROR] COMPILATION ERROR : 
    [INFO] -------------------------------------------------------------
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[11,24] ';' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[11,30] <identifier> expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[13,26] ';' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[13,27] invalid method declaration; return type required
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[14,20] ';' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[14,21] not a statement
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[17,25] '(' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[17,42] ',', ')', or '[' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[18,13] not a statement
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[18,18] ';' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[18,31] ';' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[18,32] not a statement
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[11,24] unclosed character literal
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[11,30] <identifier> expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[13,26] unclosed character literal
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[13,28] invalid method declaration; return type required
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[14,20] unclosed character literal
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[14,22] not a statement
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[17,24] unclosed character literal
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[17,26] invalid method declaration; return type required
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[17,42] unclosed character literal
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[18,18] unclosed character literal
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[18,13] not a statement
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[18,31] unclosed character literal
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[18,33] not a statement
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/DotDummySpec.java:[11,24] ';' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/DotDummySpec.java:[11,28] <identifier> expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/DotDummySpec.java:[13,26] ';' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/DotDummySpec.java:[13,27] invalid method declaration; return type required
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/DotDummySpec.java:[17,24] '(' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/DotDummySpec.java:[17,25] invalid method declaration; return type required
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/DotDummySpec.java:[17,44] wrong receiver parameter name
    [INFO] 32 errors 
    [INFO] -------------------------------------------------------------
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD FAILURE
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  1.123 s
    [INFO] Finished at: 2023-02-01T13:58:11+01:00
    [INFO] ------------------------------------------------------------------------
    [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project property-dot-space: Compilation failure: Compilation failure: 
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[11,24] ';' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[11,30] <identifier> expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[13,26] ';' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[13,27] invalid method declaration; return type required
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[14,20] ';' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[14,21] not a statement
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[17,25] '(' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[17,42] ',', ')', or '[' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[18,13] not a statement
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[18,18] ';' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[18,31] ';' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/SpaceDummySpec.java:[18,32] not a statement
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[11,24] unclosed character literal
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[11,30] <identifier> expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[13,26] unclosed character literal
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[13,28] invalid method declaration; return type required
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[14,20] unclosed character literal
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[14,22] not a statement
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[17,24] unclosed character literal
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[17,26] invalid method declaration; return type required
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[17,42] unclosed character literal
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[18,18] unclosed character literal
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[18,13] not a statement
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[18,31] unclosed character literal
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/QuoteDummySpec.java:[18,33] not a statement
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/DotDummySpec.java:[11,24] ';' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/DotDummySpec.java:[11,28] <identifier> expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/DotDummySpec.java:[13,26] ';' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/DotDummySpec.java:[13,27] invalid method declaration; return type required
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/DotDummySpec.java:[17,24] '(' expected
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/DotDummySpec.java:[17,25] invalid method declaration; return type required
    [ERROR] /exampleprojectpath/property-dot-space/target/generated-sources/java/com/example/v1/DotDummySpec.java:[17,44] wrong receiver parameter name
    [ERROR] -> [Help 1]
    [ERROR] 
    [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
    [ERROR] Re-run Maven using the -X switch to enable full debug logging.
    [ERROR] 
    [ERROR] For more information about the errors and possible solutions, please read the following articles:
    [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
    
  • generated DotDummySpec.java looks like:
    package com.example.v1;
    
    @com.fasterxml.jackson.annotation.JsonInclude(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL)
    @com.fasterxml.jackson.annotation.JsonPropertyOrder({"with.dot"})
    @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = com.fasterxml.jackson.databind.JsonDeserializer.None.class)
    @javax.annotation.processing.Generated("io.fabric8.java.generator.CRGeneratorRunner")
    public class DotDummySpec implements io.fabric8.kubernetes.api.model.KubernetesResource {
    
        @com.fasterxml.jackson.annotation.JsonProperty("with.dot")
        @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SKIP)
        private String with.dot;
    
        public String getWith.dot() {
            return with.dot;
        }
    
        public void setWith.dot(String with.dot) {
            this.with.dot = with.dot;
        }
    }
    
  • generated QuoteDummySpec.java looks like:
    package com.example.v1;
    
    @com.fasterxml.jackson.annotation.JsonInclude(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL)
    @com.fasterxml.jackson.annotation.JsonPropertyOrder({"with'quote"})
    @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = com.fasterxml.jackson.databind.JsonDeserializer.None.class)
    @javax.annotation.processing.Generated("io.fabric8.java.generator.CRGeneratorRunner")
    public class QuoteDummySpec implements io.fabric8.kubernetes.api.model.KubernetesResource {
    
        @com.fasterxml.jackson.annotation.JsonProperty("with'quote")
        @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SKIP)
        private String with'quote;
    
        public String getWith'quote() {
            return with'quote;
        }
    
        public void setWith'quote(String with'quote) {
            this.with'quote = with'quote;
        }
    }
    
  • generated SpaceDummySpec.java looks like:
    package com.example.v1;
    
    @com.fasterxml.jackson.annotation.JsonInclude(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL)
    @com.fasterxml.jackson.annotation.JsonPropertyOrder({"with space"})
    @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = com.fasterxml.jackson.databind.JsonDeserializer.None.class)
    @javax.annotation.processing.Generated("io.fabric8.java.generator.CRGeneratorRunner")
    public class SpaceDummySpec implements io.fabric8.kubernetes.api.model.KubernetesResource {
    
        @com.fasterxml.jackson.annotation.JsonProperty("with space")
        @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SKIP)
        private String with space;
    
        public String getWith space() {
            return with space;
        }
    
        public void setWith space(String with space) {
            this.with space = with space;
        }
    }
    
    

In the current state the generated classes are of no use and I do not see any valid workaround other than implementing these classes myself.

Expected behavior

A successful maven build is expected which generated classes DotDummy and DotDummySpec, QuoteDummy and QuoteDummySpec, SpaceDummy and SpaceDummySpec and compiled them.

Runtime

other (please specify in additional context)

Kubernetes API Server version

other (please specify in additional context)

Environment

macOS

Fabric8 Kubernetes Client Logs

No response

Additional context

no kubernetes runtime or API server needed to reproduce this bug

@miriSch
Copy link
Contributor

miriSch commented Feb 1, 2023

Maybe the sanitize method could make use of Character#isJavaIdentifierPart as Character.isJavaIdentifierStart(str.charAt(0)) is already used.

@andreaTP
Copy link
Member

andreaTP commented Feb 1, 2023

Hi @christiangebhard thanks for the report!
To my great surprise, those three are all valid CRDs, so we have to improve the field sanitization mechanism to cover those cases.

@christiangebhard
Copy link
Author

Thanks for your help @andreaTP , really appreciate it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants