Spring initiative investigation
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