Home > Software engineering >  Why Arraylist<String> get stored in H2 database as a long and random string?
Why Arraylist<String> get stored in H2 database as a long and random string?

Time:10-29

I created an entity (Model or Data class) in a Spring-Boot (Kotlin) project which contains a field with the type Arraylist but when I send an array data in JSON format from Postman, the Array gets stored in the database as a long random string.

When I try to retrieve the data from the database I get the actual array, perfectly formated.

My question is why is an ArrayList stored in an H2 database like this???

Evaluation.kt

@Entity
data class Evaluation (
 @Id val id : String,
 val timeStamp : Long,
 val symptoms : ArrayList<String>,
 val travelHistory : Boolean,
 val contactWithCovidPatient : Boolean,
 val evaluatedBy : String,
 var evaluationPercentage : String? = null,
 @ManyToOne var user: User? = null
)

EvaluationController.kt

@RestController
class EvaluationController (val evaluationService: IEvaluationService) {

@PostMapping("evaluate/{userId}")
fun evaluateUser(@PathVariable userId : String, @RequestBody evaluation: Evaluation) : ResponseEntity<Evaluation> =
    ResponseEntity.ok().body(evaluationService.addEvaluation(evaluation, userId))

}

Request Body JSON

{
"id":"e_01",
"timeStamp":"123456789",
"pinCode":"123457",
"travelHistory":true,
"contactWithCovidPatient":true,
"evaluatedBy":"u_01",
"symptoms": ["Fever","Cough"]
}

Response JSON

{
"id": "e_01",
"timeStamp": 123456789,
"symptoms": [
    "Fever",
    "Cough"
],
"travelHistory": true,
"contactWithCovidPatient": true,
"evaluatedBy": "u_01",
"evaluationPercentage": "95",
"user": {
    "id": "u_01",
    "name": "abc01",
    "phoneNumber": "9876543210",
    "pinCode": "123457",
    "covidResult": "Positive"
}
}

H2 Database Table

enter image description here

CodePudding user response:

This is a hex string representing the serialized ArrayList object. See Serializable Objects for details about object serialization in Java.

Running the following code yields the same result:

List<String> symptoms = new ArrayList<>(Arrays.asList("Fever", "Cough"));
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(symptoms);
byte[] serializedObject = byteArrayOutputStream.toByteArray();
String hex = Hex.encodeHexString(serializedObject); // Apache Commons Codec
System.out.println(hex);
aced0005737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a657870000000027704000000027400054665766572740005436f75676878

CodePudding user response:

The raw string seen in the DB is a serialized object.

One way of implementing this is to first join your string ArrayList into one delimited string, but I highly recommend against this. In general it's bad practice to put a list into a single field of a table. What you should be doing is creating a separate table for Symptoms with a one-to-many relationship with Evaluation.

You need to be aware of denormalization while designing your objects when using JPA. In your case, consider the following questions :

  1. What happens if you want to query evaluations with specific symptoms?
  2. What happens if you want to query a list of all the symptoms?
  3. What happens if you want to expand symptoms with some other detail, such as date when a symptom appeared?

If you are ever in a situation of trying to add a collection of something into a database field 99.9999% of the time you're doing it wrong. Symptoms should be their own entity, and you have a one-to-many or many-to-many relationship between evaluation and symptom, depending on what you require.

Edit :

To clarify my answer further, when designing object classes think about whether a field is a value object or an entity. A value object is something that cannot be broken down further and can be represented by a primitive, such as Date, String, Int, etc. Some examples could be an object ID, name, phone number, etc.

An entity is an object that can be expanded further, like the Evaluations object you created. Within Evaluations you have a list of Symptoms, and you're treating Symptoms as a value object. Is it a value object though? I can immediately think of some additional fields you could put into a Symptom object, and by denormalizing symptoms the way you did, you are also inputting tons of duplicate data into the database.

An evaluation object containing ["Fever", "Cough"] in your implementation will be input into the database as one field. But another evaluation object containing the same symptoms will be input into the database for that evaluation because you don't have a foreign key dependency or a separate table representing symptoms. On top of not being able to query symptoms in relation with evaluations, or not being able to query symptoms on their own.

  • Related