Spring initiative investigation
- Natalia Zaitseva
MODKBEKBJ-46 - Getting issue details... STATUS DRAFT
Goal:
The main goal of the spike was investigation if the proposed plugin meets project initial requirements.
Initial requirements:
- for endpoints it has to generate interfaces or classes that could be extended to implement the necessary logic [MUST];
support !include directive in RAML files like below :
types: note: !include note.json noteCollection: !include noteCollection.json errors: !include raml-util/schemas/errors.schema
- support definition of a single element in collection as $ref
Investigation results:
Initial requirement:
for endpoints it has to generate interfaces or classes that could be extended to implement the necessary logic [MUST];
Result:
Pros: ability to create Controllers and Models from the raml file
The plugin provides several rules an ability to generate interfaces. To achiev this you have to specify the rule name in pom.xml file
<configuration> <rule>com.phoenixnap.oss.ramlplugin.raml2code.rules.Spring4ControllerInterfaceRule</rule> </configuration>
Here is the raml file which were used to test:
#%RAML 1.0 title: Drinks Services version: ${project.version} mediaType: application/json baseUri: / types: drink: type: object properties: type: type: string description: The drink type. name: type: string description: The drink name. drinkCollection: type: object properties: drinks: type: array items: drink drinkUpload: type: object properties: name: type : string healthCheck: type: object properties: timestamp: type: string status: type: string /drinks: description: Provides interaction with 'Drink' resource get: description: Retrieves a list of available drinks. responses: 200: body: application/json: type: drinkCollection 400: description: | The request sent to the server contains data which is not as expected e.g. incorrect drink type 404: description: | The requested resource was not found post: description: Creates a new drink. body: application/json: type: !include examples/postDrink.json responses: 201: body: application/json: type: drink /{drinkName}: uriParameters: drinkName: displayName: DrinkName description: | The name of the drink for info required: true type: string get: description: Retrieves details for a specific drink. responses: 200: body: application/json: type: drink 404: description: "Drink Name not found" body: text/plain: example: "Drink Name not found" 400: description: "Internal server error" body: text/plain: example: "Internal server error" put: description: Modify an existing drink. body: application/json: type: drinkUpload responses: 200: body: application/json: type: drinkUpload 400: description: "Bad request" body: text/plain: example: "Bad request" 404: description: "User not found" body: text/plain: example: "User not found" 500: description: "Internal server error" body: text/plain: example: "Internal server error" delete: description: Delete an existing drink. responses: 204: description: "No Content" body: text/plain: example: "No Content" 404: description: "Not Found" body: text/plain: example: "Not found" /healthCheck: description: Provides server health check get: description: Retrieves the server's health status. responses: 200: description: The health check item has been successfully retrieved. body: application/json: type: healthCheck 400: description: "Bad request" body: text/plain: example: "Bad request" 404: description: "Not found" body: text/plain: example: "Not found"
this are the Controllers generated by plugin:
/** * Provides interaction with 'Drink' resource * (Generated with springmvc-raml-parser v.2.0.4) * */ @RestController @Validated @RequestMapping(value = "/drinks", produces = "application/json") public interface DrinkController { /** * Retrieves a list of available drinks. * */ @RequestMapping(value = "", method = RequestMethod.GET) public ResponseEntity<DrinkCollection> getDrinks(); /** * Creates a new drink. * */ @RequestMapping(value = "", method = RequestMethod.POST) public ResponseEntity<Drink> createDrink( @javax.validation.Valid @org.springframework.web.bind.annotation.RequestBody CreateDrinkRequest createDrinkRequest); /** * Retrieves details for a specific drink. * */ @RequestMapping(value = "/{drinkName}", method = RequestMethod.GET) public ResponseEntity<Drink> getDrinkByName( @PathVariable String drinkName); /** * Modify an existing drink. * */ @RequestMapping(value = "/{drinkName}", method = RequestMethod.PUT) public ResponseEntity<DrinkUpload> updateDrinkByName( @PathVariable String drinkName, @javax.validation.Valid @org.springframework.web.bind.annotation.RequestBody DrinkUpload drinkUpload); /** * Delete an existing drink. * */ @RequestMapping(value = "/{drinkName}", method = RequestMethod.DELETE) public ResponseEntity<?> deleteDrinkByName( @PathVariable String drinkName); }
** * Provides server health check * (Generated with springmvc-raml-parser v.2.0.4) * */ @RestController @Validated @RequestMapping(value = "/healthCheck", produces = "application/json") public interface HealthCheckController { /** * Retrieves the server's health status. * */ @RequestMapping(value = "", method = RequestMethod.GET) public ResponseEntity<HealthCheck> getHealthCheck(); }
and Models
public class Drink implements Serializable { final static long serialVersionUID = 7968831422593218332L; /** * The drink type. * */ protected String type; /** * The drink name. * */ protected String name; /** * Creates a new Drink. * */ public Drink() { super(); } /** * Creates a new Drink. * */ public Drink(String type, String name) { super(); this.type = type; this.name = name; } /** * Returns the type. * * @return * type */ @NotNull public String getType() { return type; } /** * Set the type. * * @param type * the new type */ public void setType(String type) { this.type = type; } /** * Returns the name. * * @return * name */ @NotNull public String getName() { return name; } /** * Set the name. * * @param name * the new name */ public void setName(String name) { this.name = name; } public int hashCode() { return new HashCodeBuilder().append(type).append(name).toHashCode(); } public boolean equals(Object other) { if (other == null) { return false; } if (other == this) { return true; } if (this.getClass()!= other.getClass()) { return false; } Drink otherObject = ((Drink) other); return new EqualsBuilder().append(type, otherObject.type).append(name, otherObject.name).isEquals(); } public String toString() { return new ToStringBuilder(this).append("type", type).append("name", name).toString(); } }
public class HealthCheck implements Serializable { final static long serialVersionUID = 8277845917257136452L; protected String timestamp; protected String status; /** * Creates a new HealthCheck. * */ public HealthCheck() { super(); } /** * Creates a new HealthCheck. * */ public HealthCheck(String timestamp, String status) { super(); this.timestamp = timestamp; this.status = status; } /** * Returns the timestamp. * * @return * timestamp */ @NotNull public String getTimestamp() { return timestamp; } /** * Set the timestamp. * * @param timestamp * the new timestamp */ public void setTimestamp(String timestamp) { this.timestamp = timestamp; } /** * Returns the status. * * @return * status */ @NotNull public String getStatus() { return status; } /** * Set the status. * * @param status * the new status */ public void setStatus(String status) { this.status = status; } public int hashCode() { return new HashCodeBuilder().append(timestamp).append(status).toHashCode(); } public boolean equals(Object other) { if (other == null) { return false; } if (other == this) { return true; } if (this.getClass()!= other.getClass()) { return false; } HealthCheck otherObject = ((HealthCheck) other); return new EqualsBuilder().append(timestamp, otherObject.timestamp).append(status, otherObject.status).isEquals(); } public String toString() { return new ToStringBuilder(this).append("timestamp", timestamp).append("status", status).toString(); } }
Summary
Pros: ability to create Controllers and Models from the raml file
Cons: properties do not have Jackson annotations like
@JsonProperty("customerId") @JsonPropertyDescription("Customer ID using the KB") @NotNull private String customerId;
- Rules description can be found here https://github.com/phoenixnap/springmvc-raml-plugin#rule
- Sample module can be found here. The pom file which uses this rule can be found here