Search code examples
jsonrestmavenjakarta-eerestlet

Restlet accepts JSON input from client and respond with POST


I am writing a program which accepts a JSON input with the following format from client:

{
    "campaignID": 1,
    "clientID": 1,
    "pmapID": 1,
    "ward": "1-Bedded (Private)",
    "age": 20,
    "attr1": "EXA1(A)",
    "attr2": "EO",
    "attr3": "11/02/2012",
    "attr4": "SIN",
    "attr5": "N",
    "attr6": "Y"
}

I'd like to read the JSON input, save all the attributes into local variables (String, int, ...) and finally respond with a POST("JSON") which will return a single float/double value (e.g. {"PMC": 30.12} ).

public class RestletApplication extends Application
{
    @Override
    public synchronized Restlet createInboundRoot()
    {
        Router router = new Router(getContext());
        router.attach("/pmc/calculate", PMCResource.class);
        return router;
    }
}

I have written the function so far but am lost how to read the JSON input:

 public class PMCResource extends ServerResource
    {   
        @Post("JSON")
        public Representation post(Representation entity) throws ResourceException {
            try {
                if (entity.getMediaType().isCompatible(MediaType.APPLICATION_JSON))
                {
                    // Read JSON file and parse onto local variables

                    // Do processing & return a float value

                }
            } catch (Exception e) {
                getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
            }
        }
    }

5 May 2016 - Edited the resource class

// Imports

public class PMCResource extends ServerResource
{
    static Logger LOGGER = LoggerFactory.getLogger(PMCResource.class);

    @Override
    @Post("JSON")
    public Representation post(Representation entity) throws ResourceException
    {
        PMCMatrixDAO matrix = new PMCMatrixDAOImpl();
        JsonObjectBuilder response = Json.createObjectBuilder();

        try
        {
            if (entity.getMediaType().isCompatible(MediaType.APPLICATION_JSON))
            {
                InputStream is = new FileInputStream(getClass().getResource("/input.json").getFile());

                try (JsonReader reader = Json.createReader(is)) {
                    JsonObject obj = reader.readObject();
                    double result = matrix.calculatePMC(obj);
                    response.add("PMC", result);
                }
            }

        } catch (Exception e) {
            getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
        }

        return new StringRepresentation(response.build().toString());
    }
}

The Implementation class

public class PMCMatrixDAOImpl implements PMCMatrixDAO
{       
    public double calculatePMC(JsonObject obj) 
    {   
        int campaignID = obj.getInt("campaignID");
        int clientID = obj.getInt("clientID");
        int pmapID = obj.getInt("pmapID");
        String ward = obj.getString("ward");
        int age = obj.getInt("age");
        String attr1 = obj.getString("attr1");
        String attr2 = obj.getString("attr2");
        String attr3 = obj.getString("attr3");
        String attr4 = obj.getString("attr4");
        String attr5 = obj.getString("attr5");
        String attr6 = obj.getString("attr6");

        // SQL processing
        double dPMC = sqlQueryCall(...);

        return dPMC;
    }
}

Solution

  • In order to parse your JSON file, and since you're using Maven I'll assume you have it on your classpath, you can do it using a FileInputStream or a FileReader. So, assuming your JSON file is called input.json and it is on the root of your src/main/resources folder, you can load it the following way:

    • using a FileInputStream:

      InputStream is = new FileInputStream(getClass().getResource("/input.json").getFile());
      
      try (JsonReader reader = Json.createReader(is)) {
          // file processing is done here
      }
      
    • using a FileReader:

      FileReader fr = new FileReader(getClass().getResource("/input.json").getFile());
      
      try (JsonReader reader = Json.createReader(fr)) {
          // file processing is done here
      }
      

    Ok, so now that we have our JsonReader created, lets retrieve the contents of our JSON file:

    InputStream is = new FileInputStream(getClass().getResource("/input.json").getFile());
    
    try (JsonReader reader = Json.createReader(is)) {
        JsonObject obj = reader.readObject();
    
        // retrieve JSON contents
        int campaingID = obj.getInt("campaignID");
        int clientID = obj.getInt("clientID");
        int pmapID = obj.getInt("pmapID");
        String ward = obj.getString("ward");
        int age = obj.getInt("age");
        String attr1 = obj.getString("attr1");
        String attr2 = obj.getString("attr2");
        String attr3 = obj.getString("attr3");
        String attr4 = obj.getString("attr4");
        String attr5 = obj.getString("attr5");
        String attr6 = obj.getString("attr6");
    }
    

    As an alternative of having several variables across your method, you could create a simple POJO, having those variable as attributes, and then populate it using Jackson:

    public class MyPojo {
    
        private int campaingID;
        private int clientID;
        private int pmapID;
        private String ward;
        private int age;
        private String attr1;
        private String attr2;
        private String attr3;
        private String attr4;
        private String attr5;
        private String attr6;
    
        // getters & setters
    }
    

    Finally, in order to send the response back to your client, you could do this:

    JsonObject response = Json.createObjectBuilder().add("PMC", 30.12).build();
    
    return new StringRepresentation(response.toString());
    

    So, the entire solution could look like this:

    @Override
    @Post("JSON")
    public Representation post(Representation entity) throws ResourceException {
        JsonObjectBuilder response = Json.createObjectBuilder();
    
        try {
            if (entity.getMediaType().isCompatible(MediaType.APPLICATION_JSON)) {
                InputStream is = new FileInputStream(getClass().getResource("/input.json").getFile());
    
                try (JsonReader reader = Json.createReader(is)) {
                    JsonObject obj = reader.readObject();
    
                    // retrieve JSON contents
                    int campaingID = obj.getInt("campaignID");
                    int clientID = obj.getInt("clientID");
                    int pmapID = obj.getInt("pmapID");
                    String ward = obj.getString("ward");
                    int age = obj.getInt("age");
                    String attr1 = obj.getString("attr1");
                    String attr2 = obj.getString("attr2");
                    String attr3 = obj.getString("attr3");
                    String attr4 = obj.getString("attr4");
                    String attr5 = obj.getString("attr5");
                    String attr6 = obj.getString("attr6");
                }
    
                // Do processing & execute your SQL query call here
                double result = sqlQueryCall(...);
    
                response.add("PMC", result);
            }
        } catch (Exception e) {
            getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
        }
    
        return new StringRepresentation(response.build().toString());
    }
    

    As a side note, the JsonReader class belongs to the Java EE API which, for compiling purposes it's okay. Although, for running purposes, one requires the declaration of a JSON-API implementation dependency in one's Maven project. For instance:

    <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.json</artifactId>
        <version>1.0.4</version>
    </dependency>
    

    Below is the way one can communicate to the REST web service through a client:

    1. Create a simple POJO object that will contain the information to send, as mentioned above (MyPojo).

    2. Your REST service would look something like this:

      public class PMCResource extends ServerResource {
      
          static Logger LOGGER = Logger.getLogger(RestletMain.class.getName());
      
          @Post("JSON")
          public Representation post(MyPojo entity) throws ResourceException {
              PMCMatrixDAO matrix = new PMCMatrixDAOImpl();
              JsonObjectBuilder response = Json.createObjectBuilder();
      
              try {
                  double result = matrix.calculatePMC(entity);
                  response.add("PMC", result);
              } catch (Exception e) {
                  getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
              }
      
              return new StringRepresentation(response.build().toString());
          }
      }
      
    3. Modify your PMCMatrixDAOImpl in order to process your POJO:

      public double calculatePMC(MyPojo pojo) {
          (...)
      }
      
    4. Create a client that allows you to test your REST service:

      public class PMCResourceMain {
      
          public static void main(String[] args) {
              // take into account the context-root, if exists, and path to your REST service
              ClientResource resource = new ClientResource("http://<host>:<port>");
      
              MyPojo myPojo = new MyPojo();
              myPojo.setCampaingID(1);
              myPojo.setClientID(1);
              myPojo.setPmapID(1);
              myPojo.setWard("1-Bedded (Private)");
              myPojo.setAge(20);
              myPojo.setAttr1("EXA1(A)");
              myPojo.setAttr2("EO");
              myPojo.setAttr3("11/02/2012");
              myPojo.setAttr4("SIN");
              myPojo.setAttr5("N");
              myPojo.setAttr6("Y");
      
              try {
                  resource.post(myPojo, MediaType.APPLICATION_JSON).write(System.out);
              } catch (ResourceException | IOException e) {
                  e.printStackTrace();
              }
          }
      }
      

    Full Restlet documentation can be found here.