diff --git a/README.md b/README.md index 3f95f02..2e3670a 100644 --- a/README.md +++ b/README.md @@ -190,4 +190,6 @@ using prepared statement. - [Accessing Databases Through JDBC with Java](https://app.pluralsight.com/projects/accessing-databases-through-jdbc-in-java) - [Design_Patterns_In_Java_CRUD](https://github.com/naman14310/Design_Patterns_In_Java_CRUD) - [Database Normalization](http://extreme-java.blogspot.com/2014/05/database-normalization.html) -- [Database Interaction with DAO and DTO Design Patterns](https://dzone.com/articles/database-interaction-dao-and) \ No newline at end of file +- [Database Interaction with DAO and DTO Design Patterns](https://dzone.com/articles/database-interaction-dao-and) +- [`try`-with-resources](https://en.wikipedia.org/wiki/Java_syntax#try-with-resources_statements) +- [tryResourceClose](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html) \ No newline at end of file diff --git a/pom.xml b/pom.xml index 915dc3e..296a541 100644 --- a/pom.xml +++ b/pom.xml @@ -61,11 +61,36 @@ org.jetbrains annotations - RELEASE + 23.1.0 compile + + + + org.projectlombok + lombok + 1.18.24 + provided + + + + + org.apache.maven.plugins + maven-pmd-plugin + 3.19.0 + + + + pmd-ruleset.xml + + + + + + + orders @@ -97,6 +122,32 @@ maven-surefire-plugin 2.22.2 + + org.apache.maven.plugins + maven-pmd-plugin + 3.19.0 + + + true + + true + + + + pmd-ruleset.xml + + + + + + pmd-check + verify + + check + + + + diff --git a/src/main/java/com/example/order/Main.java b/src/main/java/com/example/order/Main.java index 9561573..689fced 100644 --- a/src/main/java/com/example/order/Main.java +++ b/src/main/java/com/example/order/Main.java @@ -13,6 +13,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.sql.SQLException; import java.util.ArrayList; import java.util.List; @@ -32,11 +33,10 @@ public class Main { * * @param args Command and arguments to be interpreted by the application */ - public static void main(String[] args) { - BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); - String command = ""; + public static void main(String[] args) throws SQLException, IOException { - try { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) { + String command = ""; while (!Commands.EXIT.getCmd().equalsIgnoreCase(command)) { System.out.print(INITIAL_PROMPT); String line = reader.readLine(); @@ -63,7 +63,7 @@ public static void main(String[] args) { * * @param args Arguments given to the application */ - private static void processCommand(String[] args) { + private static void processCommand(String[] args) throws SQLException, IOException { String error = validateArgs(args); if (isEmpty(error)) { @@ -120,10 +120,9 @@ private static void processCommand(String[] args) { */ private static @NotNull OrderDto askForOrderDetails() { OrderDto orderDTO = new OrderDto(); - BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); - boolean invalidInput; - try { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) { + boolean invalidInput; /* Ask for customer ID */ do { System.out.print("Customer ID: "); @@ -141,7 +140,7 @@ private static void processCommand(String[] args) { do { OrderDetailDto orderDetailDTO = new OrderDetailDto(); - // Ask for product ID + /* Ask for product ID */ do { System.out.print("Product ID: "); String line = reader.readLine(); diff --git a/src/main/java/com/example/order/dao/DeleteOrderDao.java b/src/main/java/com/example/order/dao/DeleteOrderDao.java index 2e30d9d..a8246cb 100644 --- a/src/main/java/com/example/order/dao/DeleteOrderDao.java +++ b/src/main/java/com/example/order/dao/DeleteOrderDao.java @@ -5,6 +5,7 @@ import com.example.order.util.ExceptionHandler; import org.jetbrains.annotations.NotNull; +import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; @@ -32,7 +33,7 @@ public DeleteOrderDao(Database database) { * @param paramsDto Object with the parameters for the operation * @return Number of orders deleted */ - public int deleteOrdersById(@NotNull ParamsDto paramsDto) { + public int deleteOrdersById(@NotNull ParamsDto paramsDto) throws IOException { int numberResults = 0; try (Connection con = database.getConnection(); diff --git a/src/main/java/com/example/order/dao/GetOrderDao.java b/src/main/java/com/example/order/dao/GetOrderDao.java index 36dafef..b5ffe79 100644 --- a/src/main/java/com/example/order/dao/GetOrderDao.java +++ b/src/main/java/com/example/order/dao/GetOrderDao.java @@ -6,6 +6,7 @@ import com.example.order.util.ExceptionHandler; import org.jetbrains.annotations.NotNull; +import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -16,7 +17,7 @@ * DAO to get an order */ public class GetOrderDao { - private final String query = "SELECT * FROM orders o WHERE o.order_id = ?"; + private final static String query = "SELECT * FROM orders o WHERE o.order_id = ?"; private final Database database; /** @@ -53,8 +54,8 @@ public OrderDto getOrderById(ParamsDto paramsDto) { orderDto.setStatus(rs.getString(4)); } - } catch (SQLException ex) { - ExceptionHandler.handleException(ex); + } catch (SQLException | IOException ex) { + ExceptionHandler.handleException((SQLException) ex); } return orderDto; diff --git a/src/main/java/com/example/order/dao/InsertOrderDao.java b/src/main/java/com/example/order/dao/InsertOrderDao.java index 4fd9002..2e324dd 100644 --- a/src/main/java/com/example/order/dao/InsertOrderDao.java +++ b/src/main/java/com/example/order/dao/InsertOrderDao.java @@ -7,6 +7,7 @@ import com.example.order.util.OrderStatus; import org.jetbrains.annotations.NotNull; +import java.io.IOException; import java.sql.*; import java.time.LocalDateTime; @@ -38,7 +39,7 @@ public InsertOrderDao(Database database) { * @param orderDto Object with the information to insert * @return The ID of the order inserted */ - public long insertOrder(OrderDto orderDto) { + public long insertOrder(OrderDto orderDto) throws IOException { long orderId = -1; try (Connection con = database.getConnection(); diff --git a/src/main/java/com/example/order/dao/TotalOrderDao.java b/src/main/java/com/example/order/dao/TotalOrderDao.java index fcfc766..9f457dc 100644 --- a/src/main/java/com/example/order/dao/TotalOrderDao.java +++ b/src/main/java/com/example/order/dao/TotalOrderDao.java @@ -5,6 +5,7 @@ import com.example.order.util.ExceptionHandler; import org.jetbrains.annotations.NotNull; +import java.io.IOException; import java.math.BigDecimal; import java.sql.*; @@ -12,7 +13,7 @@ * DAO to get the total of all the paid orders of a customer */ public class TotalOrderDao { - private final String query = "{call GET_PAID_ORDER_TOTAL_FROM_CUSTOMER(?)}"; + private final static String query = "{call GET_PAID_ORDER_TOTAL_FROM_CUSTOMER(?)}"; private final Database database; /** @@ -30,7 +31,7 @@ public TotalOrderDao(Database database) { * @param paramsDto Object with the arguments of the operation * @return Total of all paid orders */ - public BigDecimal getTotalAllPaidOrders(ParamsDto paramsDto) { + public BigDecimal getTotalAllPaidOrders(ParamsDto paramsDto) throws SQLException, IOException { BigDecimal result = null; try (Connection con = database.getConnection(); diff --git a/src/main/java/com/example/order/dao/UpdateOrderDao.java b/src/main/java/com/example/order/dao/UpdateOrderDao.java index 8e83b45..44966f6 100644 --- a/src/main/java/com/example/order/dao/UpdateOrderDao.java +++ b/src/main/java/com/example/order/dao/UpdateOrderDao.java @@ -5,6 +5,7 @@ import com.example.order.util.ExceptionHandler; import org.jetbrains.annotations.NotNull; +import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; @@ -13,7 +14,6 @@ * DAO to update an order */ public class UpdateOrderDao { - private final String query = "UPDATE orders o SET o.order_status = ? WHERE o.order_id = ?"; private final Database database; /** @@ -31,7 +31,7 @@ public UpdateOrderDao(Database database) { * @param paramsDto Object with the parameters for the operation * @return Number of affected rows */ - public int updateOrderStatus(ParamsDto paramsDto) { + public int updateOrderStatus(ParamsDto paramsDto) throws IOException { int numberResults = 0; try (Connection con = database.getConnection(); @@ -55,6 +55,7 @@ public int updateOrderStatus(ParamsDto paramsDto) { * @throws SQLException In case of an error */ private @NotNull PreparedStatement createPreparedStatement(@NotNull Connection con, @NotNull ParamsDto paramsDto) throws SQLException { + String query = "UPDATE orders o SET o.order_status = ? WHERE o.order_id = ?"; PreparedStatement ps = con.prepareStatement(query); ps.setString(1, paramsDto.getStatus()); ps.setLong(2, paramsDto.getOrderId()); diff --git a/src/main/java/com/example/order/service/DeleteOrderService.java b/src/main/java/com/example/order/service/DeleteOrderService.java index 043a3bd..cd860fa 100644 --- a/src/main/java/com/example/order/service/DeleteOrderService.java +++ b/src/main/java/com/example/order/service/DeleteOrderService.java @@ -4,6 +4,8 @@ import com.example.order.dto.ParamsDto; import com.example.order.util.Database; +import java.io.IOException; + /** * Service class to delete one or more orders */ @@ -16,7 +18,7 @@ public class DeleteOrderService implements OrderService { * @param paramsDTO Object with the parameters to execute the service */ @Override - public String execute(ParamsDto paramsDTO) { + public String execute(ParamsDto paramsDTO) throws IOException { String result; int rowsAffected = deleteOrderDao.deleteOrdersById(paramsDTO); diff --git a/src/main/java/com/example/order/service/InsertOrderService.java b/src/main/java/com/example/order/service/InsertOrderService.java index 53cf3e7..d8c1481 100644 --- a/src/main/java/com/example/order/service/InsertOrderService.java +++ b/src/main/java/com/example/order/service/InsertOrderService.java @@ -5,6 +5,8 @@ import com.example.order.util.Database; import org.jetbrains.annotations.NotNull; +import java.io.IOException; + /** * Service class to insert an order */ @@ -17,7 +19,7 @@ public class InsertOrderService implements OrderService { * @param paramsDTO Object with the parameters to execute the service */ @Override - public String execute(@NotNull ParamsDto paramsDTO) { + public String execute(@NotNull ParamsDto paramsDTO) throws IOException { String result; long orderId = insertOrderDao.insertOrder(paramsDTO.getOrder()); diff --git a/src/main/java/com/example/order/service/OrderService.java b/src/main/java/com/example/order/service/OrderService.java index 43b47fb..ff62763 100644 --- a/src/main/java/com/example/order/service/OrderService.java +++ b/src/main/java/com/example/order/service/OrderService.java @@ -2,9 +2,12 @@ import com.example.order.dto.ParamsDto; +import java.io.IOException; +import java.sql.SQLException; + /** * Interface for service classes */ public interface OrderService { - String execute(ParamsDto paramsDTO); + String execute(ParamsDto paramsDTO) throws IOException, SQLException; } diff --git a/src/main/java/com/example/order/service/TotalOrderService.java b/src/main/java/com/example/order/service/TotalOrderService.java index 984e6a8..9d89de6 100644 --- a/src/main/java/com/example/order/service/TotalOrderService.java +++ b/src/main/java/com/example/order/service/TotalOrderService.java @@ -4,7 +4,9 @@ import com.example.order.dto.ParamsDto; import com.example.order.util.Database; +import java.io.IOException; import java.math.BigDecimal; +import java.sql.SQLException; /** * Service class to get the total of the orders of a customer @@ -18,7 +20,7 @@ public class TotalOrderService implements OrderService { * @param paramsDTO Object with the parameters to execute the service */ @Override - public String execute(ParamsDto paramsDTO) { + public String execute(ParamsDto paramsDTO) throws IOException, SQLException { String result; BigDecimal total = totalOrderDao.getTotalAllPaidOrders(paramsDTO); diff --git a/src/main/java/com/example/order/service/UpdateOrderService.java b/src/main/java/com/example/order/service/UpdateOrderService.java index fac31b5..b3954ec 100644 --- a/src/main/java/com/example/order/service/UpdateOrderService.java +++ b/src/main/java/com/example/order/service/UpdateOrderService.java @@ -4,6 +4,8 @@ import com.example.order.dto.ParamsDto; import com.example.order.util.Database; +import java.io.IOException; + /** * Service class to update an order */ @@ -16,7 +18,7 @@ public class UpdateOrderService implements OrderService { * @param paramsDTO Object with the parameters to execute the service */ @Override - public String execute(ParamsDto paramsDTO) { + public String execute(ParamsDto paramsDTO) throws IOException { String result; int rowsAffected = updateOrderDao.updateOrderStatus(paramsDTO); diff --git a/src/main/java/com/example/order/util/Database.java b/src/main/java/com/example/order/util/Database.java index f069082..30366c1 100644 --- a/src/main/java/com/example/order/util/Database.java +++ b/src/main/java/com/example/order/util/Database.java @@ -2,6 +2,7 @@ import org.h2.tools.RunScript; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.sql.Connection; @@ -10,14 +11,16 @@ /** * Singleton class to get database connections + * + * @link https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom */ public class Database { private static Database instance = null; private static boolean isInitialized = false; - private final String url = "jdbc:h2:mem:orders;DB_CLOSE_DELAY=-1"; - private final String user = "sa"; - private final String password = ""; + private static final String url = "jdbc:h2:mem:orders;DB_CLOSE_DELAY=-1"; + private static final String user = "sa"; + private static final String password = ""; /** * Private constructor @@ -25,6 +28,10 @@ public class Database { private Database() { } + private static class LazyHolder { + static final Database INSTANCE = new Database(); + } + /** * Method that creates an instance of this class (if it's not created already) * @@ -32,7 +39,7 @@ private Database() { */ public static Database getInstance() { if (instance == null) { - instance = new Database(); + instance = LazyHolder.INSTANCE; } return instance; } @@ -42,7 +49,7 @@ public static Database getInstance() { * * @param connection Object that represents a connection to the database */ - private static void initializeDatabase(Connection connection) { + private static void initializeDatabase(Connection connection) throws IOException { try { InputStream is = Database.class.getResourceAsStream("/db.sql"); assert is != null; @@ -58,7 +65,7 @@ private static void initializeDatabase(Connection connection) { * @return A connection object * @throws SQLException In case of a database error */ - public Connection getConnection() throws SQLException { + public Connection getConnection() throws SQLException, IOException { Connection connection = DriverManager.getConnection(url, user, password); if (!isInitialized && connection != null) { diff --git a/src/main/java/com/example/order/util/ExceptionHandler.java b/src/main/java/com/example/order/util/ExceptionHandler.java index 1befdbb..57d9f0d 100644 --- a/src/main/java/com/example/order/util/ExceptionHandler.java +++ b/src/main/java/com/example/order/util/ExceptionHandler.java @@ -1,7 +1,5 @@ package com.example.order.util; -import org.jetbrains.annotations.NotNull; - import java.sql.SQLException; /** @@ -14,7 +12,7 @@ public class ExceptionHandler { * * @param sqlException Exception from which information will be extracted */ - public static void handleException(@NotNull SQLException sqlException) { + public static void handleException(SQLException sqlException) { System.out.println(sqlException.getErrorCode()); System.out.println(sqlException.getSQLState()); System.out.println(sqlException.getMessage()); diff --git a/src/main/java/com/example/order/util/H2StoredProcedures.java b/src/main/java/com/example/order/util/H2StoredProcedures.java index c3e4dad..f82b5ff 100644 --- a/src/main/java/com/example/order/util/H2StoredProcedures.java +++ b/src/main/java/com/example/order/util/H2StoredProcedures.java @@ -27,8 +27,10 @@ public static ResultSet getPaidOrderTotalFromCustomer(@NotNull Connection conn, PreparedStatement ps = conn.prepareStatement(sql.toString()); ResultSet results = ps.executeQuery(); - while (results.next()) + + while (results.next()) { joiner.add(results.getString("order_id")); + } sql = new StringBuilder(); sql.append("SELECT SUM( MULT(product_price, order_detail_quantity) ) FROM order_details, products "); diff --git a/src/test/java/com/example/order/DatabaseTest.java b/src/test/java/com/example/order/DatabaseTest.java index 7797155..d0f4ed4 100644 --- a/src/test/java/com/example/order/DatabaseTest.java +++ b/src/test/java/com/example/order/DatabaseTest.java @@ -100,8 +100,7 @@ public void shouldUseDriverManagerToConnectToDB() { con.close(); } catch (Exception e) { //e.printStackTrace(); - assertTrue("The connection is not valid. The method `getConnection()` threw an exception. Make sure you're opening the connection with the right parameters.", - false); + fail("The connection is not valid. The method `getConnection()` threw an exception. Make sure you're opening the connection with the right parameters."); } } } diff --git a/src/test/java/com/example/order/DeleteOrderDaoTest.java b/src/test/java/com/example/order/DeleteOrderDaoTest.java index 52b7fde..a8ee97e 100644 --- a/src/test/java/com/example/order/DeleteOrderDaoTest.java +++ b/src/test/java/com/example/order/DeleteOrderDaoTest.java @@ -1,5 +1,6 @@ package com.example.order; +import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.sql.Connection; @@ -54,7 +55,7 @@ public void setup() { } @Test - public void shouldCreateDatabaseConnection() throws SQLException { + public void shouldCreateDatabaseConnection() throws SQLException, IOException { Database databaseMock = Mockito.mock(Database.class); when(databaseMock.getConnection()).thenReturn(databaseInstance.getConnection()); diff --git a/src/test/java/com/example/order/GetOrderDaoTest.java b/src/test/java/com/example/order/GetOrderDaoTest.java index 008860f..5f72a0c 100644 --- a/src/test/java/com/example/order/GetOrderDaoTest.java +++ b/src/test/java/com/example/order/GetOrderDaoTest.java @@ -1,5 +1,6 @@ package com.example.order; +import java.io.IOException; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.PreparedStatement; @@ -35,7 +36,7 @@ public void setup() { } @Test - public void shouldCreateDatabaseConnection() throws SQLException { + public void shouldCreateDatabaseConnection() throws SQLException, IOException { when(databaseMock.getConnection()).thenReturn(databaseInstance.getConnection()); GetOrderDao getOrderDao = new GetOrderDao(databaseMock); diff --git a/src/test/java/com/example/order/InsertOrderDaoTest.java b/src/test/java/com/example/order/InsertOrderDaoTest.java index 54f272b..f034165 100644 --- a/src/test/java/com/example/order/InsertOrderDaoTest.java +++ b/src/test/java/com/example/order/InsertOrderDaoTest.java @@ -1,5 +1,6 @@ package com.example.order; +import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.sql.*; @@ -54,7 +55,7 @@ public void setup() { } @Test - public void shouldGetConnectionObject() throws SQLException { + public void shouldGetConnectionObject() throws SQLException, IOException { Database databaseMock = Mockito.mock(Database.class); when(databaseMock.getConnection()).thenReturn(databaseInstance.getConnection()); diff --git a/src/test/java/com/example/order/TotalOrderDaoTest.java b/src/test/java/com/example/order/TotalOrderDaoTest.java index 0aee472..d6dc884 100644 --- a/src/test/java/com/example/order/TotalOrderDaoTest.java +++ b/src/test/java/com/example/order/TotalOrderDaoTest.java @@ -1,5 +1,6 @@ package com.example.order; +import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigDecimal; @@ -49,7 +50,7 @@ public void setup() { } @Test - public void shouldGetConnectionObject() throws SQLException { + public void shouldGetConnectionObject() throws SQLException, IOException { Database databaseMock = Mockito.mock(Database.class); when(databaseMock.getConnection()).thenReturn(databaseInstance.getConnection()); diff --git a/src/test/java/com/example/order/UpdateOrderDaoTest.java b/src/test/java/com/example/order/UpdateOrderDaoTest.java index b7bf8c0..f8d78e1 100644 --- a/src/test/java/com/example/order/UpdateOrderDaoTest.java +++ b/src/test/java/com/example/order/UpdateOrderDaoTest.java @@ -1,5 +1,6 @@ package com.example.order; +import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.sql.Connection; @@ -52,7 +53,7 @@ public void setup() { } @Test - public void shouldCreateDatabaseConnection() throws SQLException { + public void shouldCreateDatabaseConnection() throws SQLException, IOException { Database databaseMock = Mockito.mock(Database.class); when(databaseMock.getConnection()).thenReturn(databaseInstance.getConnection());