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:

  1. for endpoints it has to generate interfaces or classes that could be extended to implement the necessary logic [MUST];
  2. support !include directive in RAML files like below :

    types:
    
      note: !include note.json
      noteCollection: !include noteCollection.json
      errors: !include raml-util/schemas/errors.schema
  3. support definition of a single element in collection as $ref


Investigation results:

Initial requirement:

  1. 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: 

 api.raml
#%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:

 Click here to expand...
DrinkController
/**
 * 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);

}


HealthCheckController
**
 * 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

 Click here to expand...
Drink
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();
    }

}


HealthCheck
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;