Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
78f72ec
#1596:Adding module for SLOB Pattern
KishalayP Oct 22, 2023
4db8fad
#1596:Adding Interface for Serializers
KishalayP Oct 22, 2023
fb9dd96
#1596:Adding Objects
KishalayP Oct 22, 2023
04379bb
#1596:Adding BLOB Based Serializer
KishalayP Oct 22, 2023
e1d4a9b
#1596:Implemented Clob Based Serializer
KishalayP Oct 22, 2023
e8eefa4
#1596:Implemented Service for DB operations
KishalayP Oct 22, 2023
b52130d
#1596:Implemented basic flow using Clob Serializer
KishalayP Oct 22, 2023
d46e771
#1596:Added H2 DB Dependency
KishalayP Oct 22, 2023
338d0ea
#1596:Added Java Doc Stubs
KishalayP Oct 24, 2023
26789e5
Updating Objects
SHRADDHAP18 Dec 21, 2023
eedf641
#1596:Completed Clob Serializer along with Tests
KishalayP Jan 20, 2024
d06caab
Merge remote-tracking branch 'origin/feature/slob_design_pattern' int…
KishalayP Jan 20, 2024
dc5658a
#1596:Completed Slob Serializer along with Tests
KishalayP Jan 20, 2024
133ed50
#1596:Completed Blob Serializer along with Tests
KishalayP Jan 20, 2024
153ce10
Merge remote-tracking branch 'origin/feature/slob_design_pattern' int…
KishalayP Jan 21, 2024
9fd27e1
#1596:Updated DatabaseService to handle Blob and Clob Data
KishalayP Jan 21, 2024
bb3059c
#1596:Added UML and updated README.md
KishalayP Jan 21, 2024
9717c47
Merge remote-tracking branch 'origin/master' into feature/slob_design…
KishalayP Jan 21, 2024
b19d34c
#1596:Updated data types for DB
KishalayP Jan 21, 2024
5ac8d14
#1596:Code Style Formatting Cnames
KishalayP Jan 21, 2024
3e9cb86
Adding Java Docs
SHRADDHAP18 Jan 21, 2024
efe71f1
#1596:Reformatted as per Code Style
KishalayP Jan 21, 2024
1831f1f
#1596:Updating Java Doc
KishalayP Jan 21, 2024
859a423
#1596:Updating Main function to handle both Serializers
KishalayP Jan 21, 2024
565c718
#1596:Updated Java Docs
KishalayP Jan 21, 2024
494aa8c
#1596:Updated Java Docs
KishalayP Jan 21, 2024
2862cb6
#1596:Updated Java Docs and formatting
KishalayP Jan 21, 2024
09c70e9
#1596:Updated Java Docs and formatting
KishalayP Jan 21, 2024
94e689b
#1596:Adding Java Docs
SHRADDHAP18 Jan 21, 2024
fd0e1a4
#1596:Reformatted as per Code Style
KishalayP Jan 21, 2024
e7df198
#1596:Updating Java Doc
KishalayP Jan 21, 2024
4e8b995
#1596:Updating Main function to handle both Serializers
KishalayP Jan 21, 2024
d02b34e
#1596:Updated Java Docs
KishalayP Jan 21, 2024
fddafd0
#1596:Updated Java Docs
KishalayP Jan 21, 2024
d0fe0c7
#1596:Updated Java Docs and formatting
KishalayP Jan 21, 2024
7c92e4e
#1596:Updated Java Docs and formatting
KishalayP Jan 21, 2024
336654a
#1596:Updated Java Docs and formatting
KishalayP Jan 21, 2024
38e6e6b
#1596:Updated Java Docs and formatting
KishalayP Jan 21, 2024
dc56f7c
#1596:Updated README.md
KishalayP Jan 21, 2024
fc35305
Merge remote-tracking branch 'origin/feature/slob_design_pattern' int…
KishalayP Jan 21, 2024
7e8acad
#1596:Updated Java Docs and README.md
KishalayP Jan 21, 2024
e988f6a
#1596:Updated Extension
KishalayP Jan 21, 2024
88ab371
#1596:Updated README.md
KishalayP Jan 21, 2024
35c339f
Merge branch 'master' into feature/slob_design_pattern
KishalayP Jan 27, 2024
29aca42
Merge branch 'master' into feature/slob_design_pattern
KishalayP Feb 12, 2024
94e4847
Merge branch 'master' into feature/slob_design_pattern
KishalayP Mar 10, 2024
db87f73
#1596:Updated Documentation as per review comments
KishalayP Mar 10, 2024
5ef36a3
#1596:Updated Documentation as per review comments
KishalayP Mar 10, 2024
c61639c
#1596: Updated README.md
KishalayP Mar 10, 2024
7e7869d
#1596:Updated Documentation as per review comments
KishalayP Mar 18, 2024
c56697e
Merge remote-tracking branch 'origin/feature/slob_design_pattern' int…
KishalayP Mar 18, 2024
f5d7aa0
Merge branch 'master' into feature/slob_design_pattern
KishalayP Mar 18, 2024
40fa0c0
Merge branch 'master' into feature/slob_design_pattern
KishalayP Mar 24, 2024
eaf438d
#1596: Added SLOB Module
KishalayP Mar 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@
<module>single-table-inheritance</module>
<module>dynamic-proxy</module>
<module>gateway</module>
<module>slob</module>
</modules>
<repositories>
<repository>
Expand Down
354 changes: 354 additions & 0 deletions slob/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,354 @@
---
title: Serialized LOB
category: Structural
language: en
tag:
- Data access
---

## Intent

* Object models often contain complicated graphs of small objects. Much of the information in these
structures isn’t in the objects but in the links between them.
* Objects don’t have to be persisted as table rows related to each other.
* Another form of persistence is serialization, where a whole graph of objects is written out as a
single large object (LOB) in a table.

## Explanation

**In plain words**

> The Forest here represents the object graph.
> A forest contains animals and plants. As is in real life the forest object contains plants and
> animals where some animals eat other animals and some eat only plants.
> * These relationships are maintained in the Forest Object.
> * There are 2 types of Serializers available ClobSerializer and BlobSerializer.
> * ClobSerializer uses character or textual based serialization, here the Object graph is converted
> * to XML and then stored as text in DB.
> * BlobSerializer uses binary data for serialization, here the Object graph is converted to Byte
> * Array and then stored as a blob in DB.

**Programmatic Example**

* Here is the `Animal` class. It represents the Animal object in the Forest. It contains the name of
the animals in the forest and details of what they eat from the forest plants/animals or both.

```java
/**
* Creates an object Forest which contains animals and plants as its constituents. Animals may eat
* plants or other animals in the forest.
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Forest implements Serializable {

private String name;
private final Set<Animal> animals = new HashSet<>();
private final Set<Plant> plants = new HashSet<>();

/**
* Provides the representation of Forest in XML form.
*
* @return XML Element
*/
public Element toXmlElement() throws ParserConfigurationException {
Document xmlDoc = getXmlDoc();

Element forestXml = xmlDoc.createElement("Forest");
forestXml.setAttribute("name", name);

Element animalsXml = xmlDoc.createElement("Animals");
for (Animal animal : animals) {
Element animalXml = animal.toXmlElement(xmlDoc);
animalsXml.appendChild(animalXml);
}
forestXml.appendChild(animalsXml);

Element plantsXml = xmlDoc.createElement("Plants");
for (Plant plant : plants) {
Element plantXml = plant.toXmlElement(xmlDoc);
plantsXml.appendChild(plantXml);
}
forestXml.appendChild(plantsXml);
return forestXml;
}

/**
* Returns XMLDoc to use for XML creation.
*
* @return XML DOC Object
* @throws ParserConfigurationException {@inheritDoc}
*/
private Document getXmlDoc() throws ParserConfigurationException {
return DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder().newDocument();
}

/**
* Parses the Forest Object from the input XML Document.
*
* @param document the XML document from which the Forest is to be parsed
*/
public void createObjectFromXml(Document document) {
name = document.getDocumentElement().getAttribute("name");
NodeList nodeList = document.getElementsByTagName("*");
iterateXmlForAnimalAndPlants(nodeList, animals, plants);
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder("\n");
sb.append("Forest Name = ").append(name).append("\n");
sb.append("Animals found in the ").append(name).append(" Forest: \n");
for (Animal animal : animals) {
sb.append("\n--------------------------\n");
sb.append(animal.toString());
sb.append("\n--------------------------\n");
}
sb.append("\n");
sb.append("Plants in the ").append(name).append(" Forest: \n");
for (Plant plant : plants) {
sb.append("\n--------------------------\n");
sb.append(plant.toString());
sb.append("\n--------------------------\n");
}
return sb.toString();
}
}
```

* Here is the `LobSerializer` abstract class. It provides the specification to serialize and
deserialize the input object and persist and load that object into a DB.

```java
/**
* A LobSerializer can be used to create an instance of a serializer which can serialize and
* deserialize an object and persist and load that object into a DB. from their Binary
* Representation.
*/
public abstract class LobSerializer implements Serializable, Closeable {

private final transient DatabaseService databaseService;

/**
* Constructor initializes {@link LobSerializer#databaseService}.
*
* @param dataTypeDb Input provides type of Data to be stored by the Data Base Service
* @throws SQLException If any issue occurs during instantiation of DB Service or during startup.
*/
protected LobSerializer(String dataTypeDb) throws SQLException {
databaseService = new DatabaseService(dataTypeDb);
databaseService.startupService();
}

/**
* Provides the specification to Serialize the input object.
*
* @param toSerialize Input Object to serialize
* @return Serialized Object
* @throws ParserConfigurationException if any issue occurs during parsing of input object
* @throws TransformerException if any issue occurs during Transformation
* @throws IOException if any issues occur during reading object
*/
public abstract Object serialize(Forest toSerialize)
throws ParserConfigurationException, TransformerException, IOException;

/**
* Saves the object to DB with the provided ID.
*
* @param id key to be sent to DB service
* @param name Object name to store in DB
* @param object Object to store in DB
* @return ID with which the object is stored in DB
* @throws SQLException if any issue occurs while saving to DB
*/
public int persistToDb(int id, String name, Object object) throws SQLException {
databaseService.insert(id, name, object);
return id;
}

/**
* Loads the object from db using the ID and column name.
*
* @param id to query the DB
* @param columnName column from which object is to be extracted
* @return Object from DB
* @throws SQLException if any issue occurs while loading from DB
*/
public Object loadFromDb(int id, String columnName) throws SQLException {
return databaseService.select(id, columnName);
}

/**
* Provides the specification to Deserialize the input object.
*
* @param toDeserialize object to deserialize
* @return Deserialized Object
* @throws ParserConfigurationException If issue occurs during parsing of input object
* @throws IOException if any issues occur during reading object
* @throws SAXException if any issues occur during reading object for XML parsing
*/
public abstract Forest deSerialize(Object toDeserialize)
throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException;

@Override
public void close() {
try {
databaseService.shutDownService();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
```

* Here is the `ClobSerializer` class. It extends the `LobSerializer` abstract class and provides the
implementation to serialize and deserialize the input object and persist and load that object into
a DB using ClobSerializer.
* Objects are serialized using character or textual based serialization
using XML to represent the object graph.

```java

/**
* Creates a Serializer that uses Character based serialization and deserialization of objects graph
* to and from XML Representation.
*/
public class ClobSerializer extends LobSerializer {

public static final String TYPE_OF_DATA_FOR_DB = "TEXT";

public ClobSerializer() {
super(TYPE_OF_DATA_FOR_DB);
}

/**
* Converts the input node to its XML String Representation.
*
* @param node XML Node that is to be converted to string
* @return String representation of XML parsed from the Node
* @throws TransformerException If any issues occur in Transformation from Node to XML
*/
private static String elementToXmlString(Element node) throws TransformerException {
StringWriter sw = new StringWriter();
Transformer t = TransformerFactory.newDefaultInstance().newTransformer();
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.transform(new DOMSource(node), new StreamResult(sw));
return sw.toString();
}

/**
* Serializes the input object graph to its XML Representation using DOM Elements.
*
* @param forest Object which is to be serialized
* @return Serialized object
* @throws ParserConfigurationException If any issues occur in parsing input object
* @throws TransformerException If any issues occur in Transformation from Node to XML
*/
@Override
public Object serialize(Forest forest) throws ParserConfigurationException, TransformerException {
Element xmlElement = forest.toXmlElement();
return elementToXmlString(xmlElement);
}

/**
* Deserializes the input XML string using DOM Parser and return its Object Graph Representation.
*
* @param toDeserialize Input Object to De-serialize
* @return Deserialized Object
* @throws ParserConfigurationException If any issues occur in parsing input object
* @throws IOException if any issues occur during reading object
* @throws SAXException If any issues occur in Transformation from Node to XML
*/
@Override
public Forest deSerialize(Object toDeserialize)
throws ParserConfigurationException, IOException, SAXException {
DocumentBuilder documentBuilder = DocumentBuilderFactory.newDefaultInstance()
.newDocumentBuilder();
var stream = new ByteArrayInputStream(toDeserialize.toString().getBytes());
Document parsed = documentBuilder.parse(stream);
Forest forest = new Forest();
forest.createObjectFromXml(parsed);
return forest;
}
}
```

* Here is the `SlobSerializer` class. It extends the `LobSerializer` abstract class and provides the
implementation to serialize and deserialize the input object and persist and load that object into
a DB using ClobSerializer.
* Objects are serialized using binary data based serialization objects a persisted as a BINARY/BLOB
in DB.

```java
/**
* Creates a Serializer that uses Binary serialization and deserialization of objects graph to and
* from their Binary Representation.
*/
public class BlobSerializer extends LobSerializer {

public static final String TYPE_OF_DATA_FOR_DB = "BINARY";

public BlobSerializer() throws SQLException {
super(TYPE_OF_DATA_FOR_DB);
}

/**
* Serializes the input object graph to its Binary Representation using Object Stream.
*
* @param toSerialize Object which is to be serialized
* @return Serialized object
* @throws IOException {@inheritDoc}
*/
@Override
public Object serialize(Forest toSerialize) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(toSerialize);
oos.close();
return new ByteArrayInputStream(baos.toByteArray());
}

/**
* Deserializes the input Byte Array Stream using Object Stream and return its Object Graph
* Representation.
*
* @param toDeserialize Input Object to De-serialize
* @return Deserialized Object
* @throws ClassNotFoundException {@inheritDoc}
* @throws IOException {@inheritDoc}
*/
@Override
public Forest deSerialize(Object toDeserialize) throws IOException, ClassNotFoundException {
InputStream bis = (InputStream) toDeserialize;
Forest forest;
try (ObjectInput in = new ObjectInputStream(bis)) {
forest = (Forest) in.readObject();
}
return forest;
}
}
```

## Class diagram

![alt text](./etc/slob.urm.png "Serialized LOB")

## Applicability

* This pattern works best when you can chop out a piece of the object model and use it to represent
the LOB.
* Think of a LOB as a way to take a bunch of objects that aren’t likely to be queried from any SQL
route outside the application.
* This graph can then be hooked into the SQL schema. Serialized LOB works poorly when you have
objects outside the LOB reference objects buried in it.
* Serialized LOB isn’t considered as often as it might be. XML makes it much more attractive since
it yields an easy-to-implement textual approach.
* Its main disadvantage is that you can’t query the structure using SQL.
* SQL extensions appear to get at XML data within a field, but that’s still not the same (or
portable).

## Credits

* [Serialized LOB](https://martinfowler.com/eaaCatalog/serializedLOB.html) by Martin Fowler
Binary file added slob/etc/slob.urm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading