diff --git a/pom.xml b/pom.xml index 7ed97bcae..c0ead428c 100644 --- a/pom.xml +++ b/pom.xml @@ -215,6 +215,7 @@ composite-view metadata-mapping service-to-worker + serialized-entity identity-map diff --git a/serialized-entity/README.md b/serialized-entity/README.md new file mode 100644 index 000000000..a0a3853f9 --- /dev/null +++ b/serialized-entity/README.md @@ -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 +![alt_text](./etc/class_diagram.urm.png "Serialized Entity") + +## 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) diff --git a/serialized-entity/etc/class_diagram.urm.png b/serialized-entity/etc/class_diagram.urm.png new file mode 100644 index 000000000..fb8e7a734 Binary files /dev/null and b/serialized-entity/etc/class_diagram.urm.png differ diff --git a/serialized-entity/etc/serialize-entity.urm.puml b/serialized-entity/etc/serialize-entity.urm.puml new file mode 100644 index 000000000..7bf89dbb9 --- /dev/null +++ b/serialized-entity/etc/serialize-entity.urm.puml @@ -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 \ No newline at end of file diff --git a/serialized-entity/pom.xml b/serialized-entity/pom.xml new file mode 100644 index 000000000..aea122f5a --- /dev/null +++ b/serialized-entity/pom.xml @@ -0,0 +1,71 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + serialized-entity + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.mockito + mockito-core + test + + + com.h2database + h2 + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.serializedentity.App + + + + + + + + + diff --git a/serialized-entity/src/main/java/com/iluwatar/serializedentity/App.java b/serialized-entity/src/main/java/com/iluwatar/serializedentity/App.java new file mode 100644 index 000000000..fb3b383e6 --- /dev/null +++ b/serialized-entity/src/main/java/com/iluwatar/serializedentity/App.java @@ -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. + * + *

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.

+ * + *

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).

+ * + */ +@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; + } +} diff --git a/serialized-entity/src/main/java/com/iluwatar/serializedentity/Country.java b/serialized-entity/src/main/java/com/iluwatar/serializedentity/Country.java new file mode 100644 index 000000000..25ebddf89 --- /dev/null +++ b/serialized-entity/src/main/java/com/iluwatar/serializedentity/Country.java @@ -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; + +} diff --git a/serialized-entity/src/main/java/com/iluwatar/serializedentity/CountryDao.java b/serialized-entity/src/main/java/com/iluwatar/serializedentity/CountryDao.java new file mode 100644 index 000000000..f5d915446 --- /dev/null +++ b/serialized-entity/src/main/java/com/iluwatar/serializedentity/CountryDao.java @@ -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. + * + *

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; +} diff --git a/serialized-entity/src/main/java/com/iluwatar/serializedentity/CountrySchemaSql.java b/serialized-entity/src/main/java/com/iluwatar/serializedentity/CountrySchemaSql.java new file mode 100644 index 000000000..4887ed9dd --- /dev/null +++ b/serialized-entity/src/main/java/com/iluwatar/serializedentity/CountrySchemaSql.java @@ -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; + } + +} diff --git a/serialized-entity/src/test/java/com/iluwatar/serializedentity/AppTest.java b/serialized-entity/src/test/java/com/iluwatar/serializedentity/AppTest.java new file mode 100644 index 000000000..52ac9cd6e --- /dev/null +++ b/serialized-entity/src/test/java/com/iluwatar/serializedentity/AppTest.java @@ -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[]{})); + } +} diff --git a/serialized-entity/src/test/java/com/iluwatar/serializedentity/CountryTest.java b/serialized-entity/src/test/java/com/iluwatar/serializedentity/CountryTest.java new file mode 100644 index 000000000..85d3ed87f --- /dev/null +++ b/serialized-entity/src/test/java/com/iluwatar/serializedentity/CountryTest.java @@ -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(); + } + } +} diff --git a/servant/pom.xml b/servant/pom.xml index 5e0b13915..65650364b 100644 --- a/servant/pom.xml +++ b/servant/pom.xml @@ -27,6 +27,7 @@ --> 4.0.0 + servant com.iluwatar java-design-patterns