I'm coming from PHP and moved to java. I'm asking myself (and you guys) if there is a way to implement someting like this:
I'm trying to implement a class/classes to create CRUD operations for many database entities. All entities inherit their functions (most of them from the parent)
I need to implement the tableName and idFieldName in the parent class DatabaseEntity to avoid compiler warnings.
It seems like java tries to use the parents properties (which are obviously null) because the function is implemented in the parent.
Is there a way to overcome this problem? Any feedback is greatly apreciated!
abstract class DatabaseEntity {
protected String tableName;
protected String idFieldName;
public DataRecord readFromDB(int recordID) throws SQLException {
...
String sqlStatement = String.format("SELECT * FROM %s WHERE %s = %s", this.tableName, this.idFieldName, recordID); // Exception shows this line
...
}
}
class DatabaseRecord extends DatabaseEntity {
protected String tableName = "DatabaseRecordTable";
protected String idFieldName = "ID";
public void getRecord() {
...
DataRecord record = this.readFromDB(1); // leads to java.lang.NullPointerException: null
...
}
}
Disclaimer: I'm new to github and I apreciate any feedback on improoving my posts :)
when you use the method readFromDBin which you refer to the tableNameand the idFieldName, these two fields remain nullas long as they are not initailized,
try to remove the fields from your abstract class and do something like this :
abstract class DatabaseEntity {
// protected String tableName;
// protected String idFieldName;
public abstract String getTableName();
public abstract String getIdFieldName() ;
public DataRecord readFromDB(int recordID) throws SQLException {
...
String sqlStatement = String.format("SELECT * FROM %s WHERE %s = %s",getTableName(), getIdFieldName(), recordID);
...
}
}
and the implementation would be like :
class DatabaseRecord extends DatabaseEntity {
protected String tableName = "DatabaseRecordTable";
protected String idFieldName = "ID";
public void getRecord() throws SQLException {
DataRecord record = this.readFromDB(1);
}
#Override
public String getTableName() {
return this.tableName;
}
#Override
public String getIdFieldName() {
return this.idFieldName ;
}
}
Related
I have the following class which I'm using as the base of all the models in my project:
public abstract class BaseModel
{
static String table;
static String idField = "id";
public static boolean exists(long id) throws Exception
{
Db db = Util.getDb();
Query q = db.query();
q.select( idField ).whereLong(idField, id).limit(1).get(table);
return q.hasResults();
}
//snip..
}
I'm then trying to extend from it, in the following way:
public class User extends BaseModel
{
static String table = "user";
//snip
}
However, if I try to do the following:
if ( User.exists( 4 ) )
//do something
Then, rather than the query: "SELECT id FROM user WHERE id = ?", it is producing the query: "SELECT id from null WHERE id = ?". So, the overriding of the table field in the User class doesn't seem to be having any effect.
How do I overcome this? If I added a setTable() method to BaseModel, and called setTable() in the constructor of User, then will the new value of table be available to all methods of the User class as well?
You cannot override static methods or fields of any type in Java.
public class User extends BaseModel
{
static String table = "user";
//snip
}
This creates a new field User#table that just happens to have the same name as BaseModel#table. Most IDEs will warn you about that.
If you change the value of the field in BaseModel, it will apply to all other model classes as well.
One way is to have the base methods generic
protected static boolean exists(String table, long id) throws Exception
{
Db db = Util.getDb();
Query q = db.query();
q.select( idField ).whereLong(idField, id).limit(1).get(table);
return q.hasResults();
}
and use it in the subclass
public static boolean exists(long id)
{
return exists("user", id);
}
If you want to use the field approach, you have to create a BaseDAO class and have a UserDAO (one for each model class) that sets the field accordingly. Then you create singleton instances of all the daos.
Because Java doesn't allow you to override static members, you basically need to resort to the slightly more verbose but overall nicer singleton pattern, wherein you're still conceptually writing "static" code, but you're technically using (global/singleton/"static") instances, so you're not restricted by the limitations of static.
(note that you also need to use methods because fields don't participate in polymorphism, and thus cannot be overridden)
public abstract class BaseTable {
public abstract String table();
public String idField() { return "id"; }
public boolean exists(long id) {
// don't build queries this way in real life though!
System.out.println("SELECT count(*) FROM " + table() + " WHERE " + idField() + " = " + id);
return true;
}
}
public class UserTable extends BaseTable {
public static final User INSTANCE = new UserTable();
private UseTabler() {}
#Override public String table() { return "user"; }
}
public class PostTable extends BaseTable {
public static final Post INSTANCE = new PostTable();
private PostTable() {}
#Override public String table() { return "post"; }
}
public static void main(String[] args) {
UserTable.INSTANCE.exists(123);
PostTable.INSTANCE.exists(456);
}
Outputs:
SELECT count(*) FROM user WHERE id = 123
SELECT count(*) FROM post WHERE id = 456
In order to do what you are looking to do, don't make table static in the BaseModel. Then in the other classes that inherit from BaseModel, you can set table in the default constructor to whatever you wish.
static {
table = "user";
}
public class TableContent {
public static String EXCEL_SHEET_NAME = Nit.THEAD.getName();
public static String FILENAME= Nit.FILENAME.getName();
public enum Nit {
FILENAME("Nit-workorder-list"),
THEAD("NIT WORKORDER"),
TENDERSPECNO("TENDER SPECFICATION NO."),
FEE("TENDER FEE"),
SDAMOUNT("SD AMOUNT"),
TYPE("NIT TYPE"),
PRE_BID("PRE BIDDING DATE"),
OPEN_DATE("OPENING DATE"),
STATUS("CONTRACTOR STATUS");
private final String name;
public String getName() {
return name;
}
private Nit(String name) {
this.name = name;
}
public static Nit getNitHeadByName(String name)
{
Nit[] nit=Nit.values();
if(nit==null)
{
return null;
}
for(Nit nitHead:nit)
{
if(nitHead.getName().equals(name))
return nitHead;
}
return null;
}
public enum NitWorkOrder {
}
public enum NitList {
}
My objective is:
I want to export excel sheet from my application, every time I need to hardcode the table headings, which was not good programming practice.
So I use enum to overcome the hardcode problem. Now there are different table heading according to the list, then I enclosed all the required ENUMS in single class.
I used to write getXXXByName() and getXXXByValue() to access the enum, by name or by value.
But he problem is I need to write getXXXByName() and getXXXByValue() everytime inside each enum. I want to write these methods inside the class and outside the enums, and access those methods with the help of class name.
I just want to declare my constants inside enum.
Please kindly suggest me an idea or a way so I can make this method universal which will work for each and every enum. I want to write these methods in such a way so it can be accessed for all enums enclosed in my class. I thought about generics but I have little knowledge.
You can use generics to push functionality up to a parent class by telling the parent class that the type is an enum that implements an interface.
// Use an interface to inform the super class what the enums can do.
public interface Named {
public String getName();
}
// Super class of all Tables.
public static class Table<E extends Enum<E> & Named> {
private final Class<E> itsClass;
private final String sheetName;
private final String fileName;
public Table(Class<E> itsClass) {
this.itsClass = itsClass;
// Walk the enum to get filename and sheet name.
String sheetName = null;
String fileName = null;
for ( E e: itsClass.getEnumConstants() ){
if ( e.name().equals("FILENAME")) {
fileName = e.getName();
}
if ( e.name().equals("THEAD")) {
sheetName = e.getName();
}
}
this.sheetName = sheetName;
this.fileName = fileName;
}
// Use the interface and the enum details to do your stuff.
public E getByName (String name) {
for ( E e: itsClass.getEnumConstants() ){
if ( e.getName().equals(name)) {
return e;
}
}
return null;
}
}
// Extend Table and tell it about your enum using the super constructor.
public static class TableContent extends Table<TableContent.Nit> {
public TableContent() {
super(TableContent.Nit.class);
}
public enum Nit implements Named{
FILENAME("Nit-workorder-list"),
THEAD("NIT WORKORDER"),
TENDERSPECNO("TENDER SPECFICATION NO."),
FEE("TENDER FEE"),
SDAMOUNT("SD AMOUNT"),
TYPE("NIT TYPE"),
PRE_BID("PRE BIDDING DATE"),
OPEN_DATE("OPENING DATE"),
STATUS("CONTRACTOR STATUS");
private final String name;
Nit(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}
I am working on a project that utilizes a database with several relations. We are working with tables such as:
Customers(id, f_name, l_name)
CreditCards(cardNum, expDate, securityCode)
BillingInfo(id, f_name, l_name, address, city, zip)
etc...
Using Java Database Connectivity, my question is, is there a common way one performs queries on these relations?
Even before getting to the "guts" of this project, I envision being able to call some method void insert(int id, String f_name, String l_name), a member method of a hypothetical CustomerQueryHandler class. This class would of course be accompanied by other methods such as a delete and update method.
I figured I'd start with an abstract class called QueryHandler:
import java.sql.*;
public abstract class QueryHandler {
protected String jdbcUrl = null;
protected String userid = null;
protected String password = null;
protected Connection conn;
QueryHandler(String url_in, String id_in, String pass_in) {
this.jdbcUrl = url_in;
this.userid = id_in;
this.password = pass_in;
try {
this.ds = new OracleDataSource();
} catch (SQLException e) {
e.printStackTrace();
}
ds.setURL(this.jdbcUrl);
try {
conn = ds.getConnection(userid, password);
} catch (SQLException e) {
e.printStackTrace();
}
}
public abstract void insert(/*not sure of signature*/);
public abstract void update(/*not sure of signature*/);
public abstract void delete(/*not sure of signature*/);
/* OTHER METHODS BELOW */
}
There would be a derived class for each table and each derived class would implement its own version of insert, update, and delete:
public class CustomersQueryHandler extends QueryHandler {
public CustomersQueryHandler(String url_in, String id_in, String pass_in) {
super(String url_in, String id_in, String pass_in);
}
...
This is actually the point where I became very confused because, does it make sense for this to be a superclass, even though each subclass will have its own parameter list for the aforementioned methods?
I have the following class which I'm using as the base of all the models in my project:
public abstract class BaseModel
{
static String table;
static String idField = "id";
public static boolean exists(long id) throws Exception
{
Db db = Util.getDb();
Query q = db.query();
q.select( idField ).whereLong(idField, id).limit(1).get(table);
return q.hasResults();
}
//snip..
}
I'm then trying to extend from it, in the following way:
public class User extends BaseModel
{
static String table = "user";
//snip
}
However, if I try to do the following:
if ( User.exists( 4 ) )
//do something
Then, rather than the query: "SELECT id FROM user WHERE id = ?", it is producing the query: "SELECT id from null WHERE id = ?". So, the overriding of the table field in the User class doesn't seem to be having any effect.
How do I overcome this? If I added a setTable() method to BaseModel, and called setTable() in the constructor of User, then will the new value of table be available to all methods of the User class as well?
You cannot override static methods or fields of any type in Java.
public class User extends BaseModel
{
static String table = "user";
//snip
}
This creates a new field User#table that just happens to have the same name as BaseModel#table. Most IDEs will warn you about that.
If you change the value of the field in BaseModel, it will apply to all other model classes as well.
One way is to have the base methods generic
protected static boolean exists(String table, long id) throws Exception
{
Db db = Util.getDb();
Query q = db.query();
q.select( idField ).whereLong(idField, id).limit(1).get(table);
return q.hasResults();
}
and use it in the subclass
public static boolean exists(long id)
{
return exists("user", id);
}
If you want to use the field approach, you have to create a BaseDAO class and have a UserDAO (one for each model class) that sets the field accordingly. Then you create singleton instances of all the daos.
Because Java doesn't allow you to override static members, you basically need to resort to the slightly more verbose but overall nicer singleton pattern, wherein you're still conceptually writing "static" code, but you're technically using (global/singleton/"static") instances, so you're not restricted by the limitations of static.
(note that you also need to use methods because fields don't participate in polymorphism, and thus cannot be overridden)
public abstract class BaseTable {
public abstract String table();
public String idField() { return "id"; }
public boolean exists(long id) {
// don't build queries this way in real life though!
System.out.println("SELECT count(*) FROM " + table() + " WHERE " + idField() + " = " + id);
return true;
}
}
public class UserTable extends BaseTable {
public static final User INSTANCE = new UserTable();
private UseTabler() {}
#Override public String table() { return "user"; }
}
public class PostTable extends BaseTable {
public static final Post INSTANCE = new PostTable();
private PostTable() {}
#Override public String table() { return "post"; }
}
public static void main(String[] args) {
UserTable.INSTANCE.exists(123);
PostTable.INSTANCE.exists(456);
}
Outputs:
SELECT count(*) FROM user WHERE id = 123
SELECT count(*) FROM post WHERE id = 456
In order to do what you are looking to do, don't make table static in the BaseModel. Then in the other classes that inherit from BaseModel, you can set table in the default constructor to whatever you wish.
static {
table = "user";
}
I have found myself in the need to override a static method, simply because it makes most sense, but I also know this is not possible.
The superclass, Entity.java:
abstract public class Entity<T> {
public Entity() {
//set up database connection
}
abstract public static Map<Object, T> getAll();
abstract public void insert();
abstract public void update();
protected void getData(final String query) {
//get data via database
}
protected void executeQuery(final String query) {
//execute sql query on database
}
}
One of the many concrete implementations, Account.java:
public class Account extends Entity<Account> {
private final static String 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;
}
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;
}
#Override
public static Map<Object, Account> getAll() {
//return a map using the ALL_QUERY string, calls getData(string);
}
#Override
public void insert() {
//insert this using INSERT_QUERY, calls executeQuery(string);
}
#Override
public void update() {
//update this using UPDATE_QUERY, calls executeQuery(string);
}
}
I haven't been going in depth explaining the code, but any general feedback on it would also be appreciated, I hope the comments explain enough.
So basically I think we can all agree that using Account.getAll() makes more sense over new Account().getAll() (if I would introduce a dummy syntax for it).
However I do want to have it extend the Entity class, currently it is only for convienience, but later on I may have to use sets/lists/multisets of Entity and perform an update() action on all of them, for example if I would build some queue that performances all updates every minute.
So well, is there a way to construct getAll() correctly?
Regards.
You could have separate classes for operations on all elements:
abstract public class Collection<T extends Entity<T>> {
abstract public static List<T> getAll();
public void printAll() {
// Print all entries of List obtained from getAll()
}
}
Which you could use as:
public class Accounts extends Collection<Account> {
#Override
public List<Account> getAll() {
//return a list using the ALL_QUERY string, calls getData(string);
}
}
It doesn't seems to me that it is really "simply because it makes most sense".
Tying persistence at your entity is not a good idea. There are already lots of patterns that give an appropriate design on this problem.
For example, in Domain Driven Design, "Persistence Ignorance" is what people trying to achieve. Consider making a Repository for each of your entity:
interface Repository<T> {
List<T> findAll();
void insert(T);
void update(T);
}
so you can override it by whatever way you want:
interface UserRepository extends Repository<User> {
// some other methods which is meaningful for User
User findByLoginName(String loginName);
}
class UserRepositoryImpl implements UserRepository {
List<User> findAll() {
// call whatever query
}
void insert(T){...}
void update(T){...}
User findByLoginName(String loginName) {...}
}
With a proper design and a component to handle the retrieval/storage of entity, you can have a less-persistence-coupled entity, and with repository that can perform proper "overriding".