i'm trying to make a DAO class for my Java project.
I've a SQLite Database with only one table "USER".
The schema is:
CREATE TABLE USER(
username VARCHAR(20) NOT NULL PRIMARY KEY,
password VARCHAR NOT NULL,
total_matches INTEGER DEFAULT 0,
victories INTEGER DEFAULT 0,
times_alien INTEGER DEFAULT 0,
times_human INTEGER DEFAULT 0,
total_steps INTEGER DEFAULT 0,
humans_killed INTEGER DEFAULT 0,
aliens_killed INTEGER DEFAULT 0,
kills_as_human INTEGER DEFAULT 0,
kills_as_alien INTEGER DEFAULT 0,
total_escapes INTEGER DEFAULT 0,
total_broken_hatches INTEGER DEFAULT 0,
total_noises INTEGER DEFAULT 0,
online_status VARCHAR(5) NOT NULL DEFAULT "false");
My UserDAOImpl class has findAll(), findByNickname(String nickname), insert, update, delete methods.
I use PreparedStatementto prevent SQL Injection.
My Issue is that if I call my insert(User toInsert) method and then cycle through the findAll() result, I can see the right insertion.
But if I go to the Terminal and open the DB with the SQLite command line, when I execute "SELECT * FROM USER", the previous insertion doesn't shows.
The DB Class:
/**
* The Class DB.
* Gives a connection to the game Database.
*/
public class DB {
/** the singleton instance of the Database. */
private static DB instance = new DB();
/** the path to the database. */
private static final String DBPath = "db/eftaios_DB.db";
/**
* Istantiates a new Database.
*/
private DB(){
/*
*
*/
}
/**
* Create a connection between this class and the database files.
*
* #return the database connection.
* #throws SQLException the SQL exception
*/
public Connection connect() throws SQLException{
Connection dbConnection = null;
try {
Class.forName("org.sqlite.JDBC");
String dbPath = DB.class.getClassLoader().getResource(DBPath).getPath();
dbConnection = DriverManager.getConnection("jdbc:sqlite:"+dbPath);
} catch (ClassNotFoundException e) {
/*
* do nothing, the class is imported in the maven dependencies
*/
} catch (SQLException e) {
throw new SQLException();
}
return dbConnection;
}
The DAO Class is:
/**
* The class UserDAOImpl implements the UserDAOInterface
* It implements a DAO (Data Access Object) for the User table.
* It gives access to the User table on the Database.
* With this class you can perform queries like find, insert, delete and update on the USER table.
*/
public class UserDAOImpl implements UserDAOInterface {
/** the database connection used to query it. */
private Connection dbConnection;
/** the result of a query to the database. */
private ResultSet queryResult;
/** the statement to execute to perform db queries. */
private Statement queryStatement;
/** the prepared statement to execute mysql injection secure queryes. */
private PreparedStatement queryPreparedStatement;
/** the name of the database user's table. */
private static final String USER_TABLE = "USER";
/**
* To user list.
*
* #param qryResult the qry result
* #return the list
* #throws SQLException the SQL exception
*/
private List<User> toUserList(ResultSet qryResult) throws SQLException{
List<User> result = new ArrayList<User>();
/* forall user in result, populate the new user and add it to the users list */
while(qryResult.next()){
User record = new User();
record.setNickname(qryResult.getString(User.NICKNAME_COL_NAME));
record.setPassword(qryResult.getString(User.PASSWORD_COL_NAME));
record.setAliensKilled(qryResult.getInt(User.ALIENS_KILLED_COL_NAME));
record.setHumansKilled(qryResult.getInt(User.HUMANS_KILLED_COL_NAME));
record.setKillsAsAlien(qryResult.getInt(User.KILLS_AS_ALIEN_COL_NAME));
record.setKillsAsHuman(qryResult.getInt(User.KILLS_AS_HUMAN_COL_NAME));
record.setOnlineStatus(qryResult.getBoolean(User.ONLINE_STATUS_COL_NAME));
record.setTimesAlien(qryResult.getInt(User.TIMES_ALIEN_COL_NAME));
record.setTimesHuman(qryResult.getInt(User.TIMES_HUMAN_COL_NAME));
record.setTotalBrokenHatches(qryResult.getInt(User.TOTAL_BROKEN_HATCHES_COL_NAME));
record.setTotalEscapes(qryResult.getInt(User.TOTAL_ESCAPES_COL_NAME));
record.setTotalMatches(qryResult.getInt(User.TOTAL_MATCHES_COL_NAME));
record.setTotalNoises(qryResult.getInt(User.TOTAL_NOISES_COL_NAME));
record.setTotalSteps(qryResult.getInt(User.TOTAL_STEPS_COL_NAME));
record.setVictories(qryResult.getInt(User.VICTORIES_COL_NAME));
result.add(record);
}
return result;
}
/*
* (non-Javadoc)
* #see it.polimi.ingsw.deolacremona.server.model.database.UserDAOInterface#findAll()
*/
#Override
public List<User> findAll() throws SQLException {
String findAllQuery = "SELECT * FROM "+USER_TABLE;
List<User> users = new ArrayList<User>();
this.dbConnection = DB.getDatabase().connect();
this.dbConnection.setAutoCommit(false);
this.queryStatement = this.dbConnection.createStatement();
this.queryResult = this.queryStatement.executeQuery(findAllQuery);
users = this.toUserList(queryResult);
this.dbConnection.commit();
this.queryResult.close();
this.queryStatement.close();
this.dbConnection.close();
return users;
}
/*
* (non-Javadoc)
* #see it.polimi.ingsw.deolacremona.server.model.database.UserDAOInterface#findByNickname(java.lang.String)
*/
#Override
public List<User> findByNickname(String userNickname) throws SQLException {
String findByNicknameQuery = "SELECT * FROM "+USER_TABLE+" WHERE "+User.NICKNAME_COL_NAME+"=?";
List<User> users = new ArrayList<User>();
this.dbConnection = DB.getDatabase().connect();
this.dbConnection.setAutoCommit(false);
/* preparing the statement to prevent sql injection */
this.queryPreparedStatement = this.dbConnection.prepareStatement(findByNicknameQuery);
this.queryPreparedStatement.setString(1, userNickname);
/* now get the result */
this.queryResult = this.queryPreparedStatement.executeQuery();
users = this.toUserList(queryResult);
this.dbConnection.commit();
this.queryPreparedStatement.close();
this.queryResult.close();
this.dbConnection.close();
return users;
}
/*
* (non-Javadoc)
* #see it.polimi.ingsw.deolacremona.server.model.database.UserDAOInterface#insert(it.polimi.ingsw.deolacremona.server.model.database.User)
*/
#Override
public boolean insert(User toInsert) throws SQLException {
boolean result = false;
MD5Hasher hasher = new MD5Hasher();
String md5Password = hasher.md5(toInsert.getPassword());
String insertQuery =
"INSERT INTO "+USER_TABLE+" ("+User.NICKNAME_COL_NAME+","+User.PASSWORD_COL_NAME+") VALUES (?,?)";
this.dbConnection = DB.getDatabase().connect();
this.dbConnection.setAutoCommit(false);
/* preparing the statement to prevent sql injection */
this.queryPreparedStatement = this.dbConnection.prepareStatement(insertQuery);
this.queryPreparedStatement.setString(1, toInsert.getNickname());
this.queryPreparedStatement.setString(2, md5Password);
if(this.queryPreparedStatement.executeUpdate()==1)
result = true;
this.queryPreparedStatement.close();
this.dbConnection.commit();
this.dbConnection.close();
return result;
}
/*
* (non-Javadoc)
* #see it.polimi.ingsw.deolacremona.server.model.database.UserDAOInterface#update(it.polimi.ingsw.deolacremona.server.model.database.User)
*/
#Override
public boolean update(User toUpdate) throws SQLException {
boolean result = false;
String updateQuery = "UPDATE "+USER_TABLE+" SET "
+ User.ALIENS_KILLED_COL_NAME +"=?,"
+ User.HUMANS_KILLED_COL_NAME +"=?,"
+ User.KILLS_AS_ALIEN_COL_NAME +"=?,"
+ User.KILLS_AS_HUMAN_COL_NAME +"=?,"
+ User.ONLINE_STATUS_COL_NAME +"=?,"
+ User.TIMES_ALIEN_COL_NAME +"=?,"
+ User.TIMES_HUMAN_COL_NAME +"=?,"
+ User.TOTAL_BROKEN_HATCHES_COL_NAME +"=?,"
+ User.TOTAL_ESCAPES_COL_NAME +"=?,"
+ User.TOTAL_MATCHES_COL_NAME +"=?,"
+ User.TOTAL_NOISES_COL_NAME +"=?,"
+ User.TOTAL_STEPS_COL_NAME +"=?,"
+ User.VICTORIES_COL_NAME +"=?"
+ " WHERE "+User.NICKNAME_COL_NAME+"=?";
/* preparing the sql statement to prevent sql injection */
this.dbConnection = DB.getDatabase().connect();
this.dbConnection.setAutoCommit(false);
this.queryPreparedStatement = this.dbConnection.prepareStatement(updateQuery);
this.queryPreparedStatement.setInt (1, toUpdate.getAliensKilled());
this.queryPreparedStatement.setInt (2, toUpdate.getHumansKilled());
this.queryPreparedStatement.setInt (3, toUpdate.getKillsAsAlien());
this.queryPreparedStatement.setInt (4, toUpdate.getKillsAsHuman());
this.queryPreparedStatement.setBoolean(5, toUpdate.isOnlineStatus());
this.queryPreparedStatement.setInt (6, toUpdate.getTimesAlien());
this.queryPreparedStatement.setInt (7, toUpdate.getTimesHuman());
this.queryPreparedStatement.setInt (8, toUpdate.getTotalBrokenHatches());
this.queryPreparedStatement.setInt (9, toUpdate.getTotalEscapes());
this.queryPreparedStatement.setInt (10, toUpdate.getTotalMatches());
this.queryPreparedStatement.setInt (11, toUpdate.getTotalNoises());
this.queryPreparedStatement.setInt (12, toUpdate.getTotalSteps());
this.queryPreparedStatement.setInt (13, toUpdate.getVictories());
this.queryPreparedStatement.setString (14, toUpdate.getNickname());
if(this.queryPreparedStatement.executeUpdate()==1){
result = true;
}
this.queryPreparedStatement.close();
this.dbConnection.commit();
this.dbConnection.close();
return result;
}
/*
* (non-Javadoc)
* #see it.polimi.ingsw.deolacremona.server.model.database.UserDAOInterface#updateAdder(it.polimi.ingsw.deolacremona.server.model.database.User)
*/
#Override
public boolean updateAdder(User toUpdate) {
// TODO Auto-generated method stub
return false;
}
/*
* (non-Javadoc)
* #see it.polimi.ingsw.deolacremona.server.model.database.UserDAOInterface#delete(it.polimi.ingsw.deolacremona.server.model.database.User)
*/
#Override
public boolean delete(User toDelete) throws SQLException {
boolean result = false;
String deleteQuery = "DELETE FROM "+USER_TABLE+" WHERE username=?";
this.dbConnection = DB.getDatabase().connect();
this.dbConnection.setAutoCommit(false);
this.queryPreparedStatement = this.dbConnection.prepareStatement(deleteQuery);
this.queryPreparedStatement.setString(1, toDelete.getNickname());
if(this.queryPreparedStatement.executeUpdate()==1){
result = true;
}
this.queryPreparedStatement.close();
this.dbConnection.commit();
this.dbConnection.close();
return result;
}
}
My test main method is:
public static void main(String[] args) throws SQLException, UnknownHostException{
DB database = DB.getDatabase();
database.connect();
MD5Hasher h = new MD5Hasher();
UserDAOImpl d = new UserDAOImpl();
User s = new User();
s.setNickname("davide");
s.setPassword("ciao");
if(d.insert(s))
System.out.println("insert");
// d.delete(s);
for(User x : d.findAll()){
System.out.println("Nickname: "+x.getNickname()+" password: "+x.getPassword()+" matches: "+x.getTotalMatches());
}
}
Thank you for your time.
EDIT: when I cut the database and put it into another directory, exit eclipse, move back the database in his previous directory and reopen eclipse, then all the changes that Java done previously are lost. –
SOLVED: In a Maven Project, all the resources are copied into another directory after the "build" command. I was reading the wrong db.
Related
So I have a claim script that I'm trying to put together, that claims the product after purchase. The program is built inside of Java. The problem I'm running into is that there is a custom field they input on their purchase, and the store itself inserts it into a JSON format. So I need to execute a query that pulls the custom field into the WHERE statement, like so :
public class StoreClaim implements Runnable {
public static final String HOST = "104.161.43.58"; // website ip address
public static final String USER = "eseezjte_forum";
public static final String PASS = "Fishsticks123";
public static final String DATABASE = "eseezjte_forum";
private Player player;
private Connection conn;
private Statement stmt;
public StoreClaim(Player player) {
this.player = player;
}
public void run() {
try {
if (!connect(HOST, DATABASE, USER, PASS)) {
return;
}
String name = player.getUsername().replace("_", " ");
ResultSet connect = executeQuery("SELECT ps_claimed, ps_item_id, ps_custom_fields->$.1 AS claimed FROM nexus_purchases WHERE ps_custom_fields->$.1 = '"+name+"' AND ps_claimed='0'");
while (connect.next()) {
player.sm("WORKING!");
return;
}
destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* #param host the host ip address or url
* #param database the name of the database
* #param user the user attached to the database
* #param pass the users password
* #return true if connected
*/
public boolean connect(String host, String database, String user, String pass) {
try {
this.conn = DriverManager.getConnection("jdbc:mysql://"+host+":3306/"+database, user, pass);
return true;
} catch (SQLException e) {
System.out.println("Failing connecting to database!");
return false;
}
}
/**
* Disconnects from the MySQL server and destroy the connection
* and statement instances
*/
public void destroy() {
try {
conn.close();
conn = null;
if (stmt != null) {
stmt.close();
stmt = null;
}
} catch(Exception e) {
e.printStackTrace();
}
}
/**
* Executes an update query on the database
* #param query
* #see {#link Statement#executeUpdate}
*/
public int executeUpdate(String query) {
try {
this.stmt = this.conn.createStatement(1005, 1008);
int results = stmt.executeUpdate(query);
return results;
} catch (SQLException ex) {
ex.printStackTrace();
}
return -1;
}
/**
* Executres a query on the database
* #param query
* #see {#link Statement#executeQuery(String)}
* #return the results, never null
*/
public ResultSet executeQuery(String query) {
try {
this.stmt = this.conn.createStatement(1005, 1008);
ResultSet results = stmt.executeQuery(query);
return results;
} catch (SQLException ex) {
ex.printStackTrace();
}
return null;
}
So i need to insert into this Result Set the JSON I'm trying to pull from.
This is what I'm trying to pull from the database and insert as the name to verify which user bought the product to claim.
I get the error :
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '>$.1 AS claimed FROM nexus_purchases WHERE ps_custom_fields->$.1 = 'quantum' ...' at line 1
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1052)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3609)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3541)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2002)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2163)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2618)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2568)
at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1557)
at quantum.site.StoreClaim.executeQuery(StoreClaim.java:139)
at quantum.site.StoreClaim.run(StoreClaim.java:45)
at java.lang.Thread.run(Thread.java:748)
java.lang.NullPointerException
at quantum.site.StoreClaim.run(StoreClaim.java:46)
at java.lang.Thread.run(Thread.java:748)
which points to :
ResultSet connect = executeQuery("SELECT ps_claimed, ps_item_id, ps_custom_fields->$.1 AS claimed FROM nexus_purchases WHERE ps_custom_fields->$.1 = '"+name+"' AND ps_claimed='0'");
I need the execute to check the databse, find a row in which the name == the custom field "1": variable, and where claimed == 0, and I will need to pull the ps_item_id from that row to execute inside another file. How do i properly access the array and check if the player name is == to the "1": variable?
After trying multiple different ways, I found through JSON object how to parse the data. I had to initiate a first ResultSet, and than from that result set, pull the custom_field and than pull that into a JSON Object, parse the "1" to a string, and than use another ResultSet with that string to get that row
String name = player.getUsername().replace("_", " ");
ResultSet connect = executeQuery("SELECT * FROM nexus_purchases WHERE ps_claimed='0'");
while (connect.next()) {
String str = connect.getString("ps_custom_fields");
JSONObject obj = new JSONObject(str);
String n = obj.getString("1");
ResultSet check = executeQuery("SELECT * FROM nexus_purchases WHERE '"+n+"' = '"+name+"' AND ps_claimed='0'");
while (check.next()) {
player.sm("WORKING!");
return;
}
}
I am facing problem. We are writting Java application as school project and we are supposed to use threads. Obviously, the application is not as complex to require threads, but we have to have them.
We decided to use threads for database communication, but we are not sure, how to use them for single methods. We created Database Transfer Object with some methods to insert entities into DB. How to use Runnable for single methods, please? To be more specific, we would like to create Runnable in methods and then add it to thread pool, but then, we would be able to get returns back.
public class EmployeeDTO {
private Employee employee;
private Connection conn;
private int id_employee;
/**
* Database connection
* #throws ClassNotFoundException
* #throws SQLException
*/
public EmployeeDTO() throws ClassNotFoundException, SQLException {
DatabaseConnection dbcon = new DatabaseConnection();
conn = dbcon.getConnection();
}
public EmployeeDTO(Employee employee) throws ClassNotFoundException, SQLException {
this.employee = employee;
DatabaseConnection dbcon = new DatabaseConnection();
conn = dbcon.getConnection();
}
/**
* Insert new Employee into database and sets it's id
* #param emp
* #throws SQLException
*/
public void insertEmployee(Employee emp) throws SQLException {
setEmployee(emp);
PreparedStatement pr = conn.prepareStatement("INSERT INTO employees "
+ "(nickname,name,surname,password_emp) "
+ "VALUES (?,?,?,?)", PreparedStatement.RETURN_GENERATED_KEYS);
pr.setString(1, employee.getNickname());
pr.setString(2, employee.getName());
pr.setString(3, employee.getSurname());
pr.setString(4, employee.getPassword());
pr.executeUpdate();
ResultSet rs = pr.getGeneratedKeys();
while (rs.next()) {
employee.setId_employee(rs.getInt(1));
}
}
/**
* Delete an employee from database
* #param id
* #throws SQLException
*/
public void deleteEmployee(int id) throws SQLException {
PreparedStatement pr = conn.prepareStatement("DELETE FROM employees WHERE id_employee=?");
pr.setInt(1, id);
pr.executeUpdate();
}
}
To be more specific, we would like to create Runnable in methods and then add it to thread pool, but then, we would be able to get returns back.
Sounds like you want to submit Callable tasks (not Runnable) to a thread pool. When you submit a Callable<T> task to an ExecutorService, you get back a Future<T> object that you can use at a later time to wait for the result of the task.
You may want to do something like below. Your insertEmployee method will be called from call method.
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.Callable;
public class EmployeeDTO implements Callable<String> {
private Employee employee;
private Connection conn;
private int id_employee;
/**
* Database connection
* #throws ClassNotFoundException
* #throws SQLException
*/
public EmployeeDTO() throws ClassNotFoundException, SQLException {
DatabaseConnection dbcon = new DatabaseConnection();
conn = dbcon.getConnection();
}
public EmployeeDTO(Employee employee) throws ClassNotFoundException, SQLException {
this.employee = employee;
DatabaseConnection dbcon = new DatabaseConnection();
conn = dbcon.getConnection();
}
/**
* Insert new Employee into database and sets it's id
* #param emp
* #throws SQLException
*/
public void insertEmployee(Employee emp) throws SQLException {
setEmployee(emp);
PreparedStatement pr = conn.prepareStatement("INSERT INTO employees "
+ "(nickname,name,surname,password_emp) "
+ "VALUES (?,?,?,?)", PreparedStatement.RETURN_GENERATED_KEYS);
pr.setString(1, employee.getNickname());
pr.setString(2, employee.getName());
pr.setString(3, employee.getSurname());
pr.setString(4, employee.getPassword());
pr.executeUpdate();
ResultSet rs = pr.getGeneratedKeys();
while (rs.next()) {
employee.setId_employee(rs.getInt(1));
}
}
/**
* Delete an employee from database
* #param id
* #throws SQLException
*/
public void deleteEmployee(int id) throws SQLException {
PreparedStatement pr = conn.prepareStatement("DELETE FROM employees WHERE id_employee=?");
pr.setInt(1, id);
pr.executeUpdate();
}
/**
* Computes a result, or throws an exception if unable to do so.
*
* #return computed result
* #throws Exception if unable to compute a result
*/
public String call() throws Exception {
insertEmployee(employee);
return "SUCCESS";
}
}
In other class you can use the ExecutorService like below
try{
Set<Callable<String>> callables = new HashSet<Callable<String>>();
EmployeeDTO employee = new EmployeeDTO(emp);
callables.add(employee);
ExecutorService executorService = Executors.newFixedThreadPool(1);
List<Future<String>> futures = executorService.invokeAll(callables);
}catch (ExecutionException eEx) {
eEx.getMessage();
}finally{
executorService.shutdown();
}
I'm currently working in migrating a project to java, keeping the data intact (database). Most data are taken via stored procedures(SP), and there's a hell lot of SP in the database.
So, while executing each SP, I have to write a class for that, which is building up a huge pile of classes.
Hence, is there any way to generalize the class, so that I could transform every SP results to this class, and then to client side(as json)?
Following scenarios are hidden n ma qn:
Dynamic number of fields.
Dynamic field names.
Type could be string
(could deal with that).
I have tried sending data as java.util.List, but that doesn't comes in a pretty format. Have to take data assuming indexes.
PS: I have searched for the same, but couldn't find any. And sorry if I'm asking for too much.
Yes, it should be possible to write such a generic class. Here is a small example class as a starting point for you. I use Firebird with the example database employee.fdb because there are already some stored procedures defined.
So to connect to the Firebird server, I use the Jaybird JDBC driver and include the jaybird-full-2.2.5.jar JAR file.
There are several different JSON libraries for JAVA. I use the JSR 353: Java API for JSON Processing - Reference Implementation here in streaming mode (like StaX for XML). So the second external JAR here is javax.json-1.0.4.jar.
My example works only for stored procedures returning result sets. For stored procedures with output parameters a CallableStatement should be used instead of a PreparedStatement.
First, a generic SQL statement is created for the specific stored procedure with its input parameters. To call the stored procedure, a PreparedStatemend is used. The parameters are set according to the individual parameter types. (Procedures createSql() and createStatement())
In procedure convertToJson() the method ResultSet.getMetaData() is used to get the result set's column information (how many columns, column name and column type).
The executeStoredProcedure() methods are public API methods to call.
The main() method connects to the èmployee.fdb database and calls three stored procedures: GET_EMP_PROJ, MAIL_LABEL and ORG_CHART.
package com.genericsptojson;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;
import javax.json.Json;
import javax.json.stream.JsonGenerator;
import javax.json.stream.JsonGeneratorFactory;
public class GenericSpToJson {
private static final String DB_URL = "jdbc:firebirdsql:localhost/3050:/var/lib/firebird/2.5/data/employee.fdb";
private static final String DB_USER = "SYSDBA";
private static final String DB_PWD = "***";
private Connection con;
public GenericSpToJson(Connection con) {
this.con = con;
}
/**
* Creates the SQL to call the stored procedure.
*
* #param spName
* Name of stored procecdure to call
* #param paramCount
* number of input parameters
* #return SQL with placeholders for input parameters
*/
private String createSql(String spName, int paramCount) {
if(paramCount > 0) {
final StringBuilder params = new StringBuilder();
boolean isFirst = true;
for(int i = 0; i < paramCount; i++) {
if(isFirst) {
isFirst = false;
} else {
params.append(", ");
}
params.append('?');
}
return String.format("SELECT * FROM %s (%s)", spName, params.toString());
} else {
return String.format("SELECT * FROM %s", spName);
}
}
/**
* Creates a PreparedStatement to call the stored procedure. This works only
* for stored procedures creating result sets. Stored procedures with OUT
* parameters should be handled by a CallableStatement instead.
*
* #param spName
* The stored procedure name to be called.
* #param params
* The input parameters.
* #return A prepared statement. All parameters are set.
* #throws SQLException
*/
private PreparedStatement createStatement(String spName, Object... params) throws SQLException {
final PreparedStatement stmt = con.prepareStatement(createSql(spName, params.length));
for(int i = 0; i < params.length; i++) {
final Object param = params[i];
if(param instanceof String) {
stmt.setString(i + 1, (String) param);
} else if(param instanceof Integer) {
stmt.setInt(i + 1, ((Integer) param).intValue());
} else {
// Handle other param types ...
}
}
return stmt;
}
/**
* Converts the result set to JSON in streaming mode.
*
* #param spName
* The stored procedure name.
* #param rs
* The result set of the stored procedure call.
* #param out
* The output stream to write the JSON into.
* #throws SQLException
*/
private void convertToJson(String spName, ResultSet rs, OutputStream out) throws SQLException {
// Get the result set meta data to obtain column information on the fly.
final ResultSetMetaData metaData = rs.getMetaData();
// Create the JSON generator with pretty printing
final Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JsonGenerator.PRETTY_PRINTING, true);
final JsonGeneratorFactory jsonGeneratorFactory = Json.createGeneratorFactory(properties);
final JsonGenerator generator = jsonGeneratorFactory.createGenerator(out);
generator.writeStartObject(); // root object
generator.write("storedProcedureName", spName);
generator.write("columnCount", metaData.getColumnCount());
generator.writeStartArray("records"); // records array
while(rs.next()) {
generator.writeStartObject(); // record object
// Each record object contains one field for every column.
// The field name is the columns name.
for(int col = 1; col <= metaData.getColumnCount(); col++) {
final String fieldName = metaData.getColumnName(col);
switch(metaData.getColumnType(col)) {
case Types.INTEGER:
final int intValue = rs.getInt(col);
if(rs.wasNull()) {
generator.writeNull(fieldName);
} else {
generator.write(fieldName, intValue);
}
break;
case Types.VARCHAR:
case Types.CHAR:
String stringValue = rs.getString(col);
if(rs.wasNull()) {
generator.writeNull(fieldName);
} else {
if(metaData.getColumnType(col) == Types.CHAR) {
stringValue = stringValue.trim();
}
generator.write(fieldName, stringValue);
}
break;
// Handle other types here
default:
System.out.println(String.format("Unhandled SQL type: %s", metaData.getColumnTypeName(col)));
}
}
generator.writeEnd(); // record object
}
generator.writeEnd(); // records array
generator.writeEnd(); // root object
generator.flush();
generator.close();
}
/**
* Executes the stored procedures with the given input parameters and creates
* JSON in streaming mode.
*
* #param spName
* The name of the stored procedure.
* #param out
* The output stream to write the generated JSON into.
* #param params
* The stored procedure's parameters.
*/
public void executeStoredProcedure(String spName, OutputStream out, Object... params) {
PreparedStatement stmt = null;
ResultSet rs = null;
try {
stmt = createStatement(spName, params);
rs = stmt.executeQuery();
convertToJson(spName, rs, out);
} catch (SQLException e) {
e.printStackTrace();
} finally {
// Cleaning up ...
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
/**
* Convenience method to call the stored procedure and create a JSON string.
* This should only be called for short result sets. For longer result sets
* use {#link #executeStoredProcedure(String, OutputStream, Object...)} where
* it is not necessary to hold the entire JSON document in memory.
*
* #param spName
* The name of the stored procedure to call.
* #param params
* The stored procedure's parameters
* #return The stored procedure's call result as a JSON string.
* #throws UnsupportedEncodingException
*/
public String executeStoredProcedure(String spName, Object... params) throws UnsupportedEncodingException {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
executeStoredProcedure(spName, out, params);
return out.toString("UTF-8");
}
public static void main(String[] args) {
Connection con = null;
try {
Class.forName("org.firebirdsql.jdbc.FBDriver");
con = DriverManager.getConnection(DB_URL, DB_USER, DB_PWD);
final GenericSpToJson converter = new GenericSpToJson(con);
System.out.println("Executing stored procedure GET_EMP_PROJ (8):\n"
+ converter.executeStoredProcedure("GET_EMP_PROJ", 8));
System.out.println("\n\nExecuting stored procedure MAIL_LABEL (1015):\n"
+ converter.executeStoredProcedure("MAIL_LABEL", 1015));
System.out.println("\n\nExecuting stored procedure ORG_CHART:\n"
+ converter.executeStoredProcedure("ORG_CHART"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
The output is (shortened):
Executing stored procedure GET_EMP_PROJ (8):
{
"storedProcedureName":"GET_EMP_PROJ",
"columnCount":1,
"records":[
{
"PROJ_ID":"VBASE"
},
{
"PROJ_ID":"GUIDE"
},
{
"PROJ_ID":"MKTPR"
}
]
}
Executing stored procedure MAIL_LABEL (1015):
{
"storedProcedureName":"MAIL_LABEL",
"columnCount":6,
"records":[
{
"LINE1":"GeoTech Inc.",
"LINE2":"K.M. Neppelenbroek",
"LINE3":"P.0.Box 702",
"LINE4":"",
"LINE5":null,
"LINE6":"Netherlands 2514"
}
]
}
Executing stored procedure ORG_CHART:
{
"storedProcedureName":"ORG_CHART",
"columnCount":5,
"records":[
{
"HEAD_DEPT":null,
"DEPARTMENT":"Corporate Headquarters",
"MNGR_NAME":"Bender, Oliver H.",
"TITLE":"CEO",
"EMP_CNT":2
},
{
"HEAD_DEPT":"Corporate Headquarters",
"DEPARTMENT":"Sales and Marketing",
"MNGR_NAME":"MacDonald, Mary S.",
"TITLE":"VP",
"EMP_CNT":2
},
// ... SNIP ...
{
"HEAD_DEPT":"Corporate Headquarters",
"DEPARTMENT":"Finance",
"MNGR_NAME":"Steadman, Walter",
"TITLE":"CFO",
"EMP_CNT":2
}
]
}
I am using Google App Engine with Cloud Endpoints to code a simple API. That API only has one entity: Book, with fields Long id and String name.
The Google Plugin for Eclipse generated for me an API class which has a getBook(Long id) method. However, I would also like to be able to get a book knowing its name. That is to say I would like to also have a getBookByName(String name) method. Could you show me a simple code for it, or a link which shows something like that? I think I have to use the JDO framework with a query object.
Here is the API class code:
#Api(name = "bookendpoint")
public class BookEndpoint {
/**
* This method lists all the entities inserted in datastore.
* It uses HTTP GET method and paging support.
*
* #return A CollectionResponse class containing the list of all entities
* persisted and a cursor to the next page.
*/
#SuppressWarnings({ "unchecked", "unused" })
#ApiMethod(name = "listBook")
public CollectionResponse<Book> listBook(
#Nullable #Named("cursor") String cursorString,
#Nullable #Named("limit") Integer limit) {
PersistenceManager mgr = null;
Cursor cursor = null;
List<Book> execute = null;
try {
mgr = getPersistenceManager();
Query query = mgr.newQuery(Book.class);
if (cursorString != null && cursorString != "") {
cursor = Cursor.fromWebSafeString(cursorString);
HashMap<String, Object> extensionMap = new HashMap<String, Object>();
extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
query.setExtensions(extensionMap);
}
if (limit != null) {
query.setRange(0, limit);
}
execute = (List<Book>) query.execute();
cursor = JDOCursorHelper.getCursor(execute);
if (cursor != null)
cursorString = cursor.toWebSafeString();
// Tight loop for fetching all entities from datastore and accomodate
// for lazy fetch.
for (Book obj : execute)
;
} finally {
mgr.close();
}
return CollectionResponse.<Book> builder().setItems(execute)
.setNextPageToken(cursorString).build();
}
/**
* This method gets the entity having primary key id. It uses HTTP GET method.
*
* #param id the primary key of the java bean.
* #return The entity with primary key id.
*/
#ApiMethod(name = "getBook")
public Book getBook(#Named("id") Long id) {
PersistenceManager mgr = getPersistenceManager();
Book book = null;
try {
book = mgr.getObjectById(Book.class, id);
} finally {
mgr.close();
}
return book;
}
/**
* This inserts a new entity into App Engine datastore. If the entity already
* exists in the datastore, an exception is thrown.
* It uses HTTP POST method.
*
* #param book the entity to be inserted.
* #return The inserted entity.
*/
#ApiMethod(name = "insertBook")
public Book insertBook(Book book) {
PersistenceManager mgr = getPersistenceManager();
try {
if (book.getId() != null) {
if (containsBook(book)) {
throw new EntityExistsException("Object already exists");
}
}
mgr.makePersistent(book);
} finally {
mgr.close();
}
return book;
}
/**
* This method is used for updating an existing entity. If the entity does not
* exist in the datastore, an exception is thrown.
* It uses HTTP PUT method.
*
* #param book the entity to be updated.
* #return The updated entity.
*/
#ApiMethod(name = "updateBook")
public Book updateBook(Book book) {
PersistenceManager mgr = getPersistenceManager();
try {
if (!containsBook(book)) {
throw new EntityNotFoundException("Object does not exist");
}
mgr.makePersistent(book);
} finally {
mgr.close();
}
return book;
}
/**
* This method removes the entity with primary key id.
* It uses HTTP DELETE method.
*
* #param id the primary key of the entity to be deleted.
*/
#ApiMethod(name = "removeBook")
public void removeBook(#Named("id") Long id) {
PersistenceManager mgr = getPersistenceManager();
try {
Book book = mgr.getObjectById(Book.class, id);
mgr.deletePersistent(book);
} finally {
mgr.close();
}
}
private boolean containsBook(Book book) {
PersistenceManager mgr = getPersistenceManager();
boolean contains = true;
try {
mgr.getObjectById(Book.class, book.getId());
} catch (javax.jdo.JDOObjectNotFoundException ex) {
contains = false;
} finally {
mgr.close();
}
return contains;
}
private static PersistenceManager getPersistenceManager() {
return PMF.get().getPersistenceManager();
}
}
Overloading is not supported. You should just call your functions "getBookByName", "getBookByISBN", etc...
I have created an sql database with a table containing information about Airplanes, I want to be able to take this information and insert it into an ArrayList of type Aircraft(object) although the different info in the sql table are different primitive types........can this be done?`package uk.ac.qub.sqldbflights;
This is the Aircraft object with all the attributes which are the
public class Aircraft {
/**
* private String containing the airline name of the aircraft
* -Can't be blank
*/
private int aircraft_number;
/**
* private String containing the flight number belonging to the aircraft
* -Can't be blank
*/
private String airline_company;
/**
* private String containing the aircrafts city of origin
* -Can't be blank
*/
private String departure_airport;
/**
* private int which holds the aircrafts fuel level
* -Must be over 0 and less than 100
*/
private float passenger_number;
/**
* private int containing the number of passengers aboard the aircraft
* -Must be over 0 and less than 300
*/
private float fuel_percentage;
/**
* private Boolean indicting wether the aircraft is in the landing queue or not
*/
private int flight_time_remaining;
/**
* private Boolean indicating wether the aircraft is landed or not
*/
private boolean in_queue;
private boolean is_landed;
public Aircraft() {
}
/**
* Song creation
* #param name -not null
* #param artist -not null
* #param album -not null
* #param genre- not null and one of Pop, Dance, Rock
* #throws IllegalArgumentException
*/
public Aircraft(int aircraft_number, String airline_company, String departure_airport, int passenger_number, float fuel_percentage, int flight_time_remaining, boolean in_queue, boolean is_landed)
throws IllegalArgumentException {
try {
// set name
this.setAircraft_number(aircraft_number);
this.setAirline_company(airline_company);
this.setDeparture_airport(departure_airport);
this.setPassenger_number(passenger_number);
this.setFuel_percentage(fuel_percentage);
this.setFlight_time_remaining(flight_time_remaining);
this.setIn_queue(in_queue);
this.setIs_landed(is_landed);
} catch (IllegalArgumentException ex) {
System.out.println("Unable to create song due to arguments passed");
throw ex;
}}
public int getAircraft_number() {
return aircraft_number;
}
public void setAircraft_number(int aircraft_number) {
this.aircraft_number = aircraft_number;
}
public String getAirline_company() {
return airline_company;
}
public void setAirline_company(String airline_company) {
this.airline_company = airline_company;
}
public String getDeparture_airport() {
return departure_airport;
}
public void setDeparture_airport(String departure_airport) {
this.departure_airport = departure_airport;
}
public float getPassenger_number() {
return passenger_number;
}
public void setPassenger_number(float passenger_number) {
this.passenger_number = passenger_number;
}
public float getFuel_percentage() {
return fuel_percentage;
}
public void setFuel_percentage(float fuel_percentage) {
this.fuel_percentage = fuel_percentage;
}
public int isFlight_time_remaining() {
return flight_time_remaining;
}
public void setFlight_time_remaining(int flight_time_remaining) {
this.flight_time_remaining = flight_time_remaining;
}
public boolean isIn_queue() {
return in_queue;
}
public void setIn_queue(boolean in_queue) {
this.in_queue = in_queue;
}
public boolean isIs_landed() {
return is_landed;
}
public void setIs_landed(boolean is_landed) {
this.is_landed = is_landed;
}
}
This is the code which makes the connection to the sql DB and trys to add the info to an arraylist...
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
public class FlightsDbtoArrayList {
ArrayList<Aircraft> allFlights = new ArrayList<Aircraft>();
public static void main(String[] args) {
// Entering username to verify connection to SQL Server
String url = "jdbc:mysql://";
Connection con;
Statement statement1;
try {
Class.forName("com.mysql.jdbc.Driver");
//Catching any errors and printing a message to the user
} catch(java.lang.ClassNotFoundException e) {
System.err.print("ClassNotFoundException: ");
System.err.println(e.getMessage());
}
try {
// Entering username and password to verify connection to SQL Server
con = DriverManager.getConnection(url);
//Creating platform for a SQL query Statement
statement1 = con.createStatement();
//Creating and executing the designed SQL query statement
ResultSet results1 = statement1.executeQuery("SELECT aircraft_number, airline_company, departure_airport, passenger_number, fuel_Percentage, flight_time_remaining, in_queue, is_landed FROM flights");
//Displaying the results of the query to screen
printResults(results1);
con.close();
statement1.close();
} catch(SQLException ex) {
System.err.println("SQLException: " + ex.getMessage());
}
}
/**
* Method to display the results of the three SQL queries
* #param results
* #throws SQLException
*
*
*/
public ArrayList<Aircraft> allFlights() {
return allFlights;
}
/**
* set songs on the system
* #param allSongs
*/
public void setSongs(ArrayList<Aircraft> allSongs) {
allSongs = this.allFlights;
}
private static void printResults(ResultSet results) throws SQLException {
while (results.next()) {
int aircraft_number = results.getInt("aircraft_number");
String airline_company = results.getString("airline_company");
String departure_airport = results.getString("departure_airport");
int passenger_number = results.getInt("passenger_number");
float fuel_percentage = results.getFloat("fuel_percentage");
int flight_time_remaining = results.getInt("flight_time_remaining");
boolean in_queue = results.getBoolean("in_queue");
boolean is_landed = results.getBoolean("is_landed");
Aircraft a1;
ArrayList<Aircraft> allFlights = new ArrayList<Aircraft>();
a1 = new Aircraft(aircraft_number, airline_company, departure_airport, passenger_number, fuel_percentage, flight_time_remaining, in_queue, is_landed);
allFlights.add(a1);
System.out.println(allFlights);
}
}
}
`
Yes it is definitely possible to have list of objects(Aircraft) derived from database. But in this case your while loop inside the PrintResult has some errors.
You are creating list allFights within the while loop which will create new list in each iteration and add a1 to it so in the end you will only have a list with one aircraft details in it.
System.out.println(allFlights) will not give much desired output (or it might), but I would advice you should override toString() method in your AirCraft class.
Try to change your PrintResult method as following.
private static void printResults(ResultSet results) throws SQLException {
ArrayList<Aircraft> allFlights = new ArrayList<Aircraft>();
Aircraft a1;
while (results.next()) {
int aircraft_number = results.getInt("aircraft_number");
String airline_company = results.getString("airline_company");
String departure_airport = results.getString("departure_airport");
int passenger_number = results.getInt("passenger_number");
float fuel_percentage = results.getFloat("fuel_percentage");
int flight_time_remaining = results.getInt("flight_time_remaining");
boolean in_queue = results.getBoolean("in_queue");
boolean is_landed = results.getBoolean("is_landed");
a1 = new Aircraft(aircraft_number, airline_company, departure_airport, passenger_number, fuel_percentage, flight_time_remaining, in_queue, is_landed);
allFlights.add(a1);
//Instead of this line System.out.println(allFlights);
//write following code
For(AirCraft aircraft : allFlights){
System.out.println(aircraft.toString());
}
}
}
Edit 2: Write the following method in your AirCraft class.
#Override
Public String toString(){
String string;
//Write some code here so that you can represent you object using this method
//for example I am adding just the aircraft_number
string = getAircraft_number()+"";
return string;
}
Important: The toString() method I wrote is just an example you need to learn how to correctly write toString() method for any of your class. this and this are good starting point to learn that. And stop worrying about your your list of allFlights because as per this code it is getting created but you can not print it the way you are trying to.