mulesoft-labs / raml-for-jax-rs

This project is all about two way transformation of JAX-RS-annotated Java code to RAML API description and back.
Other
296 stars 181 forks source link

unable to create type array item of type object #434

Open rkrgarlapati opened 4 years ago

rkrgarlapati commented 4 years ago

Hi,

Upon running below command, i see array related exception.

java -jar ./target/raml-to-jaxrs-cli-<version>-jar-with-dependencies.jar -d /tmp -r foo.bar ../examples/maven-examples/raml-defined-example/src/main/resources/types_user_defined.raml

Sample from raml, can you please help, i have many type: array in my raml. I see similar kind of issues raised multiple times, but most of them suggested me to remove type: array. But in my case it would be too much of manual work.

 versions:
  type: array
  items:
    properties:
      key:
        type: string
        required: false

Exception:

Exception in thread "main" org.raml.ramltopojo.GenerationException: unable to create type array item of type object (or maybe an inline array type ?)
        at org.raml.ramltopojo.array.ArrayTypeHandler.javaClassReference(ArrayTypeHandler.java:56)
        at org.raml.ramltopojo.TypeDeclarationType.calculateTypeName(TypeDeclarationType.java:407)
        at org.raml.ramltopojo.object.ObjectTypeHandler.findType(ObjectTypeHandler.java:399)
        at org.raml.ramltopojo.object.ObjectTypeHandler.createInterface(ObjectTypeHandler.java:202)
        at org.raml.ramltopojo.object.ObjectTypeHandler.create(ObjectTypeHandler.java:66)
        at org.raml.ramltopojo.TypeDeclarationType.createNamedType(TypeDeclarationType.java:380)
        at org.raml.ramltopojo.RamlToPojoImpl.buildPojo(RamlToPojoImpl.java:59)
        at org.raml.jaxrs.generator.builders.RamlToPojoTypeGenerator.output(RamlToPojoTypeGenerator.java:59)
        at org.raml.jaxrs.generator.CurrentBuild.generate(CurrentBuild.java:161)
        at org.raml.jaxrs.generator.RamlScanner.handleRamlFile(RamlScanner.java:84)
        at org.raml.jaxrs.generator.RamlScanner.handle(RamlScanner.java:62)
        at org.raml.jaxrs.generator.RamlScanner.handle(RamlScanner.java:45)
        at org.raml.jaxrs.ramltojaxrs.Main.main(Main.java:82)

It resolved my issue after adding this annotation as below:

versions:
  (ramltopojo.types):
    generateInlineArrayType: true
  type: array
  items:
    type: string

But I am not willing to change the original RAML file, is there any other solution.

jpbelang commented 4 years ago

Not exaclty sure what version you were using.

            versions:
              type: array
              items:
                properties:
                  key:
                    type: string
                    required: false

This is handled by the raml-java-tools project. There are examples that seem to work with your case. specifically

    inlineStuff:
      type: array
      items:
         type: object
         properties:
             last: string

The difference may be the "type: object" line.

The underlying parser that was used in 3.x.x is very finicky about inline types (sometimes having them behave differently...).
Examples are in this project: https://github.com/mulesoft-labs/raml-java-tools Around here: raml-to-pojo-maven-example/src/main/resources/arrays.raml

jpbelang commented 4 years ago

Which version are you using ?

rkrgarlapati commented 4 years ago

#%RAML 1.0

rkrgarlapati commented 4 years ago

Strange issue:

As you suggested i used this plugin,

<plugin>
    <groupId>org.raml</groupId>
    <artifactId>raml-to-pojo-maven-plugin</artifactId>
    <version>1.0.6</version>
    <executions>
        <execution>
            <id>goo</id>
            <phase>generate-sources</phase>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <defaultPackage>foo.foo</defaultPackage>
                <ramlFile>
                    c:\raml-path\process-api.raml
                </ramlFile>

                <!--<basePlugins>
                    <value>core.equalsAndHashCode</value>
                </basePlugins>-->
                <resourcePackage>com.folder.client.resources</resourcePackage>
                <modelPackage>com.folder.client.model</modelPackage>
                <supportPackage>com.folder.client.support</supportPackage>
                <outputDirectory>${project.basedir}/src/main/java</outputDirectory>

            </configuration>
        </execution>
    </executions>
</plugin>

compile successful, generated stubs only for 'uses' section(refer below), but skipped for the entire body of RAML, didn't generate any stubs for my endpoints. for example, this plugin generated stubs only for below section, skipped the body part:

uses:
  Health: /health-check/health-check.raml
  StandardErrors: /errors-library/errors-library.raml

With the same raml, i used raml-to-jaxrs-maven-plugin, it successfully generated stubs, but only trick is i need to use (ramltopojo.types) annotation as mentioned in my original post, which i would like to avoid.

jpbelang commented 4 years ago

Ok, cool.

The raml to pojo plugin only generates types defined in the raml files. It handles the types, whether they be inline or straight up standalone types.

The raml-to-jaxrs plugin generates the endpoints and calls the raml-to-pojo code when it finds an inline type defined in its endpoints (except for jsonschema types and xmlschema types, which you are not using).

So errors when generating types (like the one you were (are) getting with arrays) are the responsibility of raml-to-pojo. The thing I'm not understanding is why in my examples (in the raml-to-pojo project) the generation works (without the annotation)

There is another piece of software that I'm relying on called the raml-java-parser. This parser is being deprecated and has many issues (relative to inline types): one of them is it handles inline arrays in unpredictable ways (sometimes it calls the items objects, sometimes their proper type...). It's very annoying. It's what is happening around your type. However, from trying to understand what you are trying to do, I seem to have examples that work at generating the code properly. It's just that your raml has issues that trigger the parser problem.

So this is a bit of a shot in the dark, but change:

            versions:
              type: array
              items:
                properties:
                  key:
                    type: string
                    required: false

to:

```yaml
            versions:
              type: array
              items:
                type: object  # <------- this
                properties:
                  key:
                    type: string
                    required: false

And run the raml-for-jaxrs stuff again (and remove the annotation).

rkrgarlapati commented 4 years ago

Sorry for the delay in response.

same error:

Error generating Java classes from: null
: unable to create type array item of type object (or maybe an inline array type ?) -> [Help 1]

Not Working:

myname:
  type: string
  required: false   
  description: Nick Name
  example: "Activate fellow" 
versions:
  type: array
  items:
    type: object
    properties:
      key:
        type: string
        required: false
        example: myownOS                    
      value:
        type: string
        required: false
        example: "2.2"

with annotation, it's working:

myname:
  type: string
  required: false   
  description: Nick Name
  example: "Activate fellow" 
versions:
  (ramltopojo.types):
    generateInlineArrayType: true
  type: array
  items:
    type: object
    properties:
      key:
        type: string
        required: false
        example: myownOS                    
      value:
        type: string
        required: false
        example: "2.2"  

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>com.company.project</groupId>
    <artifactId>Simulator</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
            <version>2.1.1</version>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.raml.jaxrs</groupId>
                <artifactId>raml-to-jaxrs-maven-plugin</artifactId>
                <version>3.0.7</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.raml.jaxrs</groupId>
                        <artifactId>feature-plugins</artifactId>
                        <version>3.0.5</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <ramlFile>${project.basedir}\src\main\resources\api.raml
                    </ramlFile>
                    <resourcePackage>com.project.company.resources</resourcePackage>
                    <modelPackage>com.project.company.model</modelPackage>
                    <supportPackage>com.project.company.support</supportPackage>
                    <outputDirectory>${project.basedir}/src/main/java</outputDirectory>
                    <jsonMapper>jackson2</jsonMapper>
                    <generateTypesWith>jsr303</generateTypesWith>
                    <jsonMapperConfiguration>
                        <includeAdditionalProperties>false</includeAdditionalProperties>
                    </jsonMapperConfiguration>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
rkrgarlapati commented 4 years ago

api.txt

Please rename the attached file extension to .raml

This is the file i am facing issue with type: object. If i use annotation it's working like charm. As soon as i remove annotation i get error.

For your reference i created a shorter raml file attached. Please refer complete pom.xml from my previous post.

jpbelang commented 4 years ago

I've tried your raml and I can't get it to work. Inline types for array item types have a bug in the parser that should I make your case work would break simpler examples like "something[]" and such.

Ok, here's where we are (considering the limitations in the parser). You can: use the annotation (that's what they are there for in raml, they have no semantic value vis a vis protocol). You can: make your item type non-inline. This could be a bit of a pain if you have many endpoints and will increase the number of visible types in your code.

The good news is that the next versions (of raml-for-jaxrs and raml-java-tool) is based on the AMF parser, which is much more rugged. I've checked and it would parse your type perfectly. But they aren't done yet.

jpbelang commented 4 years ago

Just for fun, next version generates:

public interface AAAAAAAAAA {
  String getMyname();

  void setMyname(String myname);

  VersionsType getVersions();

  void setVersions(VersionsType versions);

  Map<String, Object> getAdditionalProperties();

  void setAdditionalProperties(String key, Object value);

  class VersionsType extends ArrayList<VersionsType.ItemsType> {
    public interface ItemsType {
      String getKey();

      void setKey(String key);

      String getValue();

      void setValue(String value);

      Map<String, Object> getAdditionalProperties();

      void setAdditionalProperties(String key, Object value);
    }

    public static class ItemsTypeImpl implements ItemsType {
      private String key;

      private String value;

      private Map<String, Object> additionalProperties = new ExcludingMap();

      public String getKey() {
        return this.key;
      }

      public void setKey(String key) {
        this.key = key;
      }

      public String getValue() {
        return this.value;
      }

      public void setValue(String value) {
        this.value = value;
      }

      public Map<String, Object> getAdditionalProperties() {
        return additionalProperties;
      }

      public void setAdditionalProperties(String key, Object value) {
        this.additionalProperties.put(key, value);
      }
    }
  }
}
rkrgarlapati commented 4 years ago

Thanks for the update.

With this annotation i get similar output.

              (ramltopojo.types):
                generateInlineArrayType: true