Java and JSP
General conventions
- Try to separate data ‘Entity’ classes, which contain data from logic classes which operate on the data and IO classes which manage the persistence of the data.
- Use the same names for the Java entity (data) classes for the associated PostgreSQL table.
- Use the singular version in both cases (not the plural version for tables). Except where we have to avoid SQL reserved words e.g. the ‘Users’ and 'Orders' tables.
- Use the same name for the Java entity (data) class member variables and the associated column in the PostgreSQL table.
- Be aware that while the Java classes may be case-sensitive camel-case, the names in the Postgres schema and SQL logic are case-insensitive.
- Use that name as the prefix for the IO classes which manage the JDBC persistence of the data between the entity class and PostgreSQL table.
- One of the goals is to carry names for the same entity across the system. So a global 'find in files' type text search will tend to find all the related elements.
- So this means we tend
notto use lower with under_score naming convention in the database and peripheral languages such as Javascript. - Prefer not prefixing argument variables with
ae.g. preferorderIdoveraOrderId. - Also, contrary to the other projects, prefer capitalising only the first letter of an acronym when naming variables e.g. prefer
orderIdoverorderID.
Specific conventions
Java
- Follow the conventions described here: https://www.Javatpoint.com/Java-naming-conventions
- Package names are all lowercase.
- Class names are camel case starting with an uppercase char and no underscores.
- Method names are camel case starting with a lowercase char and no underscores.
- Class member variables are camel case, starting with a lowercase prefix 'm' and no underscores.
- Class member variables are private or protected (not public), with public set
() and get () methods to access them. - Method parameter names are camel case, no longer start with a lowercase prefix 'a', and contain no underscores.
- Local variables are camel case starting with a lowercase char, no special prefix char or underscores.
- Static ‘constant’ variables are all UPPER_CASE with underscores.
- The maximum size of DB character columns is set in Java as a public static variable in the related entity class.
- Use Java base types for numeric, boolean variables wherever possible, e.g int and not Integer.
- Try to avoid nullable numeric columns in PostgreSQL - as null is awkward to translate to Java base types.
- Use Java
long(not int) for entity id variables. Although historically we have usedintfor many entity ids. - We tend to use
-1, to represent "not set" inidinto or long variables. - Use the full name for id variables consistently across the system. e.g. primary key
TradeIdis used in the Trade class, in other variables and in foreign-key and references - like Bid.TradeId.
Examples
As a clean example, the core of our Voucher processing involves these elements;
com.bidorbuy.bobe.voucher- Java packageVoucher- Java entity classVoucher- PostgreSQL tableVoucherIO- Java JDBC persistence classVoucherTransaction- Java entity classVoucherTransaction- PostgreSQL tableVoucherTransactionIO- Java JDBC persistence classVoucherInterface- the collections of logic methods for managingVouchersandVoucherTransactions
Please Note: For historical reasons, we tend to have much of our logic in static methods in classes with the ‘Interface’ suffix, e.g. VoucherInterface.mySampleMethod().
This is not ideal as the classes are not actually Java ‘Interfaces'.
If we ever refactor this convention we would do it in a more ‘Spring’-like way, using something like the 'Service’ suffix, and implement Service classes and singletons and not use static methods. As we now do for our IO classes. e.g. VoucherService.getInstance().mySampleMethod(). But for now we will stick with our convention for consistency.
Using the Voucher.Java as an example:
package com.bidorbuy.bobe.voucher;
import com.bidorbuy.bobe.enumlistitem.VoucherStatus;
import com.bidorbuy.bobe.enumlistitem.VoucherType;
import com.bidorbuy.bobe.user.HasUserId;
import Java.time.LocalDate;
import Java.time.LocalDateTime;
/**
* Entity class representing a Voucher definition record.
*/
public class Voucher implements HasUserId {
//---- GENERATED CODE START -----------
//------------------------------------
// Attribute Name Definitions
public static final String VOUCHER = "Voucher";
public static final String VOUCHERID = "Voucher_VoucherId";
public static final String USERID = "Voucher_UserId";
public static final String VOUCHERTYPE = "Voucher_VoucherType";
public static final String STATUS = "Voucher_Status";
public static final String AMOUNT = "Voucher_Amount";
public static final String USEDAMOUNT = "Voucher_UsedAmount";
public static final String CREATIONTIME = "Voucher_CreationTime";
public static final String LASTMODIFIEDTIME = "Voucher_LastModifiedTime";
public static final String EXPIRYDATE = "Voucher_ExpiryDate";
public static final String ASSIGNEDTIME = "Voucher_AssignedTime";
public static final String VOUCHERGROUPID = "Voucher_VoucherGroupId";
public static final String VOUCHERCODE = "Voucher_VoucherCode";
public static final String FROMUSERID = "Voucher_FromUserId";
public static final String ADMINUSERID = "Voucher_AdminUserId";
public static final String ORDERID = "Voucher_OrderId";
public static final String PAYMENTTRANSACTIONID = "Voucher_PaymentTransactionId";
public static final String CLIENTDEVICEID = "Voucher_ClientDeviceId";
public static final String IPADDRESS = "Voucher_IPAddress";
public static final String ADMINNOTE = "Voucher_AdminNote";
public static final String SYSTEMNOTE = "Voucher_SystemNote";
//------------------------------------
// Attribute Set & Get Methods
/** Sets the value for the attribute VoucherId.
* @param long the value to set.
*/
public void setVoucherId(long aValue) { mVoucherId = aValue; }
/** Returns the value for the attribute VoucherId.
* @return long the VoucherId attribute.
*/
public long getVoucherId() { return mVoucherId; }
/** Sets the value for the attribute UserId.
* @param int the value to set.
*/
public void setUserId(int aValue) { mUserId = aValue; }
/** Returns the value for the attribute UserId.
* @return int the UserId attribute.
*/
public int getUserId() { return mUserId; }
/** Sets the value for the attribute VoucherType.
* @param VoucherType the value to set.
*/
public void setVoucherType(VoucherType aValue) { mVoucherType = aValue; }
/** Returns the value for the attribute VoucherType.
* @return VoucherType the VoucherType attribute.
*/
public VoucherType getVoucherType() { return mVoucherType; }
/** Sets the value for the attribute Status.
* @param VoucherStatus the value to set.
*/
public void setStatus(VoucherStatus aValue) { mStatus = aValue; }
/** Returns the value for the attribute Status.
* @return VoucherStatus the Status attribute.
*/
public VoucherStatus getStatus() { return mStatus; }
/** Sets the value for the attribute Amount.
* @param double the value to set.
*/
public void setAmount(double aValue) { mAmount = aValue; }
/** Returns the value for the attribute Amount.
* @return double the Amount attribute.
*/
public double getAmount() { return mAmount; }
/** Sets the value for the attribute UsedAmount.
* @param double the value to set.
*/
public void setUsedAmount(double aValue) { mUsedAmount = aValue; }
/** Returns the value for the attribute UsedAmount.
* @return double the UsedAmount attribute.
*/
public double getUsedAmount() { return mUsedAmount; }
/** Sets the value for the attribute CreationTime.
* @param LocalDateTime the value to set.
*/
public void setCreationTime(LocalDateTime aValue) { mCreationTime = aValue; }
/** Returns the value for the attribute CreationTime.
* @return LocalDateTime the CreationTime attribute.
*/
public LocalDateTime getCreationTime() { return mCreationTime; }
/** Sets the value for the attribute LastModifiedTime.
* @param LocalDateTime the value to set.
*/
public void setLastModifiedTime(LocalDateTime aValue) { mLastModifiedTime = aValue; }
/** Returns the value for the attribute LastModifiedTime.
* @return LocalDateTime the LastModifiedTime attribute.
*/
public LocalDateTime getLastModifiedTime() { return mLastModifiedTime; }
/** Sets the value for the attribute ExpiryDate.
* @param LocalDate the value to set.
*/
public void setExpiryDate(LocalDate aValue) { mExpiryDate = aValue; }
/** Returns the value for the attribute ExpiryDate.
* @return LocalDate the ExpiryDate attribute.
*/
public LocalDate getExpiryDate() { return mExpiryDate; }
/** Sets the value for the attribute AssignedTime.
* @param LocalDateTime the value to set.
*/
public void setAssignedTime(LocalDateTime aValue) { mAssignedTime = aValue; }
/** Returns the value for the attribute AssignedTime.
* @return LocalDateTime the AssignedTime attribute.
*/
public LocalDateTime getAssignedTime() { return mAssignedTime; }
/** Sets the value for the attribute VoucherGroupId.
* @param int the value to set.
*/
public void setVoucherGroupId(int aValue) { mVoucherGroupId = aValue; }
/** Returns the value for the attribute VoucherGroupId.
* @return int the VoucherGroupId attribute.
*/
public int getVoucherGroupId() { return mVoucherGroupId; }
/** Sets the value for the attribute VoucherCode.
* @param String the value to set.
*/
public void setVoucherCode(String aValue) { mVoucherCode = aValue; }
/** Returns the value for the attribute VoucherCode.
* @return String the VoucherCode attribute.
*/
public String getVoucherCode() { return mVoucherCode; }
/** Sets the value for the attribute FromUserId.
* @param int the value to set.
*/
public void setFromUserId(int aValue) { mFromUserId = aValue; }
/** Returns the value for the attribute FromUserId.
* @return int the FromUserId attribute.
*/
public int getFromUserId() { return mFromUserId; }
/** Sets the value for the attribute AdminUserId.
* @param int the value to set.
*/
public void setAdminUserId(int aValue) { mAdminUserId = aValue; }
/** Returns the value for the attribute AdminUserId.
* @return int the AdminUserId attribute.
*/
public int getAdminUserId() { return mAdminUserId; }
/** Sets the value for the attribute OrderId.
* @param int the value to set.
*/
public void setOrderId(int aValue) { mOrderId = aValue; }
/** Returns the value for the attribute OrderId.
* @return int the OrderId attribute.
*/
public int getOrderId() { return mOrderId; }
/** Sets the value for the attribute PaymentTransactionId.
* @param int the value to set.
*/
public void setPaymentTransactionId(int aValue) { mPaymentTransactionId = aValue; }
/** Returns the value for the attribute PaymentTransactionId.
* @return int the PaymentTransactionId attribute.
*/
public int getPaymentTransactionId() { return mPaymentTransactionId; }
/** Sets the value for the attribute ClientDeviceId.
* @param long the value to set.
*/
public void setClientDeviceId(long aValue) { mClientDeviceId = aValue; }
/** Returns the value for the attribute ClientDeviceId.
* @return long the ClientDeviceId attribute.
*/
public long getClientDeviceId() { return mClientDeviceId; }
/** Sets the value for the attribute IPAddress.
* @param String the value to set.
*/
public void setIPAddress(String aValue) { mIPAddress = aValue; }
/** Returns the value for the attribute IPAddress.
* @return String the IPAddress attribute.
*/
public String getIPAddress() { return mIPAddress; }
/** Sets the value for the attribute AdminNote.
* @param String the value to set.
*/
public void setAdminNote(String aValue) { mAdminNote = aValue; }
/** Returns the value for the attribute AdminNote.
* @return String the AdminNote attribute.
*/
public String getAdminNote() { return mAdminNote; }
/** Sets the value for the attribute SystemNote.
* @param String the value to set.
*/
public void setSystemNote(String aValue) { mSystemNote = aValue; }
/** Returns the value for the attribute SystemNote.
* @return String the SystemNote attribute.
*/
public String getSystemNote() { return mSystemNote; }
/** Returns a string representation of the the entity object.
*
* @return String.
*
*/
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("VoucherId").append("=").append(mVoucherId).append(", ");
sb.append("UserId").append("=").append(mUserId).append(", ");
sb.append("VoucherType").append("=").append(mVoucherType).append(", ");
sb.append("Status").append("=").append(mStatus).append(", ");
sb.append("Amount").append("=").append(mAmount).append(", ");
sb.append("UsedAmount").append("=").append(mUsedAmount).append(", ");
sb.append("CreationTime").append("=").append(mCreationTime).append(", ");
sb.append("LastModifiedTime").append("=").append(mLastModifiedTime).append(", ");
sb.append("ExpiryDate").append("=").append(mExpiryDate).append(", ");
sb.append("AssignedTime").append("=").append(mAssignedTime).append(", ");
sb.append("VoucherGroupId").append("=").append(mVoucherGroupId).append(", ");
sb.append("VoucherCode").append("=").append(mVoucherCode).append(", ");
sb.append("FromUserId").append("=").append(mFromUserId).append(", ");
sb.append("AdminUserId").append("=").append(mAdminUserId).append(", ");
sb.append("OrderId").append("=").append(mOrderId).append(", ");
sb.append("PaymentTransactionId").append("=").append(mPaymentTransactionId).append(", ");
sb.append("ClientDeviceId").append("=").append(mClientDeviceId).append(", ");
sb.append("IPAddress").append("=").append(mIPAddress).append(", ");
sb.append("AdminNote").append("=").append(mAdminNote).append(", ");
sb.append("SystemNote").append("=").append(mSystemNote);
return sb.toString();
}
//---- GENERATED CODE END -----------
/** Voucher Default Constructor
*/
public Voucher() { }
// Constants
public static final int UNSPECIFIED = -1;
public static final int VOUCHERCODE_SIZE = 50;
public static final int IPADDRESS_SIZE = 40;
public static final int ADMINNOTE_SIZE = 500;
public static final int SYSTEMNOTE_SIZE = 500;
// Attributes
private long mVoucherId = UNSPECIFIED;
private int mUserId = UNSPECIFIED;
private VoucherType mVoucherType = VoucherType.UNSPECIFIED;
private VoucherStatus mStatus = VoucherStatus.UNSPECIFIED;
private double mAmount = 0.00;
private double mUsedAmount = 0.00;
private LocalDateTime mCreationTime = LocalDateTime.now();
private LocalDateTime mLastModifiedTime = LocalDateTime.now();
private LocalDate mExpiryDate = LocalDate.now();
private LocalDateTime mAssignedTime = null;
private int mVoucherGroupId = UNSPECIFIED;
private String mVoucherCode = null;
private int mFromUserId = UNSPECIFIED;
private int mAdminUserId = UNSPECIFIED;
private int mOrderId = UNSPECIFIED;
private int mPaymentTransactionId = UNSPECIFIED;
private long mClientDeviceId = UNSPECIFIED;
private String mIPAddress = "";
private String mAdminNote = null;
private String mSystemNote = null;
}
Tools and assistance
EntityClassGenerator
The EntityClassGenerator will generate a complete standardised entity class based on just the class outline and member variables code. If member variables are adjusted the EntityClassGenerator can be rerun to produce an adjusted class.
The generated code includes getXX(), setXX(), toString() methods. And static member name strings to use as parameter names.
e.g.
$> cat Bird.Java
package com.bidorbuy.bobe.bird;
/**
* Entity class representing a Bird.
*/
public class Bird {
/**
*/
public Bird() { }
// Constants
public static final int UNSPECIFIED = -1;
public static final int NAME_SIZE = 100;
// Attributes
private long mBirdId = UNSPECIFIED;
private String mName = null;
private double mWingSpanCm = 0.00;
}
$> bash ~/Workspaces/bob/bobe/scripts/runide.sh com.bidorbuy.tools.EntityClassGenerator Bird.Java
J/J 24/08/22 11:04:21 Running job with normal-memory: 'com.bidorbuy.tools.EntityClassGenerator Bird.Java
Generating Code for the following Attributes
long mBirdId
String mName
double mWingSpanCm
J/J 24/08/22 11:04:21 Completed job!
$> cat Bird.Java
package com.bidorbuy.bobe.voucher;
/**
* Entity class representing a Bird.
*/
public class Bird {
//---- GENERATED CODE START -----------
//------------------------------------
// Attribute Name Definitions
public static final String BIRD = "Bird";
public static final String BIRDID = "Bird_BirdId";
public static final String NAME = "Bird_Name";
public static final String WINGSPANCM = "Bird_WingSpanCm";
//------------------------------------
// Attribute Set & Get Methods
/** Sets the value for the attribute BirdId.
* @param long the value to set.
*/
public void setBirdId(long aValue) { mBirdId = aValue; }
/** Returns the value for the attribute BirdId.
* @return long the BirdId attribute.
*/
public long getBirdId() { return mBirdId; }
/** Sets the value for the attribute Name.
* @param String the value to set.
*/
public void setName(String aValue) { mName = aValue; }
/** Returns the value for the attribute Name.
* @return String the Name attribute.
*/
public String getName() { return mName; }
/** Sets the value for the attribute WingSpanCm.
* @param double the value to set.
*/
public void setWingSpanCm(double aValue) { mWingSpanCm = aValue; }
/** Returns the value for the attribute WingSpanCm.
* @return double the WingSpanCm attribute.
*/
public double getWingSpanCm() { return mWingSpanCm; }
/** Returns a string representation of the the entity object.
*
* @return String.
*
*/
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("BirdId").append("=").append(mBirdId).append(", ");
sb.append("Name").append("=").append(mName).append(", ");
sb.append("WingSpanCm").append("=").append(mWingSpanCm);
return sb.toString();
}
//---- GENERATED CODE END -----------
/**
*/
public Bird() { }
// Constants
public static final int UNSPECIFIED = -1;
public static final int NAME_SIZE = 100;
// Attributes
private long mBirdId = UNSPECIFIED;
private String mName = null;
private double mWingSpanCm = 0.00;
}
JDBCObjectIO
JDBC entity IO classes should be inherited from JDBCObjectIO<T>.
The class can then define the specific logic to identify insert, update and select columns and mapping logic.
And the underlying JDBCObjectIO will automatically provide a variety of insert, update and select operations to manage persistence between the Java entity object and the related table.
package com.bidorbuy.bobe.bird;
import com.bidorbuy.bobe.jdbc.JDBCObjectIO;
import com.bidorbuy.bobe.jdbc.JDBCObjectReader;
import com.bidorbuy.bobe.jdbc.JDBCObjectWriter;
import com.bidorbuy.bobe.jdbc.JDBCUtility;
import Java.sql.PreparedStatement;
import Java.sql.ResultSet;
import Java.sql.SQLException;
/**
* A class for the IO between Bird objects and the Bird database table.
*/
public class BirdIO extends JDBCObjectIO<Bird> {
private static BirdIO mInstance;
static {
mInstance = new BirdIO();
mInstance
.setTableName("Bird")
.setTableAlias("b")
.setInsertSQL("insert into Bird (BirdId, Name, WingSpanCm) values (?,?,?)")
.setInsertJDBCObjectWriter(
new JDBCObjectWriter<Bird>() {
public int writeObject(PreparedStatement aPreparedStatement, Bird aBird) throws SQLException {
if(aBird.getBirdId() == Bird.UNSPECIFIED) {
aBird.setBirdId(JDBCUtility.getNextSequenceIdLong(aPreparedStatement.getConnection(), "BirdId_SEQ"));
}
int param = 1;
aPreparedStatement.setLong(param++, aBird.getBirdId());
aPreparedStatement.setString(param++, StringUtility.truncate(aBird.getName(), BIRD.NAME_SIZE));
aPreparedStatement.setDouble(param++, aBird.getWingSpanCm());
return param;
}
})
.setUpdateSQL("update Bird set Name=?, WingSpanCm=? where BirdId=?")
.setUpdateJDBCObjectWriter(
new JDBCObjectWriter<Bird>() {
public int writeObject(PreparedStatement aPreparedStatement, Bird aBird) throws SQLException {
int param = 1;
aPreparedStatement.setString(param++, StringUtility.truncate(aBird.getName(), BIRD.NAME_SIZE));
aPreparedStatement.setDouble(param++, aBird.getWingSpanCm());
aPreparedStatement.setLong(param++, aBird.getBirdId());
return param;
}
})
.setSelectColumnsSQL("b.BirdId, b.Name, b.WingSpanCm")
.setJDBCObjectReader(
new JDBCObjectReader<Bird>() {
public Bird readObject(ResultSet aResultSet) throws SQLException {
Bird Bird = new Bird();
int columnIndex = 1;
Bird.setBirdId(aResultSet.getLong(columnIndex++));
Bird.setName(aResultSet.getString(columnIndex++));
Bird.setWingSpanCm(aResultSet.getDouble(columnIndex++));
return Bird;
}
}
);
}
/**
*
* @return
*/
public static BirdIO getInstance() {
return mInstance;
}
/**
*
*/
private BirdIO() {
}
}
List, ListItem and EnumListItem
Where possible represent new static or semi-static lists with entries in List and ListItem tables.
And instead of using a coded Java enum, generate a specialised class based on a List which inherits from EnumListItem.
The advantages are:
- Avoid creating additional tables for each new type of list.
- List and ListItem are cached in Java memory for fast access.
- Our generated EnumListItem classes are more powerful than conventional Java enums.
- We end up with a consistent sense of List and ENum values in Java and in PostgreSQL
plsqllogic - all derived from the common List and ListItem values.