Reuse your RAML fragments inside your Spring Java projects

karim Djaafar
Another Integration Blog
4 min readFeb 12, 2024

Sometimes you need to mix your MuleSoft integration with your Java development projects and choose the best of the two worlds.

In this post I will explain how to use a hybrid approach using your RAML specifications and your Spring MVC project using a useful plugin Spring MVC-RAML Plugin. This is a maven plugin for a contract-first approach for projects using the Spring MVC Framework which generates Java code from your API contract with the Spring Framework and afterwards lets you add your own implementation code.

Let’s see how…

Prerequisites

  • Anypoint Designer to design your RAML specification and fragments
  • Maven installation
  • springmvc-raml-plugin available here
  • Spring Boot

Creating your RAML specification

I will create a simple RAML specification for a simple todo application.

Here’s the datatype associated and the corresponding API api.raml:

#%RAML 1.0 DataType
displayName: Todo

properties:
id?:
type: string
example: "1"
task:
type: string
example: "design"
priority:
type: string
example: "1"
#%RAML 1.0
---
title: RAML SpringBoot TODOs API
version: v1
mediaType: application/json

types:
todo: !include data-types/todo.raml

/todos:
description: "The Todos resource."
get:
description: "Returns a list of todos."
responses:
200:
body:
application/json:
example: |
[
{ "id": "1", "task": "Design the API", "priority": "1" },
{ "id": "2", "task": "Generate the interfaces", "priority": "2" }
]
post:
description: "Generate a new todo."
body:
application/json:
type: todo
example: |
{ "task": "Design the API", "priority": 1 }
responses:
201:
description: "Todo created"
400:
description: "Can't create Todo from provided entity"
/{id}:
uriParameters:
id:
type: string
get:
description: "Return the todo with given id."
responses:
200:
body:
application/json:
type: todo
example: |
{ "id": "1", "task": "Design the API", "priority": "1" }
404:
description: "Todo with provided id not found"

Here is an extract of the configuration of the POM Maven project which contains the Spring MVC-RAML Plugin:

<plugin>
<groupId>com.phoenixnap.oss</groupId>
<artifactId>springmvc-raml-plugin</artifactId>
<version>2.0.5</version>
<configuration>
<ramlPath>src/main/resources/api.raml</ramlPath>
<outputRelativePath>/src/main/java</outputRelativePath>
<addTimestampFolder>false</addTimestampFolder>
<basePackage>com.example.ramlspringboot.api</basePackage>
<baseUri>/api</baseUri>
<generateUnreferencedObjects>true</generateUnreferencedObjects>
<generationConfig>
<includeAdditionalProperties>false</includeAdditionalProperties>
</generationConfig>
<seperateMethodsByContentType>false</seperateMethodsByContentType>
<rule>com.phoenixnap.oss.ramlplugin.raml2code.rules.Spring4ControllerStubRule</rule>
<ruleConfiguration>
</ruleConfiguration>
</configuration>
<executions>
<execution>
<id>generate-springmvc-endpoints</id>
<phase>compile</phase>
<goals>
<goal>generate-springmvc-endpoints</goal>
</goals>
</execution>
</executions>
</plugin>

Here some details about the plugin configuration, you can have access to the detailed documentation on the official page of the Maven plugin.

<ramlPath> allows us to configure the path to the RAML file that defines the API specs.

<outputRelativePath> will be the path to the directory where the API contract will be generated. Here you can also see we have <basePackage> to define the package for generated Java classes.

You will notice that your RAML API needs to be filled inside the directory src/main/resources/ (see ramlPath tag).

Let’s launch the plugin by launching the maven package command

mvn clean package

The resulting command generates the following code inside src/main/java:

Todo.java (The Spring Data Model generated from the RAML fragment todo.raml):


public class Todo implements Serializable
{

final static long serialVersionUID = -3245872322723690091L;
protected String id;
protected String task;
protected String priority;

/**
* Creates a new Todo.
*
*/
public Todo() {
super();
}

/**
* Creates a new Todo.
*
*/
public Todo(String id, String task, String priority) {
super();
this.id = id;
this.task = task;
this.priority = priority;
}

/**
* Returns the id.
*
* @return
* id
*/
public String getId() {
return id;
}

/**
* Set the id.
*
* @param id
* the new id
*/
public void setId(String id) {
this.id = id;
}

/**
* Returns the task.
*
* @return
* task
*/
@NotNull
public String getTask() {
return task;
}

/**
* Set the task.
*
* @param task
* the new task
*/
public void setTask(String task) {
this.task = task;
}

/**
* Returns the priority.
*
* @return
* priority
*/
@NotNull
public String getPriority() {
return priority;
}

/**
* Set the priority.
*
* @param priority
* the new priority
*/
public void setPriority(String priority) {
this.priority = priority;
}

public int hashCode() {
return new HashCodeBuilder().append(id).append(task).append(priority).toHashCode();
}

public boolean equals(Object other) {
if (other == null) {
return false;
}
if (other == this) {
return true;
}
if (this.getClass()!= other.getClass()) {
return false;
}
Todo otherObject = ((Todo) other);
return new EqualsBuilder().append(id, otherObject.id).append(task, otherObject.task).append(priority, otherObject.priority).isEquals();
}

public String toString() {
return new ToStringBuilder(this).append("id", id).append("task", task).append("priority", priority).toString();
}

}

TodoController, the corresponding Spring Controller:

/**
* The Todos resource.
* (Generated with springmvc-raml-parser v.2.0.5)
*
*/
@RestController
@RequestMapping(value = "/api/todos", produces = "application/json")
@Validated
public class TodoController {


/**
* Returns a list of todos.
*
*/
@RequestMapping(value = "", method = RequestMethod.GET)
public ResponseEntity<?> getObject() {
return null; //TODO Autogenerated Method Stub. Implement me please.
}

/**
* Generate a new todo.
*
*/
@RequestMapping(value = "", method = RequestMethod.POST)
public ResponseEntity<?> createTodo(
@Valid
@RequestBody
Todo todo) {
return null; //TODO Autogenerated Method Stub. Implement me please.
}

/**
* Return the todo with given id.
*
*/
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<Todo> getTodoById(
@PathVariable
String id) {
return null; //TODO Autogenerated Method Stub. Implement me please.
}

}
package com.example.ramlspringboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RamlSpringbootApplication {

public static void main(String[] args) {
SpringApplication.run(RamlSpringbootApplication.class, args);
}

}

As you can notice, the Spring MVC-RAML Plugin generates an API contract with the Spring Framework and you just have to add your own implementation code like below to implement the GET method (don’t forget to comment the plugin section after in order to not override your change by the plugin):

 @RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<Todo> getTodoById(
@PathVariable
String id) {

todos.add(new Todo("1" , "Design the API", "1" ));

Optional<Todo> todo = todos.stream().filter(t -> t.getId().equals(id)).findFirst();
return ResponseEntity.<Todo>ok().body(todo.get());
}

Now we can launch our project and launch Postman to test our API with the help of our Spring MVC-RAML Plugin:

% mvn spring-boot:run

To conclude

This Spring MVC-RAML Plugin help to bridge the gap between the world of RAML and Java projects and gives you a strong base for your integration projects.

--

--