mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-05-14 08:58:26 +00:00
feature: Implement Serialized Entity Pattern (#2150)
* Add files: - App.java - Country.java - CountryDao.java - CountrySchemaSql.java - CountryTest.java - README.md - serialize-entity.urm.puml - pom.xml (inherit from parent pom.xml) Update files: - pom.xml (parent pom.xml, add 1 module called serialized-entity) * Fix duplicated error in pom.xml * Update: - pom.xml (module servant, changed by error, now fixed) - pom.xml (module serialized-entity) * Update: - pom.xml (changed, artifactId) * Update: - pom.xml Add: AppTest.java * Resolved changes required by the reviewer Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
This commit is contained in:
@@ -215,6 +215,7 @@
|
||||
<module>composite-view</module>
|
||||
<module>metadata-mapping</module>
|
||||
<module>service-to-worker</module>
|
||||
<module>serialized-entity</module>
|
||||
<module>identity-map</module>
|
||||
</modules>
|
||||
<repositories>
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
---
|
||||
title: Serialized Entity Pattern
|
||||
categories: Architectural
|
||||
language: en
|
||||
tags:
|
||||
- Data access
|
||||
---
|
||||
|
||||
|
||||
## Intent
|
||||
|
||||
To easily persist Java objects to the database.
|
||||
|
||||
## Explanation
|
||||
Java serialization allow us to convert the object to a set of bytes. We can store these bytes into database as
|
||||
BLOB(binary long objects) and read them at any time and reconstruct them into Java objects.
|
||||
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
Walking through our customers example, here's the basic `Customer` entity.
|
||||
|
||||
```java
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
@AllArgsConstructor
|
||||
public class Country implements Serializable {
|
||||
|
||||
private int code;
|
||||
private String name;
|
||||
private String continents;
|
||||
private String language;
|
||||
public static final long serialVersionUID = 7149851;
|
||||
// Constructor ->
|
||||
// getters and setters ->
|
||||
}
|
||||
|
||||
```
|
||||
Here is `CountrySchemaSql`, this class have method allow us to serialize `Country` object and insert it into the
|
||||
database, also have a method that read serialized data from the database and deserialize it to `Country` object.
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
public class CountrySchemaSql {
|
||||
public static final String CREATE_SCHEMA_SQL = "CREATE TABLE IF NOT EXISTS WORLD (ID INT PRIMARY KEY, COUNTRY BLOB)";
|
||||
|
||||
public static final String DELETE_SCHEMA_SQL = "DROP TABLE WORLD IF EXISTS";
|
||||
|
||||
private Country country;
|
||||
private DataSource dataSource;
|
||||
|
||||
/**
|
||||
* Public constructor.
|
||||
*
|
||||
* @param dataSource datasource
|
||||
* @param country country
|
||||
*/
|
||||
public CountrySchemaSql(Country country, DataSource dataSource) {
|
||||
this.country = new Country(
|
||||
country.getCode(),
|
||||
country.getName(),
|
||||
country.getContinents(),
|
||||
country.getLanguage()
|
||||
);
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will serialize a Country object and store it to database.
|
||||
* @return int type, if successfully insert a serialized object to database then return country code, else return -1.
|
||||
* @throws IOException if any.
|
||||
*/
|
||||
public int insertCountry() throws IOException {
|
||||
var sql = "INSERT INTO WORLD (ID, COUNTRY) VALUES (?, ?)";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oss = new ObjectOutputStream(baos)) {
|
||||
|
||||
oss.writeObject(country);
|
||||
oss.flush();
|
||||
|
||||
preparedStatement.setInt(1, country.getCode());
|
||||
preparedStatement.setBlob(2, new ByteArrayInputStream(baos.toByteArray()));
|
||||
preparedStatement.execute();
|
||||
return country.getCode();
|
||||
} catch (SQLException e) {
|
||||
LOGGER.info("Exception thrown " + e.getMessage());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will select a data item from database and deserialize it.
|
||||
* @return int type, if successfully select and deserialized object from database then return country code,
|
||||
* else return -1.
|
||||
* @throws IOException if any.
|
||||
* @throws ClassNotFoundException if any.
|
||||
*/
|
||||
public int selectCountry() throws IOException, ClassNotFoundException {
|
||||
var sql = "SELECT ID, COUNTRY FROM WORLD WHERE ID = ?";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
|
||||
preparedStatement.setInt(1, country.getCode());
|
||||
|
||||
try (ResultSet rs = preparedStatement.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
Blob countryBlob = rs.getBlob("country");
|
||||
ByteArrayInputStream baos = new ByteArrayInputStream(countryBlob.getBytes(1, (int) countryBlob.length()));
|
||||
ObjectInputStream ois = new ObjectInputStream(baos);
|
||||
country = (Country) ois.readObject();
|
||||
LOGGER.info("Country: " + country);
|
||||
}
|
||||
return rs.getInt("id");
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.info("Exception thrown " + e.getMessage());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
This `App.java` will first delete a World table from the h2 database(if there is one) and create a new table called
|
||||
`WORLD` to ensure we have a table we want.
|
||||
It will then create two `Country` objects called `China` and `UnitedArabEmirates`, then create two `CountrySchemaSql`
|
||||
objects and use objects `China` and `UnitedArabEmirates` as arguments.
|
||||
Finally, call `SerializedChina.insertCountry()` and `serializedUnitedArabEmirates.insertCountry()` to serialize and
|
||||
store them to database, and call `SerializedChina.selectCountry()` and `serializedUnitedArabEmirates.selectCountry()`
|
||||
methods to read and deserialize data items to `Country` objects.
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
public class App {
|
||||
private static final String DB_URL = "jdbc:h2:~/test";
|
||||
|
||||
private App() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
* @param args command line args.
|
||||
* @throws IOException if any
|
||||
* @throws ClassNotFoundException if any
|
||||
*/
|
||||
public static void main(String[] args) throws IOException, ClassNotFoundException {
|
||||
final var dataSource = createDataSource();
|
||||
|
||||
deleteSchema(dataSource);
|
||||
createSchema(dataSource);
|
||||
|
||||
final var China = new Country(
|
||||
86,
|
||||
"China",
|
||||
"Asia",
|
||||
"Chinese"
|
||||
);
|
||||
|
||||
final var UnitedArabEmirates = new Country(
|
||||
971,
|
||||
"United Arab Emirates",
|
||||
"Asia",
|
||||
"Arabic"
|
||||
);
|
||||
|
||||
final var serializedChina = new CountrySchemaSql(China, dataSource);
|
||||
final var serializedUnitedArabEmirates = new CountrySchemaSql(UnitedArabEmirates, dataSource);
|
||||
serializedChina.insertCountry();
|
||||
serializedUnitedArabEmirates.insertCountry();
|
||||
|
||||
serializedChina.selectCountry();
|
||||
serializedUnitedArabEmirates.selectCountry();
|
||||
}
|
||||
|
||||
private static void deleteSchema(DataSource dataSource) {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement()) {
|
||||
statement.execute(CountrySchemaSql.DELETE_SCHEMA_SQL);
|
||||
} catch (SQLException e) {
|
||||
LOGGER.info("Exception thrown " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void createSchema(DataSource dataSource) {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement()) {
|
||||
statement.execute(CountrySchemaSql.CREATE_SCHEMA_SQL);
|
||||
} catch (SQLException e) {
|
||||
LOGGER.info("Exception thrown " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static DataSource createDataSource() {
|
||||
var dataSource = new JdbcDataSource();
|
||||
dataSource.setURL(DB_URL);
|
||||
return dataSource;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Class diagram
|
||||

|
||||
|
||||
## Applicability
|
||||
|
||||
Use the Serialized Entity pattern when
|
||||
|
||||
* You want to easily persist Java objects to the database.
|
||||
|
||||
## Related patterns
|
||||
[Data Access Object](https://github.com/iluwatar/java-design-patterns/tree/master/dao)
|
||||
|
||||
## Credits
|
||||
|
||||
* [J2EE Design Patterns by William Crawford, Jonathan Kaplan](https://www.oreilly.com/library/view/j2ee-design-patterns/0596004273/re21.html)
|
||||
* [komminen](https://github.com/komminen/java-design-patterns) (His attempts of serialized-entity inspired me and learned a lot from his code)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
@@ -0,0 +1,56 @@
|
||||
@startuml
|
||||
package com.iluwatar.serializedentity {
|
||||
class App {
|
||||
- DB_URL : String {static}
|
||||
- LOGGER : Logger {static}
|
||||
+ App()
|
||||
- createDataSource() : DataSource {static}
|
||||
- createSchema(dataSource : DataSource) {static}
|
||||
- deleteSchema(dataSource : DataSource) {static}
|
||||
+ main(args : String[]) {static}
|
||||
}
|
||||
|
||||
class Country {
|
||||
- code : int
|
||||
- name : String
|
||||
- continents : String
|
||||
- language : String
|
||||
+ serialVersionUID : final Long {static}
|
||||
~Country(int, String, String, String)
|
||||
+ getCode() : int
|
||||
+ getName() : String
|
||||
+ getContinents() : String
|
||||
+ getLanguage() : String
|
||||
+ setCode(code : int)
|
||||
+ setName(name : String)
|
||||
+ setContinents(continents : String)
|
||||
+ setLanguage(language : String)
|
||||
+ equals(that: Object) : boolean
|
||||
+ hashCode() : int
|
||||
+ toString() : String
|
||||
}
|
||||
|
||||
interface CountryDao {
|
||||
+ insertCountry : int {abstract}
|
||||
+ selectCountry : int {abstract}
|
||||
}
|
||||
|
||||
class CountrySchemaSql {
|
||||
- CREATE_SCHEMA_SQL : String {static}
|
||||
- DELETE_SCHEMA_SQL : String {static}
|
||||
- LOGGER : Logger {static}
|
||||
- dataSource : DataSource
|
||||
- country : Country
|
||||
~ CountrySchemaSql(country : Country, dataSource : DataSource)
|
||||
+ insertCountry()
|
||||
+ selectCountry()
|
||||
}
|
||||
diamond h2db
|
||||
}
|
||||
|
||||
App --> "Initialize Country objects" Country
|
||||
App --> "Initialize CountrySchemaSql" CountrySchemaSql
|
||||
CountrySchemaSql --> "implements" CountryDao
|
||||
Country --> "Stored in database" h2db
|
||||
CountrySchemaSql --> "Perform INSERT and SELECT operation after serialize and deserialize Country object" h2db
|
||||
@enduml
|
||||
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||
|
||||
The MIT License
|
||||
Copyright © 2014-2022 Ilkka Seppälä
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.26.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>serialized-entity</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.iluwatar.serializedentity.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2022 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.serializedentity;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import javax.sql.DataSource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.h2.jdbcx.JdbcDataSource;
|
||||
|
||||
|
||||
/**
|
||||
* Serialized Entity Pattern.
|
||||
*
|
||||
* <p> Serialized Entity Pattern allow us to easily persist Java objects to the database. It uses Serializable interface
|
||||
* and DAO pattern. Serialized Entity Pattern will first use Serializable to convert a Java object into a set of bytes,
|
||||
* then it will using DAO pattern to store this set of bytes as BLOB to database.</p>
|
||||
*
|
||||
* <p> In this example, we first initialize two Java objects (Country) "China" and "UnitedArabEmirates", then we
|
||||
* initialize "serializedChina" with "China" object and "serializedUnitedArabEmirates" with "UnitedArabEmirates",
|
||||
* then we use method "serializedChina.insertCountry()" and "serializedUnitedArabEmirates.insertCountry()" to serialize
|
||||
* "China" and "UnitedArabEmirates" and persist them to database.
|
||||
* Last, with "serializedChina.selectCountry()" and "serializedUnitedArabEmirates.selectCountry()" we could read "China"
|
||||
* and "UnitedArabEmirates" from database as sets of bytes, then deserialize them back to Java object (Country). </p>
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
public class App {
|
||||
private static final String DB_URL = "jdbc:h2:~/test";
|
||||
|
||||
private App() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
* @param args command line args.
|
||||
* @throws IOException if any
|
||||
* @throws ClassNotFoundException if any
|
||||
*/
|
||||
public static void main(String[] args) throws IOException, ClassNotFoundException {
|
||||
final var dataSource = createDataSource();
|
||||
|
||||
deleteSchema(dataSource);
|
||||
createSchema(dataSource);
|
||||
|
||||
// Initializing Country Object China
|
||||
final var China = new Country(
|
||||
86,
|
||||
"China",
|
||||
"Asia",
|
||||
"Chinese"
|
||||
);
|
||||
|
||||
// Initializing Country Object UnitedArabEmirates
|
||||
final var UnitedArabEmirates = new Country(
|
||||
971,
|
||||
"United Arab Emirates",
|
||||
"Asia",
|
||||
"Arabic"
|
||||
);
|
||||
|
||||
// Initializing CountrySchemaSql Object with parameter "China" and "dataSource"
|
||||
final var serializedChina = new CountrySchemaSql(China, dataSource);
|
||||
// Initializing CountrySchemaSql Object with parameter "UnitedArabEmirates" and "dataSource"
|
||||
final var serializedUnitedArabEmirates = new CountrySchemaSql(UnitedArabEmirates, dataSource);
|
||||
|
||||
/*
|
||||
By using CountrySchemaSql.insertCountry() method, the private (Country) type variable within Object
|
||||
CountrySchemaSql will be serialized to a set of bytes and persist to database.
|
||||
For more details of CountrySchemaSql.insertCountry() method please refer to CountrySchemaSql.java file
|
||||
*/
|
||||
serializedChina.insertCountry();
|
||||
serializedUnitedArabEmirates.insertCountry();
|
||||
|
||||
/*
|
||||
By using CountrySchemaSql.selectCountry() method, CountrySchemaSql object will read the sets of bytes from database
|
||||
and deserialize it to Country object.
|
||||
For more details of CountrySchemaSql.selectCountry() method please refer to CountrySchemaSql.java file
|
||||
*/
|
||||
serializedChina.selectCountry();
|
||||
serializedUnitedArabEmirates.selectCountry();
|
||||
}
|
||||
|
||||
private static void deleteSchema(DataSource dataSource) {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement()) {
|
||||
statement.execute(CountrySchemaSql.DELETE_SCHEMA_SQL);
|
||||
} catch (SQLException e) {
|
||||
LOGGER.info("Exception thrown " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void createSchema(DataSource dataSource) {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement()) {
|
||||
statement.execute(CountrySchemaSql.CREATE_SCHEMA_SQL);
|
||||
} catch (SQLException e) {
|
||||
LOGGER.info("Exception thrown " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static DataSource createDataSource() {
|
||||
var dataSource = new JdbcDataSource();
|
||||
dataSource.setURL(DB_URL);
|
||||
return dataSource;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2022 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.serializedentity;
|
||||
import java.io.Serializable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* A Country POJO taht represents the data that will serialize and store in database.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
@AllArgsConstructor
|
||||
public class Country implements Serializable {
|
||||
|
||||
private int code;
|
||||
private String name;
|
||||
private String continents;
|
||||
private String language;
|
||||
public static final long serialVersionUID = 7149851;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2022 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* In an application the Data Access Object (DAO) is a part of Data access layer. It is an object
|
||||
* that provides an interface to some type of persistence mechanism. By mapping application calls to
|
||||
* the persistence layer, DAO provides some specific data operations without exposing details of the
|
||||
* database. This isolation supports the Single responsibility principle. It separates what data
|
||||
* accesses the application needs, in terms of domain-specific objects and data types (the public
|
||||
* interface of the DAO), from how these needs can be satisfied with a specific DBMS, database
|
||||
* schema, etc.
|
||||
*
|
||||
* <p>Any change in the way data is stored and retrieved will not change the client code as the
|
||||
* client will be using interface and need not worry about exact source.
|
||||
*
|
||||
* @see InMemoryCustomerDao
|
||||
* @see DbCustomerDao
|
||||
*/
|
||||
package com.iluwatar.serializedentity;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface CountryDao {
|
||||
int insertCountry() throws IOException;
|
||||
int selectCountry() throws IOException, ClassNotFoundException;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2022 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.serializedentity;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.sql.Blob;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Country Schema SQL Class.
|
||||
*/
|
||||
@Slf4j
|
||||
public class CountrySchemaSql implements CountryDao {
|
||||
public static final String CREATE_SCHEMA_SQL = "CREATE TABLE IF NOT EXISTS WORLD (ID INT PRIMARY KEY, COUNTRY BLOB)";
|
||||
|
||||
public static final String DELETE_SCHEMA_SQL = "DROP TABLE WORLD IF EXISTS";
|
||||
|
||||
private Country country;
|
||||
private DataSource dataSource;
|
||||
|
||||
/**
|
||||
* Public constructor.
|
||||
*
|
||||
* @param dataSource datasource
|
||||
* @param country country
|
||||
*/
|
||||
public CountrySchemaSql(Country country, DataSource dataSource) {
|
||||
this.country = new Country(
|
||||
country.getCode(),
|
||||
country.getName(),
|
||||
country.getContinents(),
|
||||
country.getLanguage()
|
||||
);
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will serialize a Country object and store it to database.
|
||||
* @return int type, if successfully insert a serialized object to database then return country code, else return -1.
|
||||
* @throws IOException if any.
|
||||
*/
|
||||
@Override
|
||||
public int insertCountry() throws IOException {
|
||||
var sql = "INSERT INTO WORLD (ID, COUNTRY) VALUES (?, ?)";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oss = new ObjectOutputStream(baos)) {
|
||||
|
||||
oss.writeObject(country);
|
||||
oss.flush();
|
||||
|
||||
preparedStatement.setInt(1, country.getCode());
|
||||
preparedStatement.setBlob(2, new ByteArrayInputStream(baos.toByteArray()));
|
||||
preparedStatement.execute();
|
||||
return country.getCode();
|
||||
} catch (SQLException e) {
|
||||
LOGGER.info("Exception thrown " + e.getMessage());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will select a data item from database and deserialize it.
|
||||
* @return int type, if successfully select and deserialized object from database then return country code,
|
||||
* else return -1.
|
||||
* @throws IOException if any.
|
||||
* @throws ClassNotFoundException if any.
|
||||
*/
|
||||
@Override
|
||||
public int selectCountry() throws IOException, ClassNotFoundException {
|
||||
var sql = "SELECT ID, COUNTRY FROM WORLD WHERE ID = ?";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
|
||||
preparedStatement.setInt(1, country.getCode());
|
||||
|
||||
try (ResultSet rs = preparedStatement.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
Blob countryBlob = rs.getBlob("country");
|
||||
ByteArrayInputStream baos = new ByteArrayInputStream(countryBlob.getBytes(1, (int) countryBlob.length()));
|
||||
ObjectInputStream ois = new ObjectInputStream(baos);
|
||||
country = (Country) ois.readObject();
|
||||
LOGGER.info("Country: " + country);
|
||||
}
|
||||
return rs.getInt("id");
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.info("Exception thrown " + e.getMessage());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.iluwatar.serializedentity;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
|
||||
/**
|
||||
* Tests that Serialized Entity example runs without errors.
|
||||
*/
|
||||
class AppTest {
|
||||
|
||||
/**
|
||||
* Issue: Add at least one assertion to this test case.
|
||||
*
|
||||
* Solution: Inserted assertion to check whether the execution of the main method in {@link App#main(String[])}
|
||||
* throws an exception.
|
||||
*/
|
||||
|
||||
@Test
|
||||
void shouldExecuteSerializedEntityWithoutException() {
|
||||
assertDoesNotThrow(() -> App.main(new String[]{}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2022 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.serializedentity;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class CountryTest {
|
||||
|
||||
@Test
|
||||
void testGetMethod() {
|
||||
Country China = new Country(
|
||||
86,
|
||||
"China",
|
||||
"Asia",
|
||||
"Chinese"
|
||||
);
|
||||
|
||||
assertEquals(86, China.getCode());
|
||||
assertEquals("China", China.getName());
|
||||
assertEquals("Asia", China.getContinents());
|
||||
assertEquals("Chinese", China.getLanguage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetMethod() {
|
||||
Country country = new Country(
|
||||
86,
|
||||
"China",
|
||||
"Asia",
|
||||
"Chinese"
|
||||
);
|
||||
|
||||
country.setCode(971);
|
||||
country.setName("UAE");
|
||||
country.setContinents("West-Asia");
|
||||
country.setLanguage("Arabic");
|
||||
|
||||
assertEquals(971, country.getCode());
|
||||
assertEquals("UAE", country.getName());
|
||||
assertEquals("West-Asia", country.getContinents());
|
||||
assertEquals("Arabic", country.getLanguage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSerializable(){
|
||||
// Serializing Country
|
||||
try {
|
||||
Country country = new Country(
|
||||
86,
|
||||
"China",
|
||||
"Asia",
|
||||
"Chinese");
|
||||
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("output.txt"));
|
||||
objectOutputStream.writeObject(country);
|
||||
objectOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// De-serialize Country
|
||||
try {
|
||||
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("output.txt"));
|
||||
Country country = (Country) objectInputStream.readObject();
|
||||
objectInputStream.close();
|
||||
System.out.println(country);
|
||||
|
||||
Country China = new Country(
|
||||
86,
|
||||
"China",
|
||||
"Asia",
|
||||
"Chinese");
|
||||
|
||||
assertEquals(China, country);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>servant</groupId>
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user