DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Spring Boot - How To Use Native SQL Queries | Restful Web Services
  • How to Consume REST Web Service (GET/POST) in Java 11 or Above
  • Building REST API Backend Easily With Ballerina Language
  • User-Friendly API Publishing and Testing With Retrofit

Trending

  • How to Submit a Post to DZone
  • DZone's Article Submission Guidelines
  • Enforcing Architecture With ArchUnit in Java
  • The End of “Good Enough Agile”
  1. DZone
  2. Data Engineering
  3. Databases
  4. Creating a Simple Java REST Service Using HTTP-RPC

Creating a Simple Java REST Service Using HTTP-RPC

We take a look at how to implement a Java-based web service using the HTTP-RPC framework. Read on to find out how and for some example code.

By 
Greg Brown user avatar
Greg Brown
·
Sep. 08, 16 · Tutorial
Likes (7)
Comment
Save
Tweet
Share
13.0K Views

Join the DZone community and get the full member experience.

Join For Free


NOTE 10/22/2016 Support for implementing REST services was dropped from the HTTP-RPC project in version 3.6. However, many of the features described in this article have been migrated to the JTemplate project.

HTTP-RPC is an open-source framework for simplifying development of REST applications. It allows developers to create and access web services using a convenient, RPC-like metaphor while preserving fundamental REST principles such as statelessness and uniform resource access. The project currently includes support for implementing REST services in Java and consuming services in Java, Objective-C/Swift, or JavaScript.

HTTP-RPC services are accessed by applying an HTTP verb such as GET or POST to a target resource. Arguments are provided either via the query string or in the request body, like an HTML form. Results are generally returned as JSON, although operations that do not return a value are also supported.

For example, the following request might retrieve the sum of two numbers, whose values are specified by the a and b query arguments:

GET /math/sum?a=2&b=4

The service would return the value 6 in response.

This article provides an overview of how HTTP-RPC can be used to create a simple REST service.

WebService Class

WebService is an abstract base class for HTTP-RPC web services. Service operations are defined by adding public methods to a concrete service implementation.

The @RPC annotation is used to flag a method as remotely accessible. This annotation associates an HTTP verb and a resource path with the method. All public annotated methods automatically become available for remote execution when the service is published.

For example, the following class might be used to implement the simple addition operation discussed in the previous section:

public class MathService extends WebService {
    @RPC(method="GET", path="sum")
    public double getSum(double a, double b) {
        return a + b;
    }
}

Arguments may be any numeric or boolean type,  String ,  java.net.URL , or  java.util.List.  URL arguments represent binary content and can only be used with POST requests. List arguments represent multi-value parameters. They may be used with any request type, but elements must be a supported simple type; e.g. List<Double> or List<URL>.

Methods may return any numeric or boolean type, CharSequence, java.util.List or java.util.Map. Results are mapped to their JSON equivalents as follows:

  • numeric primitive/ Number: number
  • boolean/Boolean: true/false
  • CharSequence: string
  • java.util.List: array
  • java.util.Map: object

Methods may also return void to indicate that they do not produce a value.

List and Map types are not required to support random access; iterability is sufficient. This allows service implementations to stream collection data rather than buffering it in memory before it is written. Additionally, collection types that implement the AutoCloseable interface will be automatically closed after their contents have been written to the output stream, ensuring that system resources are not leaked.

ProductService Class

The example service provides CRUD (“create, read, update, and delete”) access to a simple product database. It extends WebService and provides a collection of methods for managing the database’s content:

public class ProductService extends WebService {
    ...
}

The underlying product data is stored in the Products table from the BIRT sample database:

CREATE TABLE Products (
  productCode VARCHAR(50) NOT NULL,
  productName VARCHAR(70) NOT NULL,
  productLine VARCHAR(50) NOT NULL,
  productScale VARCHAR(10) NOT NULL,
  productVendor VARCHAR(50) NOT NULL,
  productDescription TEXT NOT NULL,
  quantityInStock SMALLINT NOT NULL,
  buyPrice DOUBLE NOT NULL,
  MSRP DOUBLE NOT NULL,
  PRIMARY KEY (productCode)
);

GET

The getProducts() method returns the product list. It is associated with the HTTP GET operation:

@RPC(method="GET", path="products")
public ResultSetAdapter getProducts() throws SQLException {
    Statement statement = getConnection().createStatement();

    return new ResultSetAdapter(statement.executeQuery("SELECT * FROM Products"));
}

The ResultSetAdapter class allows the result of a SQL query to be efficiently returned from a service method. This class implements the List interface and makes each row in a JDBC result set appear as an instance of Map, rendering the data suitable for serialization to JSON. It also implements AutoCloseable, to ensure that the underlying result set is closed once all of the response data has been written.

Further, ResultSetAdapter is forward-scrolling only; its contents are not accessible via the get() and size() methods. This allows query results to be returned to the caller directly, without any intermediate buffering.

A response produced by the method might look something like this, where each object in the array represents a row from the result set:

[
  {
    "productCode": "S10_1678",
    "productName": "1969 Harley Davidson Ultimate Chopper",
    "productLine": "Motorcycles",
    "productScale": "1:10",
    "productVendor": "Min Lin Diecast",
    "productDescription": "This replica features working kickstand...",
    "quantityInStock": 7932,
    "buyPrice": 48.81,
    "MSRP": 95.7
  },
  ...
]

POST

The addProduct() method is associated with the HTTP POST operation. It inserts a new row into the Products table. Product information is provided by the method arguments:

@RPC(method="POST", path="products")
public void addProduct(String productCode, String productName,
    String productLine, String productScale, String productVendor, String productDescription,
    int quantityInStock, double buyPrice, double MSRP) throws SQLException {
    String sql = "INSERT INTO Products (productCode, productName,"
        + " productLine, productScale, productVendor, productDescription,"
        + " quantityInStock, buyPrice, MSRP) "
        + "VALUES (:productCode, :productName,"
        + " :productLine, :productScale, :productVendor, :productDescription,"
        + " :quantityInStock, :buyPrice, :MSRP)";

    Parameters parameters = Parameters.parse(sql);
    PreparedStatement statement = getConnection().prepareStatement(parameters.getSQL());

    parameters.apply(statement, mapOf(
        entry("productCode", productCode),
        entry("productName", productName),
        entry("productLine", productLine),
        entry("productScale", productScale),
        entry("productVendor", productVendor),
        entry("productDescription", productDescription),
        entry("quantityInStock", quantityInStock),
        entry("buyPrice", buyPrice),
        entry("MSRP", MSRP)
    ));

    statement.execute();
}

The Parameters class provides a means for executing prepared statements using JPQL-like named parameter values rather than indexed arguments. The Parameters#getSQL() method returns the parsed SQL in standard JDBC syntax. This value is used to create the actual prepared statement.

mapOf() and  entry()  are static convenience methods provided by the WebService class for simplifying map creation.

PUT

The updateProduct() method is associated with the HTTP PUT operation. It allows a caller to update the inventory level of a given product:

@RPC(method="PUT", path="products")
public void updateProduct(String productCode, int quantityInStock) throws SQLException {
    String sql = "UPDATE Products SET quantityInStock = :quantityInStock WHERE productCode = :productCode";

    Parameters parameters = Parameters.parse(sql);
    PreparedStatement statement = getConnection().prepareStatement(parameters.getSQL());

    parameters.apply(statement, mapOf(
        entry("productCode", productCode),
        entry("quantityInStock", quantityInStock)
    ));

    statement.execute();
}

This method could be overloaded to provide additional update capabilities, such as changing a price or product description.

DELETE

Finally, deleteProduct() is associated with the HTTP DELETE method. It simply deletes a row from the Products table:

@RPC(method="DELETE", path="products")
public void deleteProduct(String productCode) throws SQLException {
    String sql = "DELETE FROM Products WHERE productCode = :productCode";

    Parameters parameters = Parameters.parse(sql);
    PreparedStatement statement = getConnection().prepareStatement(parameters.getSQL());

    parameters.apply(statement, mapOf(entry("productCode", productCode)));

    statement.execute();
}

More Information

This article introduced the HTTP-RPC framework and provided an example of how it can be used to create a simple REST service. The complete source code for the sample service can be found here.

The latest version of HTTP-RPC can be downloaded here. For more information, see the project README.

REST Web Protocols Web Service Database Java (programming language)

Published at DZone with permission of Greg Brown, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Spring Boot - How To Use Native SQL Queries | Restful Web Services
  • How to Consume REST Web Service (GET/POST) in Java 11 or Above
  • Building REST API Backend Easily With Ballerina Language
  • User-Friendly API Publishing and Testing With Retrofit

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!