I have a resultset as a result of a MySQL query using the JDBC connector. So my job is to convert the resultset into a JSON format. So that I can send it to the clientside a
If you are using JSON I recommend the Jackson JSON library.
http://wiki.fasterxml.com/JacksonHome
The jar files can be found here:
http://wiki.fasterxml.com/JacksonDownload
Here is the generic code I use to convert any result set into a Map<> or List< Map<> > Converting this to JSON using JacksonJSON is pretty straight forward (See Below).
package com.naj.tmoi.entity;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EntityFactory {
public EntityFactory(Connection connection, String queryString) {
this.queryString = queryString;
this.connection = connection;
}
public Map<String, Object> findSingle(Object[] params) throws SQLException {
List<Map<String, Object>> objects = this.findMultiple(params);
if (objects.size() != 1) {
throw new SQLException("Query did not produce one object it produced: " + objects.size() + " objects.");
}
Map<String, Object> object = objects.get(0); //extract only the first item;
return object;
}
public List<Map<String, Object>> findMultiple(Object[] params) throws SQLException {
ResultSet rs = null;
PreparedStatement ps = null;
try {
ps = this.connection.prepareStatement(this.queryString);
for (int i = 0; i < params.length; ++i) {
ps.setObject(1, params[i]);
}
rs = ps.executeQuery();
return getEntitiesFromResultSet(rs);
} catch (SQLException e) {
throw (e);
} finally {
if (rs != null) {
rs.close();
}
if (ps != null) {
ps.close();
}
}
}
protected List<Map<String, Object>> getEntitiesFromResultSet(ResultSet resultSet) throws SQLException {
ArrayList<Map<String, Object>> entities = new ArrayList<>();
while (resultSet.next()) {
entities.add(getEntityFromResultSet(resultSet));
}
return entities;
}
protected Map<String, Object> getEntityFromResultSet(ResultSet resultSet) throws SQLException {
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
Map<String, Object> resultsMap = new HashMap<>();
for (int i = 1; i <= columnCount; ++i) {
String columnName = metaData.getColumnName(i).toLowerCase();
Object object = resultSet.getObject(i);
resultsMap.put(columnName, object);
}
return resultsMap;
}
private final String queryString;
protected Connection connection;
}
In the servlet I convert the List into JSON using the com.fasterxml.jackson.databind.ObjectMapper which converts Java Generics into a JSON String.
Connection connection = null;
try {
connection = DataSourceSingleton.getConnection();
EntityFactory nutrientEntityFactory = new EntityFactory(connection, NUTRIENT_QUERY_STRING);
List<Map<String, Object>> nutrients = nutrientEntityFactory.findMultiple(new Object[]{});
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(nutrients);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(json);
} catch (SQLException e) {
throw new ServletException(e);
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
throw new ServletException(e);
}
}
}
You can pass in Parameters to the PreparedStatement like this:
String name = request.getHeader("name");
EntityFactory entityFactory = new EntityFactory(DataSourceSingleton.getConnection(), QUERY_STRING);
Map<String, Object> object = entityFactory.findSingle(new String[]{name});
private static final String QUERY_STRING = "SELECT NAME, PASSWORD, TOKEN, TOKEN_EXPIRATION FROM USER WHERE NAME = ?";
}
I have used Google GSON library, its one tiny gson-2.2.4.jar 190KB library in a mywebapp/WEB-INF/lib folder. http://code.google.com/p/google-gson/
import com.google.gson.stream.JsonWriter;
---
httpres.setContentType("application/json; charset=UTF-8");
httpres.setCharacterEncoding("UTF-8");
JsonWriter writer = new JsonWriter(new OutputStreamWriter(httpres.getOutputStream(), "UTF-8"));
while(rs.next()) {
writer.beginObject();
// loop rs.getResultSetMetadata columns
for(int idx=1; idx<=rsmd.getColumnCount(); idx++) {
writer.name(rsmd.getColumnLabel(idx)); // write key:value pairs
writer.value(rs.getString(idx));
}
writer.endObject();
}
writer.close();
httpres.getOutputStream().flush();
If you want typed JSON key:value pairs there is a writer.value(String,long,integer,etc..) setters. Do switch-case within foreach rsmd loop and use appropriate setter for numbered sql types. Default could use writer.value(rs.getString(idx)) setter.
Using JsonWriter allows writing large json replys CPU+RAM effectively. You dont need to loop sqlresultset first and create massive List in RAM. Then loop list again while writing json document. This example flows as it goes, http reply is being chunked while remaining data is still written to servlet output.
Its relatively easy to create higher-level wrapper utils around GSON+Sql resultset. jsp page could use SqlIterator(sqlquery) methods (.next(), getColumnCount(), getType(idx), .getString(idx), .getLong(idx) ...) while writing http reply. It loops the original sql without intermediate List. This does not matter for smaller apps but heavy-use apps must consider cpu+ram usage patterns more closely. Or even better do SqlToJson(httpresponse, sqlrs) helper then jsp or servlet code noice is minimal.
Use jsonlib for Java. Iterate over the result set and add the properties you want as JSONObject
objects from jsonlib.
Within my applications (MySQL/java servlet/javascript on browser) I use a string function with the fast stringbuilder methods and a generic rs.getObject(). I think it is the most elegant way to do the job:
public String rStoJason(ResultSet rs) throws SQLException
{
if(rs.first() == false) {return "[]";} else {rs.beforeFirst();} // empty rs
StringBuilder sb=new StringBuilder();
Object item; String value;
java.sql.ResultSetMetaData rsmd = rs.getMetaData();
int numColumns = rsmd.getColumnCount();
sb.append("[{");
while (rs.next()) {
for (int i = 1; i < numColumns + 1; i++) {
String column_name = rsmd.getColumnName(i);
item=rs.getObject(i);
if (item !=null )
{value = item.toString(); value=value.replace('"', '\'');}
else
{value = "null";}
sb.append("\"" + column_name+ "\":\"" + value +"\",");
} //end For = end record
sb.setCharAt(sb.length()-1, '}'); //replace last comma with curly bracket
sb.append(",{");
} // end While = end resultset
sb.delete(sb.length()-3, sb.length()); //delete last two chars
sb.append("}]");
return sb.toString();
}