phoenixnap / springmvc-raml-plugin

Spring MVC - RAML Spec Synchroniser Plugin. A Maven plugin designed to Generate Server & Client code in Spring from a RAML API descriptor and conversely, a RAML API document from the SpringMVC Server implementation.
Apache License 2.0
136 stars 84 forks source link

Using specific rules for client/server generation #230

Closed sasagonz closed 6 years ago

sasagonz commented 6 years ago

Maybe this is not an issue but an enhancement. The thing is that we want to generate the FeignClient and also the server (controller) using for example Spring4ControllerInterfaceRule or Spring4ControllerDecoratorRule. But if I'm not wrong, only a single rule can be used for code generation so the only way to do it is having two separate code generation, one for the server and another one for the client. This makes impossible to package all generated code into a single jar or dependency: we have to generate server code where it will be used and again, generate client code in a different place/project (model classes are generated twice)

stojsavljevic commented 6 years ago

Hi @sasagonz

Thanks for getting in touch.

Yes, you can only use a single rule. And TBH, I don't see much logic in your use case - packaging server and client code together. Those two have to packaged separately.

In some other use cases it might make sense to use two rules together - e.g. for making 'regular' and Feign clients so consumer can have a choice which one to use.

sasagonz commented 6 years ago

Hi @stojsavljevic , many thanks for your response.

The thing is that generated code for client and server doesn't contain any business logic. They can be only interfaces. So in my opinion, we are not mixing anything, only providing all generated code from the specification (model, client interface and server interface) in the same package.

If not, you have to use the plugin whatever place you want to use RAML spec, instead of using a simple maven dependency containing everything already generated. By this way, you would be isolating RAML generation from the usage of the classes, which in my opinion is desirable.

If the spec changes, then a new version will be generated for the related artifact. Then, once updated the dependency, you only have to change your code to implement new stuff.

Not sure if this can be achieved only with maven, I mean, generating two different artifacts from the same RAML spec, one with the client and another one with the server.

stojsavljevic commented 6 years ago

Is there a 'maven' way to invoke the plugin twice (using two different configurations)? I believe that we would need separate configs since we would need (at least) different packages for different types of code (e.g. client vs server).

Theoretically, we could make a rule(s) that encapsulates few other rules. But I would like to do it 'maven' way if possible..

claytontabone commented 6 years ago

Yes there is. In maven plugins there's always the global configuration that is contained in the top level element right next to the groupId and artifactId. Then there's additional configuration which can be specified within an execution. This is an example of how we're using the client and controller generator all within the same pluginManagement snippet. Some of the global config has been stripped for the sake of readability.

<plugin>
    <groupId>com.phoenixnap.oss</groupId>
    <artifactId>springmvc-raml-plugin</artifactId>
    <version>${springmvc.raml.plugin.version}</version>
    <configuration>
        <ramlPath>${raml-path}</ramlPath>
        <checkForResourceExistence>false</checkForResourceExistence>
        ...
    </configuration>
    <executions>
        <execution>
            <id>generate-springmvc-client</id>
            <phase>generate-sources</phase>
            <goals>
                <goal>generate-springmvc-endpoints</goal>
            </goals>
            <configuration>
                <rule>com.phoenixnap.oss.ramlapisync.generation.rules.Spring4RestTemplateClientRule</rule>
                <ruleConfiguration>
                    <baseUrlConfigurationPath>${url-field-annotation-path}</baseUrlConfigurationPath>
                    <restTemplateQualifierBeanName>${raml.plugin.rest-client-qualifier}</restTemplateQualifierBeanName>
                </ruleConfiguration>
            </configuration>
        </execution>
        <execution>
            <id>generate-springmvc-controllers</id>
            <phase>generate-sources</phase>
            <goals>
                <goal>generate-springmvc-endpoints</goal>
            </goals>
            <configuration>
                <rule>com.phoenixnap.oss.ramlapisync.generation.rules.Spring4ControllerDecoratorRule</rule>
            </configuration>
        </execution>
    </executions>
</plugin>
stojsavljevic commented 6 years ago

Thanks a lot @claytontabone That is what I was looking for.

@sasagonz I hope you can use the solution @claytontabone provided.

Another way to achieve something similar from the plugin would be to change the way rules and rules config are loaded. E.g. rules and their configs become a map and the plugin executes rules with respective rule config one by one. But even in that case the rest of the configuration will be shared. So @claytontabone's solution is more flexible since we can have separate configurations for each execution.

@sasagonz reopen this issue if you feel there is something more that can be discussed/improved.

sasagonz commented 6 years ago

Sorry for the late response but many thanks! Yes I think that multiple executions solve my problem.