Vern Jensen
Vern Jensen

Reputation: 3560

Returning JSON from RESTful Java server code?

I've inherited a web project that a contractor started. I and my coworkers are unfamiliar with the technology used, and have a number of questions. From what we can tell, this appears to be some sort of RESTful Java server code, but my understanding is there are lots of different types of Java RESTful services. Which one is this? Specific questions:

1) Where can we read more (particularly introductory information) about this specific service?

2) The code creates and returns a JSON through some kind of "magic"... I merely return a model class (code below) that has getter and setter methods for its fields, and it's automagically converted into a JSON. I'd like to learn more about how this is done automagically.

3) We already have some code that creates a JSON. We need to return this using this framework. If I already have a JSON, how do I return that? I tried something like this:

String testJSON = "{\"menu\": {\"id\": \"file\", \"value\": \"Hello there\"}}"; return testJSON;

instead of returning a model object with getters/setters, but this returns a literal text string, not a JSON. Is there a way to return an actual JSON that's already a JSON string, and have it be sent as a JSON?

You don't have to be able to answer all of the questions above. Any/all pointers in a helpful direction appreciated!

CODE

First, the view controller that returns the JSON:

package com.aimcloud.server;
import com.aimcloud.util.MySqlConnection;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.FormParam;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.aimcloud.models.SubscriptionTierModel;

@Path("subscription_tier")
public class SubscriptionTierController
{
        // this method will return a list of subscription_tier table entries that are currently active
    @GET
    @Produces({ MediaType.APPLICATION_JSON })
    public String/*ArrayList<SubscriptionTierModel>*/ getSubscriptionTiers(@QueryParam("includeActiveOnly") Boolean includeActiveOnly)
    {       
        MySqlConnection mysql = MySqlConnection.getConnection();
        ArrayList<SubscriptionTierModel> subscriptionTierArray = new ArrayList<SubscriptionTierModel>();
        String queryString;

        if (includeActiveOnly)
            queryString = "SELECT * FROM subscription_tier WHERE active=1";
        else
            queryString = "SELECT * FROM subscription_tier";

        List<Map<String, Object>> resultList = mysql.query(queryString, null);

        for (Map<String, Object> subscriptionRow : resultList)
            subscriptionTierArray.add( new SubscriptionTierModel(subscriptionRow) );

    //  String testJSON = "{\"menu\": {\"id\": \"file\", \"value\": \"Hello there\"}}";
    //  return testJSON;

        return subscriptionTierArray;
    }
}

Next, the model the code above returns:

package com.aimcloud.models;
// NOTE this does NOT import Globals
import java.sql.Types;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.json.JSONObject;
import com.aimcloud.util.LoggingUtils;

public class SubscriptionTierModel extends ModelPrototype
{
    private String name;
    private Integer num_studies;
    private Integer cost_viewing;
    private Integer cost_processing;
    private Integer active;

    protected void setupFields()
    {
        this.fields.add("name");
        this.fields.add("num_studies");
        this.fields.add("cost_viewing");
        this.fields.add("cost_processing");
        this.fields.add("active");
    }

    public SubscriptionTierModel()
    {
        super("subscription");
        this.setupFields();
    }

    public SubscriptionTierModel(Map<String, Object> map)
    {
        super("subscription");
        this.setupFields();
        this.initFromMap(map);
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public void setNum_Studies(Integer num_studies) {
        this.num_studies = num_studies;
    }

    public Integer getNum_studies() {
        return this.num_studies;
    }

    public void setCost_viewing(Integer cost_viewing) {
        this.cost_viewing = cost_viewing;
    }

    public Integer getCost_viewing() {
        return this.cost_viewing;
    }

    public void setCost_processing(Integer cost_processing) {
        this.cost_processing = cost_processing;
    }

    public Integer getCost_processing() {
        return this.cost_processing;
    }

    public void setActive(Integer active) {
        this.active = active;
    }

    public Integer getActive() {
        return this.active;
    }
}


public abstract class ModelPrototype {
    protected MySqlConnection mysql;

    protected ArrayList<String> fields;
    protected String table;
    protected Integer id = null;

    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    abstract protected void setupFields();

    public ModelPrototype() {
        mysql = MySqlConnection.getConnection();
        this.fields = new ArrayList<String>();
        this.fields.add("id");
    }

    public void initFromDbResult(List<Map<String, Object>> result) {
        if (result.size() >= 1)
        {
            Map<String, Object> userRow = result.get(0);
            this.initFromMap(userRow);

            if (result.size() > 1)
            {
            Thread.dumpStack();
            }
        } 
        else 
        {
            throw new WebApplicationException(ServerUtils.generateResponse(Response.Status.NOT_FOUND, "resource not found"));
        }
    }

    protected void initFromMap(Map<String, Object> map) {
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            Object value = entry.getValue();
            // LoggingUtils.log(entry.getKey() + " " + entry.getValue().toString());
            if (value != null && this.fields.contains(entry.getKey())) {
                this.setField(entry.getKey(), value);
            }
        }
    }

....

Upvotes: 2

Views: 6627

Answers (2)

techuser soma
techuser soma

Reputation: 4877

1) Where can we read more (particularly introductory information) about this specific service?

This is a RESTful service that uses basic jax-rs annotations to build the service. I suggest looking at a tutorial like "REST using jersey" or "REST using CXF".

2) The code creates and returns a JSON through some kind of "magic"...

The restful framework used usually takes care of this. @Produces({ MediaType.APPLICATION_JSON }) annotation indicates the framework to do this conversion.This will be defined somewhere in the configuration. Check the spring config files if you are using spring to define the beans. Usually a mapper or a provider will be defined that converts the object to json.

3) We already have some code that creates a JSON. We need to return this using this framework. If I already have a JSON, how do I return that? I tried something like this:

If you already have a json just return that json from the method. Remember to still have the @Produces({ MediaType.APPLICATION_JSON }) annotation on the method.

but this returns a literal text string, not a JSON

A json is a string. That is what you will see in the response, unless you deserialize it back to an object.

Upvotes: 3

EJK
EJK

Reputation: 12527

I suggest you read up on JAX-RS, the Java specification for RESTful web services. All of the "javax.ws.rs.*" classes/annotations come from JAX-RS

As JAX-RS, is just a specification, there needs to be something that implements the spec. There is probably a third-party, JAX-RS component that is used to run this service. Jersey in one popular implementation. Apache CXF is another.

Now back to JAX-RS. When you read up on this, you will see that the annotations on your class determine the REST characteristics of your service. For example,

@Path("subscription_tier")

defines your class as the resource with URI BASE_PATH/subscription_tier, where BASE_PATH is propbably defined in a configuration file for your web service framework.

As for how the objects are "automagically" converted into a JSON response: that is the role of the web service framework as well. It probably uses some kind of standard object-to-JSON mapping to accomplish this. (I have worked with CXF and XML resources. In that case JAXB was the mapping mechanism). This is a good thing, as the web service developer does not have to worry about this mapping, and can focus on coding just the implementation of service itself.

Upvotes: 1

Related Questions