I'm not sure whether I'm using JMockit incorrectly, or there's something amiss in my setup. I'm using JMockit 1.32 with JUnit 4.12 in Eclipse.
My problem seems to be that interfaces aren't being captured. Specifically in the java.sql package. For example:
public class Dto {
private int id;
public Dto(){}
public Dto(ResultSet rs) {
try {
id = rs.getInt(1);
} catch (SQLException e) { }
}
public int getId() {return id;}
void setId(int id) {this.id = id;}
}
.
public class ClassUnderTest {
public static Dto loadObject(Connection conn, String tablename, int id) {
Dto result = null;
ResultSet rs = null;
PreparedStatement ps = null;
try {
String sql = "select * from " + tablename + " where id = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1, id);
rs = ps.executeQuery();
if (rs.next()) {
result = new Dto(rs);
}
} catch (SQLException e) {
} finally {
try {
if (ps != null) ps.close();
} catch (SQLException e) { }
}
return result;
}
}
.
public class ResultSetTest extends junit.framework.TestCase {
private static final int OBJ_ID = 5;
#Capturing
ResultSet mockResultSet;
#Capturing
PreparedStatement mockStatement;
#Capturing
Connection mockConn;
#Test
public void testGetDtoById() throws SQLException {
new Expectations() {{
mockConn.prepareStatement(anyString); result = mockStatement;
mockStatement.setInt(anyInt, OBJ_ID);
mockResultSet.next(); result = true;
new Dto(mockResultSet); result = new Dto();
mockResultSet.next(); result = true;
}};
Dto dto = ClassUnderTest.loadObject(mockConn, "", OBJ_ID);
assertEquals(dto.getId(), OBJ_ID);
}
}
In this setup, test execution fails with a NPE on the first line in the Expectations(){} block. But from the tutorials, etc. I'm expecting a mocked instance to have been created. (e.g. tutorial)
Trying to move past this, I created explicit mocked classes like so:
public class ResultSetMockup extends MockUp<ResultSet> { }
public class PreparedStatementMockup extends MockUp<PreparedStatement>
{
#Mock ResultSet executeQuery() {return new ResultSetMockup().getMockInstance();}
}
public class ConnectionMockup extends MockUp<Connection>
{
#Mock PreparedStatement prepareStatement(String sql) throws SQLException {
return new PreparedStatementMockup().getMockInstance();
}
}
#Capturing
ResultSet mockResultSet = new ResultSetMockup().getMockInstance();
#Capturing
PreparedStatement mockStatement = new PreparedStatementMockup().getMockInstance();
#Capturing
Connection mockConn = new ConnectionMockup().getMockInstance();
At this point, the Expectations() {} block is happy, but it appears that results is never actually being set. By setting a breakpoint I see that rs.next() always fails. So I presume nothing is actually being captured.
What am I doing wrong? Or is something in my setup preventing JMockit from actually running?
The actual problem in the test is that it's mixing the APIs from JUnit 3 (anything from junit.framework) and JUnit 4+ (org.junit). This should never be done.
JMockit only supports the JUnit 4 API, not the obsolete JUnit 3 API. So, simply remove "extends from junit.framework.TestCase" that it will be ok.
BTW, your Java IDE should have warned against this mistake. IntelliJ, at least, promptly displays "Method 'testGetDtoById()' annotated with '#Test' inside class extending JUnit 3 TestCase".
Also, the test (and the code under test) has several other mistakes...
My problem appears to have been the use of JUnit. I went as far as to try tutorial examples verbatim without luck. But by converting over to TestNG all my problems went away.
It seems as though JMockit's Expectations block wasn't able to hook into the code properly with JUnit. Either calls weren't recognized or the faking wasn't happening. I'm curious now, does anyone have it working with JUnit?
Related
Started a new job and need to learn Java (been a .NET developer for over a decade). A mandate from higher up dictates all new stuff is to be done in Java / Oracle.
So I am running through the PluralSight training and right now I am trying to learn the intricacies of JDBC.
I have the following table in a Oracle Database (also a new tech for me).
CREATE TABLE "TEST"."ACCOUNT"
(
"ACCOUNT_ID" NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY VALUE,
"ACCOUNT_NAME" VARCHAR2(20)
"ACCOUNT_NUMBER" VARCHAR2(20)
"ACCOUNT_TYPE" VARCHAR2(20)
)
I set up some code using the Repository pattern. But it is fairly simple:
public static void main(String[] args) throws IOException {
IAccountMapper accountMapper = new AccountMapper();
IConfiguration configuration = new OracleConfiguration();
try (
IDataAccess<ResultSet> dataAccess = new OracleDataAccess(configuration);
IAccountRepository accountRepo = new AccountRepository(accountMapper, dataAccess);
){
//nothing here
List<Account> accounts = accountRepo.query(new AllAccountsSpecification());
} catch (Exception e){
System.err.println(e.getMessage());
}
}
The IDataAccess interface:
public interface IDataAccess<T> {
T get(String query) throws SQLException;
}
All of my implementation is in the base classes and the subclasses are referenced - ie:
public interface IOracleDataAccess extends IDataAccess<ResultSet>{
}
public class OracleDataAccess extends DataAccessBase<ResultSet> implements IOracleDataAccess {
public OracleDataAccess(IConfiguration configuration) throws SQLException {
super(configuration);
}
The implementation of the IDataAccess (a base class where T is the entity used by the repo):
public abstract class DataAccessBase<T> implements AutoCloseable {
protected final IConfiguration configuration;
protected Connection connection;
protected PreparedStatement statement;
protected ResultSet resultSet;
public DataAccessBase(IConfiguration configuration) {
this.configuration = configuration;
this.connection = DriverManager.getConnection(configuration.getConnectionString(),
configuration.getUsername(), configuration.getPassword());
}
public T get(String query) throws SQLException {
statement = connection.prepareStatement(query);
return (T)statement.executeQuery();
}
}
This DataAccess class is injected into my Repository class and is used to return the results:
public abstract class ReadOnlyRepositoryBase<T> implements IReadOnlyRepository<T> {
protected final IMapper<ResultSet, T> mapper;
protected final IDataAccess<ResultSet> database;
public ReadOnlyRepositoryBase(IMapper<ResultSet, T> mapper, IDataAccess<ResultSet> database) {
this.mapper = mapper;
this.database = database;
}
public List<T> query(ISpecification specification){
List<T> entities = new ArrayList<>;
try {
System.out.println(specification.toSqlQuery());
//This is what is output:
//SELECT * FROM ACCOUNT
//this returns 1 record when: "select tablespace_name, table_name from user_tables"
//returns no records when "select * from account"
ResultSet rs = database.get(specification.toSqlQuery());
//loop is never entered for "select * from account"
//runs once for "select tablespace_name, table_name from user_tables"
while(rs.next()){
entities.add(mapper.map(rs));
}
} catch (SQLException sqlEx){
sqlEx.printStackTrace();
}
return entities;
}
}
The problem is nothing is coming back (the ResultSet next() method returns false) This SQL:
SELECT * FROM ACCOUNT
Returns 2 records from the Oracle SQL Developer IDE - but nothing in code.
If I run this query from code:
"SELECT TABLESPACE_NAME, TABLE_NAME FROM USER_TABLES"
I get 1 record back (TEST, ACCOUNT)
Do I need to further qualify the tables in the SQL to get records back?
I am logged into the database with the same credentials I am connecting with - so I do not think it is a permission thing.
Feel like an idiot - but I imagine I am not the first here. #AlexPoole was spot on. I had inserted the records through the IDE - but apparently
I did not commit them. Coming from SQL Server - I do not need to commit after a
Insert into [Table] values (stuff)
I guess that is different with Oracle.
I've been designing some source code because we had in our project much code being repeated when making SQL queries.
So I did this code below which seems to work fine trying something similar to Command pattern. It receives just a SQL query in a String and some parameters (if needed) to set on the statement. So you can use this code as an anonymous class an execute the query only defining what to do with the output of the query.
My problem is that I wanted to design this to make mandatory to define and write the method getResult in the anonymous child class, but I can't think any way of doing it without making an abstract method and class.
If QueryCommand becomes abstract I should make another class to be able to instantiate, which can't be abstract as well. Is there any other way to make compulsory the overriding in child class? I'm looking for the smartest simplest way to achieve it.
Didn't know how to search for a similar pattern or solution.
Thanks in advance.
Source code:
import java.sql.Connection;
import java.sql.SQLException;
public interface IQueryCommand<T> {
T executeQuery(Connection conn, String query, Object... args) throws SQLException;
}
import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.MessageFormat;
import org.apache.log4j.Logger;
public class QueryCommand<T> implements IQueryCommand<T> {
private Logger LOGGER = Logger.getLogger(this.getClass());
/** The constant ERROR_CLOSING_RESULT_SET */
protected static final String ERROR_CLOSING_RESULT_SET = "Error when closing ResultSet";
/** The Constant ERROR_CLOSING_PREPARED_STATEMENT. */
protected static final String ERROR_CLOSING_PREPARED_STATEMENT = "Error when closing PreparedStatement";
// FIXME: I want this method to be mandatory to be defined in the anonymous child class
protected T getResult(ResultSet rs) throws SQLException {
return null;
};
public T executeQuery(Connection conn, String sqlQuery, Object... args) throws SQLException {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(sqlQuery);
}
PreparedStatement ps = null;
ps = conn.prepareStatement(sqlQuery);
return executeQuery(conn, ps, args);
}
public T executeQuery(Connection conn, PreparedStatement ps, Object... args) throws SQLException {
ResultSet rs = null;
try {
if(args != null && args.length > 0) {
for(int i=0; i< args.length; i++) {
setArg(ps, i+1, args[i]);
}
}
rs = ps.executeQuery();
T result = getResult(rs); // Method defined in child class
return result;
} catch (SQLException e) {
throw e;
} finally {
if(rs != null) {
try {
rs.close();
} catch (final SQLException e) {
LOGGER.error(ERROR_CLOSING_RESULT_SET, e);
}
}
if (ps != null) {
try {
ps.close();
} catch (final Exception e) {
if(ps instanceof CallableStatement) {
LOGGER.error("Error when closing CallableStatement", e);
} else if(ps instanceof PreparedStatement) {
LOGGER.error(ERROR_CLOSING_PREPARED_STATEMENT, e);
}
}
}
}
}
/**
* Sets a value on the PreparedStatemente with a method dependending on dataType
*
* #param ps the preparedStatement
* #param idx the index on which the value is set
* #param value the value to set
* #throws SQLException if an error is detected
*/
private void setArg(PreparedStatement ps, int idx, Object value) throws SQLException {
// Implementation not relevant...
}
}
Example of how to use this:
sqlQuery = " SELECT X FROM Y WHERE countryId = ? and languageId = ?";
return new QueryCommand<String>() {
// This method should be REQUIRED when compiling
#Override
protected String getResult(ResultSet rs) throws SQLException {
String result = "";
while (rs.next()) {
result = rs.getString("DESCRIPTION");
}
return result;
};
}.executeQuery(getDB2Connection(), sqlQuery.toString(), new Object[] { countryIdParameter, languageIdParameter});
I can't think any way of doing it without making an abstract method and class.
Abstract class is precisely the mechanism that you need
I should make another class to be able to instantiate, which can't be abstract as well.
That is not correct: anonymous classes are perfectly capable of inheriting an abstract class, or even extending an interface, provided, of course, that they implement all abstract methods:
public class AbstractQueryCommand<T> implements IQueryCommand<T> {
abstract protected String getResult(ResultSet rs) throws SQLException;
...
}
return new AbstractQueryCommand<String>() {
#Override
protected String getResult(ResultSet rs) throws SQLException {
String result = "";
while (rs.next()) {
result = rs.getString("DESCRIPTION");
}
return result;
};
}
Make QueryCommand abstract, then create an additional concrete final class. That way any anonymous classes need to implement the method, but you still have a non-abstract class you can instantiate (since it was apparently a requirement, although I fail to see why).
I have had some trouble with using a general type in a static method.
All comments on the source code are welcome, especially ones that significantly improve the code. I am also currently not planning on using any external framework, apart from JDBC, to keep it still simple, please do not put too much emphasis on that.
My view on not using external frameworks is also supported by the fact that the operations I will be using on the database are very minimal:
Inserting data
Updating data
Retrieving all fields. (And simply by putting in a different SQL Query you could already select what fields to retrieve
I do not plan on making a full framework, so I know that it will not be supporting everything. The speed of retrieving all fields is neither a real issue, as this will be pretty much only done on server bootup, and if used at any other time it will be done in a background task for which I do not really care when it is finished.
Entity.java:
abstract public class Entity<KeyType, DataType> {
protected KeyType key;
protected List<Object> data;
public Entity() {
data = new ArrayList<>();
}
//abstract public static Map<KeyType, DataType> getAll();
protected List<Object> createData(final DataAction dataAction) {
List<Object> list = new ArrayList<>();
if (dataAction == DataAction.INSERT) {
list.add(key);
}
list.addAll(data);
if (dataAction == DataAction.UPDATE) {
list.add(key);
}
return list;
}
abstract public void insert();
abstract public void update();
protected static <KeyType, DataType> Map<KeyType, DataType> getData(final Class<DataType> dataTypeClass, final String query) {
Map<KeyType, DataType> map = new HashMap<>();
try {
PreparedStatement preparedStatement = DatabaseConnection.getConnection().prepareStatement(query);
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
KeyType key = (KeyType)resultSet.getObject(1);
int index = 2;
List<Object> dataList = new ArrayList<>();
while (resultSet.getObject(index) != null) {
dataList.add(resultSet.getObject(index));
index++;
}
DataType dataObject = null;
try {
dataObject = dataTypeClass.getConstructor(List.class).newInstance(dataList);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException ex) {
Logger.getLogger(Entity.class.getName()).log(Level.SEVERE, null, ex);
}
map.put(key, dataObject);
}
} catch (SQLException ex) {
Logger.getLogger(Entity.class.getName()).log(Level.SEVERE, null, ex);
}
return map;
}
protected void executeQuery(final String query, final List<Object> data) {
try {
PreparedStatement preparedStatement = DatabaseConnection.getConnection().prepareStatement(query);
int dataIndex = 0;
for (Object dataObject : data) {
preparedStatement.setObject(dataIndex, dataObject);
dataIndex++;
}
preparedStatement.execute();
preparedStatement.close();
} catch (SQLException ex) {
Logger.getLogger(Entity.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
A concrete implementation, Account.java:
public class Account extends Entity<String, Account> {
private final static String SELECT_ALL_QUERY = "SELECT * FROM accounts";
private final static String INSERT_QUERY = "INSERT INTO accounts (username, password) VALUES(?, ?)";
private final static String UPDATE_QUERY = "UPDATE accounts SET password=? WHERE username=?";
private String username;
private String password;
public Account(final String username, final String password) {
this.username = username;
this.password = password;
key = username;
data.add(password);
}
public Account(final List<Object> data) {
this((String)data.get(0), (String)data.get(1));
}
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(final String password) {
this.password = password;
}
public static Map<String, Account> selectAll() {
return getData(Account.class, SELECT_ALL_QUERY);
}
#Override
public void insert() {
executeQuery(INSERT_QUERY, createData(DataAction.INSERT));
}
#Override
public void update() {
executeQuery(UPDATE_QUERY, createData(DataAction.UPDATE));
}
}
I am generally happy about the concrete implementation, it seems like I have managed to bring it down to a bare minimum, except public Account(final List<Object> data) does not seem that nice, but I can live with it.
However, as guessed, the getData() from Entity is definately not nice, and I would like to improve it if possible.
What I would like to use is something like DataType dataObject = new DataType(dataList), but it seems like Generic Type Arguments cannot be instantiated.
So are there any ways of optimizing my current code in my current view? And is it possible to decouple the concrete classes and abstract classes even more?
EDIT:
Added a relevant question (I don't think I should make a fully new question for this thing, right?):
Is there a way to move the static Strings (SQL Queries) and the insert() and update() out of the Account class, into the Entity class?
To avoid the use of reflection in your getData method you should accept a factory that given a ResultSet creates instances of the specific type. Your selectAll method would then be something like:
public static Map<String, Account> selectAll()
{
return getData(
new EntityFactory<Account>()
{
public Account newInstance(ResultSet resultSet) throws SQLException
{
return new Account(resultSet.getString(0), resultSet.getString(1));
}
},
SELECT_ALL_QUERY
);
}
The getData method then ends up something like:
protected static <K, T extends Entity<K>> Map<K, T> getData(EntityFactory<T> entityFactory, String query)
{
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try
{
connection = dataSource.getConnection();
preparedStatement = connection.prepareStatement(query);
resultSet = preparedStatement.executeQuery();
Map<K, T> entities = new HashMap<>();
while (resultSet.next())
{
Entity<K> entity = entityFactory.newInstance(resultSet);
entities.put(entity.getKey(), entity);
}
return entities;
}
finally
{
closeQuietly(resultSet);
closeQuietly(prepareStatement);
closeQuietly(connection);
}
}
And assumes the Entity looks like:
public interface Entity<K>
{
public K getKey();
}
This allows you to remove the reflection and keeps the code that understands the database structure in one place. You should also use a similar template pattern to map from the domain object to the prepared statement when doing inserts and updates.
Now you've asked for comments on the code in general.
First off, code like this violates the Single Responsibility Principal and Seperation Of Concerns. A domain class should be a domain class and not contain persistance logic. Look at patterns like the Data Access Object for how this should be done.
Second, while I'm all for keeping it simple, Hibernate solved this problem a long time ago and JPA standardized it - you need a very good reason not to use one or both of these APIs.
Finally, your use of database resources - if you are going to use JDBC directly you have to clean up properly. Database connections are expensive resources and should be handled as such, the basic template for any JDBC call should be:
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try
{
connection = //get connection from pool or single instance.
preparedStatement = connection.prepareStatement("SELECT * FROM table WHERE column = ?");
preparedStatement.setString(1, "some string");
resultSet = preparedStatement.executeQuery();
while (resultSet.next())
{
//logic goes here.
}
}
catch (SQLException e)
{
//Handle exceptions.
}
finally
{
closeQuietly(resultSet);
closeQuietly(prepareStatement);
closeQuietly(connection);
}
The closeQuietly method has to be overloaded but should take the general form:
try
{
if (resultSet != null)
{
resultSet.close();
}
}
catch (SQLException e)
{
//Log exceptions but don't re-throw.
}
Well, as Darwind and Nick Holt told you, in a normal situation, you should use JPA, which is the Java standard specification for object-relational mapping. You can use Hibernate, EclipseLink or any other framework behind. Their design is can manage connections, transactions. In addition, using standards rather than exotic frameworks means that you can get help more easily for the community.
Another option is using Spring JDBC, which is quite light and facilitates many things.
Anyway, I suppose you did this for learning purpose so let's try to go further.
First, I think you should separate the classes in charge or retrieving the data (call it manager or Data Access Object -DAO-) and the entites representing the data themselves.
For me, using the class to get all the data as you did isn't a problem in itself. The problem is the position of the key is hardcoded. This should not be determined directly a generic (I mean the same for all the Entity implementation). This makes queries subjects to bugs when the first field is not the key (are you sure a select * from... will ALWAYS return the key in the first position? ) or with a composite key.
I think a better solution is to crate a Mapper interface and to implement it for each entity.
public interface RecordMapper<KeyType, DataType extends Entity> {
public void appendToMap(ResultSet resultSet, Map<KeyType, DataType>) throws SQLException;
}
The implementation of the mapper should be in charge of instanciating your entity, retrieving the key from the resultset, populating your entity and putting it in the map you expect.
public class AccountMapper implement RecordMapper<String, Account>{
public void appendToMap(ResultSet resultSet, Map<String, Account> accounts) throws SQLException {
String user= resultSet.getString("userName");
String pwd= resultSet.getString("passWord");
Account account = new Account(user, pwd);
accounts.put(user, account);
}
}
As I told you should move your data access methods in a DAO:
public class DAO{
public <KeyType, DataType> Map<KeyType, DataType> getData(final RecordMapper<KeyType, DataType> mapper, final String query) {
Map<KeyType, DataType> map = new HashMap<>();
try {
PreparedStatement preparedStatement = DatabaseConnection.getConnection().prepareStatement(query);
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
mapper.appendToMap(resultSet, map);
}
} catch (SQLException ex) {
Logger.getLogger(Entity.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if(resultSet != null){
try{resultSet.close();} catch (Exception e){}
}
if(preparedStatement!= null){
try{preparedStatement.close();} catch (Exception e){}
}
}
return map;
}
public void executeQuery(final String query, final List<Object> data) {
try {
PreparedStatement preparedStatement = DatabaseConnection.getConnection().prepareStatement(query);
int dataIndex = 0;
for (Object dataObject : data) {
preparedStatement.setObject(dataIndex, dataObject);
dataIndex++;
}
preparedStatement.execute();
} catch (SQLException ex) {
Logger.getLogger(Entity.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if(resultSet != null){
try{resultSet.close();} catch (Exception e){}
}
if(preparedStatement!= null){
try{preparedStatement.close();} catch (Exception e){}
}
}
}
}
To answer your second quenstion, I think that putting your request string in the abstract parent instead of is certainly not a good idea. Each time you create new entity, you have to create a new query in the parent. Weird...unless I haven't understood properly your question.
Personnaly I think that the queries should be build dynamically and you should use reflection and annotations but the answer should be a bit long. Once again, you can get a look at JPA to see how creating an entity should look like. By the way, it should be even better if the entities didn't have to extend a parent Entity class.
I have a Java class with instance fields (and matching setter methods) that match the column names of a SQL database table. I would like to elegantly fetch a row from the table (into a ResultSet) and map it to an instance of this class.
For example:
I have a "Student" class with instance fields "FNAME", "LNAME", "GRADE" and appropriate getter and setter methods for each.
I also have a SQL table with three columns of the same name.
Right now I am doing something like this:
rs = statement.executeQuery(query);
Student student = new Student();
student.setFNAME(rs.getString("FNAME"));
student.setLNAME(rs.getString("LNAME"));
student.setGRADE(rs.getString("GRADE"));
There has to be a less verbose way of doing this, right? As I add columns this might get really annoying and messy.
I recommend using Spring JDBC. You don't need to use the rest of Spring to use their JDBC library. It will manage connections for you (no more closing Connection, Statement, or ResultSet) and has many conveniences, including row mapping.
We've retrofitted legacy code with Spring JDBC with little trouble.
Here is a presentation (PDF) of an overview of Spring JDBC. It's a few years old but it still works essentially the same, even without letting Spring inject the dependencies.
Spring JDBC Presentation PDF
You can do it generically by doing the following simple methods:
Interface to use as a method pointer:
public interface I_DBtoJavaObjectConvertable<T>
{
public T createFromDB(ResultSet i_rs) throws SQLException;
}
Generic class to handle every mapping from SQL to java Object:
public class DBManager
{
static volatile Connection conn;
//set here a static c'tor to handle the connection to the database
//The General generic method:
public static <T> List<T> GetObjectsFromDB(String i_Query, I_DBtoJavaObjectConvertable i_Converter)
{
List<T> ResList = new ArrayList<>();
try
{
Statement st = conn.createStatement();
for (ResultSet rs = st.executeQuery(i_Query); rs.next();)
{
ResList.add((T) i_Converter.createFromDB(rs));
}
}
catch (SQLException ex)
{
_LOG_ERROR(ex.getMessage());
}
return ResList;
}
}
Now By using Lanbda expression use can easlly convert an sql row to object, by given your convertion method, for example:
public static User FetchUserFromDB(ResultSet i_rs)
{
User userToCreate = null;
try
{
String FirstName = i_rs.getString("FirstName");
String LastName = i_rs.getString("LastName");
String Password = i_rs.getString("Password");
userToCreate = new User(FirstName, LastName, Password);
}
catch (SQLException ex)
{
_LOG_ERROR("Error in fetching user from DB: \n" + ex.getMessage());
}
return userToCreate;
}
And now you can use this this method to bring any Users you want:
public static List<User> GetAllUsersFromDB() throws SQLException
{
String Query = "select * "
+ "from UsersTable";
return DBManager.GetObjectsFromDB(Query, rs -> FetchUserFromDB(rs));
}
Or:
public static List<String> GetAllNamesFromDB() throws SQLException
{
String Query = "select FirstName "
+ "from UsersTable";
return DBManager.GetObjectsFromDB(Query, rs -> rs.getString("FirstName"));
}
You could use an ORM like one of the JPA providers e.g. Hibernate. This lets you set up mappings between your objects and your tables.
If you use JDBC that is how it works. If you want to avoid adding columns like this in Java, you may consider using some ORM frameworks.
A slightly less verbose way would be to give Student a constructor that accepts 3 strings. Then you could do this:
Student student = new Student(rs.getString("FNAME"), rs.getString("LNAME"), rs.getString("GRADE"));
The other way to do it is to use an ORM like Hibernate but Hibernate only becomes worth the massive setup effort for really big projects dealing with lots of tables.
There are many ORM libraries that simplify or eliminate the JDBC drudgery. See Source Forge ORM for some examples. I like my library, sormula, since it can be used with minimal configuration.
If you do not want to use any other framework, you can create standard mapping method and use it after every Result.
public class CurrencyDAO(){
public Currency findById(int id) {
String sql = "SELECT * FROM CCR.CURRENCY WHERE id = ?";
Currency currency = null;
Connection c = null;
try {
c = DBConnection.getConnection();
PreparedStatement ps = c.prepareStatement(sql);
ps.setInt(1, id);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
currency = processRow(rs);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
DBConnection.close(c);
}
return currency;
}
protected Currency processRow(ResultSet rs) throws SQLException {
Currency currency = new Currency();
currency.setId(rs.getInt("id"));
currency.setEUR(rs.getString("EUR"));
currency.setUSD(rs.getString("USD"));
currency.setRate(rs.getString("rate"));
return currency;
}
}
Give q2o a try. It is a JPA based object mapper which helps you with many of the tedious SQL and JDBC ResultSet related tasks, but without all the complexity an ORM framework comes with.
Bind the Student class to its corresponding table:
#Table(name = "STUDENTS")
public class Student (
private String FNAME;
private String LNAME;
private String GRADE;
...
)
Select some students by their grade:
List<Student> students = Q2ObjList.fromClause(Student.class, "GRADE = ?", grade);
Change a student's grade and persist the change to the database:
student.setGRADE(grade);
Q2obj.update(student);
q2o is helpful even when you depend on Spring JDBC:
jdbcTemplate.queryForObject("...", new RowMapper<Student>() {
#Override
public Student mapRow(final ResultSet rs, final int rowNum) throws SQLException {
return Q2Obj.fromResultSet(rs, Student.class);
}
});
It is pretty easy, isn't it? Find more about q2o here.
When you execute a query you can get metadata from the ResultSet. You have access to the columns from this. Here's an example:
#RestController
public class MyController {
#GetMapping("/characters")
public List<Payload> characters() {
List<Payload> results = new ArrayList<>();
try (Connection conn = new Connection()) {
conn.makeConnection();
Statement stmt = conn.createStatement();
ResultSet result = stmt.executeQuery("SELECT * FROM public.hello;");
ResultSetMetaData resultMetaData = result.getMetaData();
Set<String> columns = new HashSet<>();
for (int i = 1; i <= resultMetaData.getColumnCount(); i++) {
columns.add(resultMetaData.getColumnName(i));
}
while (result.next()) {
results.add(new Data(result, columns));
}
} catch (Exception e) {
results.add(new Fail("404", e.getMessage()));
}
return results;
}
}
public class Data implements Payload {
private final Map<String, Object> data = new HashMap<>();
public Data(ResultSet result, Set<String> columns) throws SQLException {
for (String column : columns) {
data.put(column, result.getString(column));
}
}
public Map<String, Object> getData() {
return data;
}
}
Now you can have one class object that parses out the columns and data for any table. You never really care what columns there are. The down side is that all of your info is now stored in a data field. So the payload would look something like:
[
{"data":{"id":"1","name":"Rick Sanchez"}},
{"data":{"id":"2","name":"Morty Smith"}},
{"data":{"id":"3","message":"Summer Smith"}}
]
Is there any way to access caller-scoped variables from an anonymous inner class in Java?
Here's the sample code to understand what I need:
public Long getNumber(final String type, final String refNumber, final Long year) throws ServiceException {
Long result = null;
try {
Session session = PersistenceHelper.getSession();
session.doWork(new Work() {
public void execute(Connection conn) throws SQLException {
CallableStatement st = conn.prepareCall("{ CALL PACKAGE.procedure(?, ?, ?, ?) }");
st.setString(1, type);
st.setString(2, refNumber);
st.setLong(3, year);
st.registerOutParameter(4, OracleTypes.NUMBER);
st.execute();
result = st.getLong(4) ;
}
});
} catch (Exception e) {
log.error(e);
}
return result;
}
The code is in a DAO service class. Obviously it doesn't compile, because it asks that result be final, if it is -- it doesn't compile because I try to modify a final var. I'm bound to JDK5. Other than dropping the doWork() altogether, is there a way to set the result value from within doWork()?
Java doesn't know that doWork is going to be synchronous and that the stack frame that result is in will still be there. You need to alter something that isn't in the stack.
I think this would work
final Long[] result = new Long[1];
and then
result[0] = st.getLong(4);
in execute(). At the end, you need to return result[0];
You might want to make a class because you don't like how it looks to use an array here, but this is the basic idea.
This situation arises a lot in Java, and the cleanest way to handle it is with a simple value container class. It's the same type thing as the array approach, but it's cleaner IMO.
public class ValContainer<T> {
private T val;
public ValContainer() {
}
public ValContainer(T v) {
this.val = v;
}
public T getVal() {
return val;
}
public void setVal(T val) {
this.val = val;
}
}
You need a 'container' to hold your value. You, however, do not have to create a container class. You may use classes in the java.util.concurrent.atomic package. They provide an immutable wrapper for a value along with a set and a get method. You have AtomicInteger, AtomicBoolean, AtomicReference<V> (for your objects) e.t.c
In the outer method:
final AtomicLong resultHolder = new AtomicLong();
In the anonymous inner class method
long result = getMyLongValue();
resultHolder.set(result);
Later in your outer method
return resultHolder.get();
Here's an example.
public Long getNumber() {
final AtomicLong resultHolder = new AtomicLong();
Session session = new Session();
session.doWork(new Work() {
public void execute() {
//Inside anonymous inner class
long result = getMyLongValue();
resultHolder.set(result);
}
});
return resultHolder.get(); //Returns the value of result
}
Long is immutable. If you use a mutable class, holding a long value, you can change the value. For example:
public class Main {
public static void main( String[] args ) throws Exception {
Main a = new Main();
System.out.println( a.getNumber() );
}
public void doWork( Work work ) {
work.doWork();
}
public Long getNumber() {
final LongHolder result = new LongHolder();
doWork( new Work() {
public void doWork() {
result.value = 1L;
}
} );
return result.value;
}
private static class LongHolder {
public Long value;
}
private static abstract class Work {
public abstract void doWork();
}
}
If the containing class is MyClass -->
MyClass.this.variable = value;
Do not remember if this would work with a private variable (I think it would work).
Only works for attributes of the class (class variable). Does not work for method local variables. In JSE 7 probably there will be closures to do that kind of thing.
Anonymous classes/methods are not closures - this is exactly the difference.
The problem is that doWork() could create a new thread to call execute() and getNumber() could return before the result is set - and even more problematically: where should execute() write the result when the stack frame that contains the variable is gone? Languages with closures have to introduce a mechanism to keep such variables alive outside their original scope (or ensure that the closure is not executed in a separate thread).
A workaround:
Long[] result = new Long[1];
...
result[0] = st.getLong(4) ;
...
return result[0];
The standard solution to this is to return a value. See, for instance, ye olde java.security.AccessController.doPrivileged.
So the code would look something like this:
public Long getNumber(
final String type, final String refNumber, final Long year
) throws ServiceException {
try {
Session session = PersistenceHelper.getSession();
return session.doWork(new Work<Long>() {
public Long execute(Connection conn) throws SQLException {
CallableStatement st = conn.prepareCall("{ CALL PACKAGE.procedure(?, ?, ?, ?) }");
try {
st.setString(1, type);
st.setString(2, refNumber);
st.setLong(3, year);
st.registerOutParameter(4, OracleTypes.NUMBER);
st.execute();
return st.getLong(4);
} finally {
st.close();
}
}
});
} catch (Exception e) {
throw ServiceException(e);
}
}
(Also fixed the potential resource leak, and returning null for any error.)
Update: So apparently Work is from a third-party library and can't be altered. So I suggest not using it, at least isolate your application from so that you are not using it directly. Something like:
public interface WithConnection<T> {
T execute(Connection connnection) throws SQLException;
}
public class SessionWrapper {
private final Session session;
public SessionWrapper(Session session) {
session = nonnull(session);
}
public <T> T withConnection(final WithConnection<T> task) throws Service Exception {
nonnull(task);
return new Work() {
T result;
{
session.doWork(this);
}
public void execute(Connection connection) throws SQLException {
result = task.execute(connection);
}
}.result;
}
}
As of Hibernate 4, the method Session#doReturningWork(ReturningWork<T> work) will return the return val from the inner method:
public Long getNumber(final String type, final String refNumber, final Long year) throws ServiceException {
try {
Session session = PersistenceHelper.getSession();
return session.doReturningWork(conn -> {
CallableStatement st = conn.prepareCall("{ CALL PACKAGE.procedure(?, ?, ?, ?) }");
st.setString(1, type);
st.setString(2, refNumber);
st.setLong(3, year);
st.registerOutParameter(4, OracleTypes.NUMBER);
st.execute();
return st.getLong(4);
});
} catch (Exception e) {
log.error(e);
}
return null;
}
(Cleaned up using a Java 8 lambda)
Using AtomicLong helped me in a very similar situation and the code looked clean.
// Create a new final AtomicLong variable with the initial value 0.
final AtomicLong YOUR_VARIABLE = new AtomicLong(0);
...
// set long value to the variable within inner class
YOUR_VARIABLE.set(LONG_VALUE);
...
// get the value even outside the inner class
YOUR_VARIABLE.get();