What's wrong with my annotations for the relevant associations (or if that's not the problem, then what is)?

Hello everyone. :slight_smile:

I have a larger code base, which I’ve translated to the following mini example to hopefully be able to get some help on the concept(s) that I’m not understanding correctly.

In the mini example problem I made, I’m trying to have a Basket entity containing multiple Kiwis (a List of Kiwi objects) and a single Watermelon object. This would mean having a table for Kiwi with a foreign key UUID to Basket and also a table for Watermelon with a foreign key UUID to Basket. I’m using SQLite and the UUIDs are Strings, not the java.util.UUID (or any other) class, for what it’s worth.

Unless I’ve forgotten something, the following is all the relevant information.:

./src
./src/main
./src/main/java
./src/main/java/com
./src/main/java/com/mycompany
./src/main/java/com/mycompany/myapp
./src/main/java/com/mycompany/myapp/Basket.java
./src/main/java/com/mycompany/myapp/Driver.java
./src/main/java/com/mycompany/myapp/HibernateUtil.java
./src/main/java/com/mycompany/myapp/Kiwi.java
./src/main/java/com/mycompany/myapp/KiwiConverter.java
./src/main/java/com/mycompany/myapp/Watermelon.java
./src/main/java/com/mycompany/myapp/WatermelonConverter.java
./src/main/java/com/mycompany/myapp/BasketDao.java
./src/main/java/com/mycompany/myapp/StringListConverter.java
./src/main/resources
./src/main/resources/hibernate.cfg.xml
./src/test
./src/test/java
./src/test/java/com
./src/test/java/com/mycompany
./src/test/java/com/mycompany/myapp

BasketDao.java:

package com.mycompany.myapp;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.Transaction;

public class BasketDao {
    private static BasketDao transactionSetDao = null;
    
    private BasketDao() {}
    
    public static BasketDao getInstance() {
        if(transactionSetDao == null) {
            transactionSetDao = new BasketDao();
        }
        
        return transactionSetDao;
    }
    
    public<T> void save(T data) {
        Transaction tx = null;
        
        try( Session session = HibernateUtil.getSessionFactory().openSession() ) {
            tx = session.beginTransaction();
            
            session.merge(data);
            
            tx.commit();
        }
    }
    
    public <T> List<T> loadAllData(Class<T> type) {
        Transaction tx = null;
        
        try( Session session = HibernateUtil.getSessionFactory().openSession() ) {
            tx = session.beginTransaction();
            
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<T> criteria = builder.createQuery(type);
            criteria.from(type);

            List<T> data = session.createQuery(criteria).getResultList();

            tx.commit();
            
            return data;
        }
    }
}

Basket.java:

package com.mycompany.myapp;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Entity
public class Basket implements Serializable {
        
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    @Column(name="basketUuid")
    private String basketUuid;
    
    private String brandName;
    
    @Convert(converter = WatermelonConverter.class)
    @OneToOne(mappedBy="basket", cascade=CascadeType.ALL)
    private Watermelon watermelon;

    @Convert(converter = KiwiConverter.class)
    @Convert(converter = StringListConverter.class)
    @OneToMany(mappedBy="basket", cascade=CascadeType.ALL)
    @ElementCollection
    private List<Kiwi> kiwis;
    
    public Basket() {
        this(UUID.randomUUID().toString(), "Generic", new Watermelon(), new ArrayList<Kiwi>());
    }

    public Basket(String basketUuid, String brandName, Watermelon watermelon, List<Kiwi> kiwis) {
        this.basketUuid = basketUuid;
        this.brandName = brandName;
        this.watermelon = watermelon;
        this.kiwis = kiwis;
    }

    public String getBasketUuid() {
        return basketUuid;
    }

    public void setBasketUuid(String basketUuid) {
        this.basketUuid = basketUuid;
    }

    public String getBrandName() {
        return brandName;
    }

    public void setBrandName(String brandName) {
        this.brandName = brandName;
    }

    public Watermelon getWatermelon() {
        return watermelon;
    }

    public void setWatermelon(Watermelon watermelon) {
        this.watermelon = watermelon;
    }

    public List<Kiwi> getKiwis() {
        return kiwis;
    }

    public void setKiwis(List<Kiwi> kiwis) {
        this.kiwis = kiwis;
    }
}

Driver.java:

package com.mycompany.myapp;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

public class Driver {

    public static void main(String[] args) throws Exception {
        
        try/*( Session session = HibernateUtil.getSessionFactory().openSession() )*/ {
//            tx = session.beginTransaction();

            Watermelon watermelon = new Watermelon(10.0, LocalDateTime.now());
            Kiwi kiwi1 = new Kiwi();
            kiwi1.setPurchasePrice(1.0);
            kiwi1.setPurchaseTimestamp(LocalDateTime.now());
            Kiwi kiwi2 = new Kiwi();
            kiwi2.setPurchasePrice(1.0);
            kiwi2.setPurchaseTimestamp(LocalDateTime.now().plusMinutes(1));
            List<Kiwi> kiwis = new ArrayList<>(2);
            kiwis.add(kiwi1);
            kiwis.add(kiwi2);
            
            Basket basket = new Basket();
            basket.setBrandName("Tote");
            basket.setWatermelon(watermelon);
            basket.setKiwis(kiwis);
//            BasketDao.getInstance().save(watermelon);
//            BasketDao.getInstance().save(kiwis);
            BasketDao.getInstance().save(basket);

//            tx.commit();
        } catch (Exception e) {
//            tx.rollback();
            e.printStackTrace();
        }
    }
}

HibernateUtil.java:

package com.mycompany.myapp;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;

public class HibernateUtil {
    private static SessionFactory sessionFactory;

    private static SessionFactory buildSessionFactory() {
        StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder().
                configure("hibernate.cfg.xml").build();

        Metadata metadata = new MetadataSources(standardRegistry).getMetadataBuilder().
                build();

        SessionFactoryBuilder sessionFactoryBuilder = metadata.getSessionFactoryBuilder();

        SessionFactory sessionFactory = sessionFactoryBuilder.build();

        return sessionFactory;
    }

    public static SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            sessionFactory = buildSessionFactory();
        }
        return sessionFactory;
    }
}

KiwiConverter.java:

package com.mycompany.myapp;

import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.time.LocalDateTime;

@Converter
public class KiwiConverter implements AttributeConverter<Kiwi,String> {
    
    private static final String SEPARATOR = ";";

    @Override
    public String convertToDatabaseColumn(Kiwi kiwi) {
        StringBuilder sb = new StringBuilder();
        
        sb.append( kiwi.getKiwiUuid() );
        sb.append( SEPARATOR );
        sb.append( kiwi.getPurchasePrice());
        sb.append( SEPARATOR );
        sb.append( kiwi.getPurchaseTimestamp());
        
        return sb.toString();
    }

    @Override
    public Kiwi convertToEntityAttribute(String dbKiwi) {
        String[] parts = dbKiwi.split(SEPARATOR);
        
        Kiwi kiwi = new Kiwi();
        
        int i = 0;
        kiwi.setKiwiUuid( parts[i++] );
        kiwi.setPurchasePrice( Double.parseDouble(parts[i++]) );
        kiwi.setPurchaseTimestamp( LocalDateTime.parse(parts[i++]) );
        /*Basket basket = new Basket(basketUuid, brandName, watermelon, kiwis);
        kiwi.setBasket(basket);*/
        
        return kiwi;
    }
    
}

Kiwi.java:

package com.mycompany.myapp;

import jakarta.persistence.Entity;
import static jakarta.persistence.FetchType.LAZY;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import java.time.LocalDateTime;
import java.util.UUID;

@Entity
public class Kiwi {
    
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String kiwiUuid;
    
    private double purchasePrice;
    
    private LocalDateTime purchaseTimestamp;
    
    @ManyToOne(fetch=LAZY)
//    @ManyToOne
    @JoinColumn(name="basketUuid")
    private Basket basket;

    public Kiwi() {
//        this(UUID.randomUUID().toString(), 1.0, LocalDateTime.now(), new Basket());
    }

    public Kiwi(String kiwiUuid, double purchasePrice, LocalDateTime purchaseTimestamp, Basket basket) {
        this.kiwiUuid = kiwiUuid;
        this.purchasePrice = purchasePrice;
        this.purchaseTimestamp = purchaseTimestamp;
        this.basket = basket;
    }

    public String getKiwiUuid() {
        return kiwiUuid;
    }

    public void setKiwiUuid(String kiwiUuid) {
        this.kiwiUuid = kiwiUuid;
    }

    public double getPurchasePrice() {
        return purchasePrice;
    }

    public void setPurchasePrice(double purchasePrice) {
        this.purchasePrice = purchasePrice;
    }

    public LocalDateTime getPurchaseTimestamp() {
        return purchaseTimestamp;
    }

    public void setPurchaseTimestamp(LocalDateTime purchaseTimestamp) {
        this.purchaseTimestamp = purchaseTimestamp;
    }

    public Basket getBasket() {
        return basket;
    }

    public void setBasket(Basket basket) {
        this.basket = basket;
    }
}

StringListConverter.java:

package com.mycompany.myapp;

import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.util.Arrays;
import static java.util.Collections.emptyList;
import java.util.List;

@Converter
public class StringListConverter implements AttributeConverter<List<String>, String> {
    private static final String DELIMITER = ";";

    @Override
    public String convertToDatabaseColumn(List<String> stringList) {
        return stringList != null ? String.join(DELIMITER, stringList) : "";
    }

    @Override
    public List<String> convertToEntityAttribute(String string) {
        return string != null ? Arrays.asList(string.split(DELIMITER)) : emptyList();
    }
}

WatermelonConverter.java:

package com.mycompany.myapp;

import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.time.LocalDateTime;

@Converter
public class WatermelonConverter implements AttributeConverter<Watermelon,String> {
    
    private static final String SEPARATOR = ";";

    @Override
    public String convertToDatabaseColumn(Watermelon watermelon) {
        StringBuilder sb = new StringBuilder();
        
        sb.append( watermelon.getWatermelonUuid() );
        sb.append( SEPARATOR );
        sb.append( watermelon.getPurchasePrice());
        sb.append( SEPARATOR );
        sb.append( watermelon.getPurchaseTimestamp());
        
        return sb.toString();
    }

    @Override
    public Watermelon convertToEntityAttribute(String dbWatermelon) {
        String[] parts = dbWatermelon.split(SEPARATOR);
        
        Watermelon watermelon = new Watermelon();
        
        int i = 0;
        watermelon.setWatermelonUuid( parts[i++] );
        watermelon.setPurchasePrice(Double.parseDouble(parts[i++]) );
        watermelon.setPurchaseTimestamp(LocalDateTime.parse(parts[i++]));
        
        return watermelon;
    }
}

Watermelon.java:

package com.mycompany.myapp;

import jakarta.persistence.Basic;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import java.time.LocalDateTime;

@Entity
public class Watermelon {
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String watermelonUuid;
    
    private double purchasePrice;
    
    @Basic
    private LocalDateTime purchaseTimestamp;
    
    @OneToOne
    @JoinColumn(name="basketUuid")
    private Basket basket;
    
    public Watermelon() {
//        this(0.0, LocalDateTime.now());
    }
    
    public Watermelon(double purchasePrice, LocalDateTime purchaseTimestamp) {
        this.purchasePrice = purchasePrice;
        this.purchaseTimestamp = purchaseTimestamp;
    }

    public String getWatermelonUuid() {
        return watermelonUuid;
    }

    public void setWatermelonUuid(String uuid) {
        this.watermelonUuid = uuid;
    }

    public double getPurchasePrice() {
        return purchasePrice;
    }

    public void setPurchasePrice(double purchasePrice) {
        this.purchasePrice = purchasePrice;
    }

    public LocalDateTime getPurchaseTimestamp() {
        return purchaseTimestamp;
    }

    public void setPurchaseTimestamp(LocalDateTime purchaseTimestamp) {
        this.purchaseTimestamp = purchaseTimestamp;
    }
}

hibernate.cfg.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- Database connection settings -->
        <property name="connection.driver_class">org.sqlite.JDBC</property>
        <property name="connection.url">jdbc:sqlite:mydatabase.sqlite</property>
        
        <!-- SQL dialect for SQLite -->
        <!-- <property name="dialect">org.hibernate.dialect.SQLiteDialect</property> -->
        <property name="hibernate.dialect">org.hibernate.community.dialect.SQLiteDialect</property>
        <property name="hbm2ddl.auto">update</property>
        <property name="show_sql">true</property>
        <mapping class="com.mycompany.myapp.Basket"/>
        <mapping class="com.mycompany.myapp.Watermelon"/>
        <mapping class="com.mycompany.myapp.Kiwi"/>
    </session-factory>
</hibernate-configuration>

Relevant part of output of code (in NetBeans):

--- exec:3.1.0:exec (default-cli) @ MiniProjectForForumHelp ---
Oct. 02, 2023 1:02:54 A.M. org.hibernate.Version logVersion
INFO: HHH000412: Hibernate ORM core version 6.3.0.Final
Oct. 02, 2023 1:02:55 A.M. org.hibernate.cache.internal.RegionFactoryInitiator initiateService
INFO: HHH000026: Second-level cache disabled
Oct. 02, 2023 1:02:55 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using built-in connection pool (not intended for production use)
Oct. 02, 2023 1:02:55 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: Loaded JDBC driver class: org.sqlite.JDBC
Oct. 02, 2023 1:02:55 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001012: Connecting with JDBC URL [jdbc:sqlite:mydatabase.sqlite]
Oct. 02, 2023 1:02:55 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {}
Oct. 02, 2023 1:02:55 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
Oct. 02, 2023 1:02:55 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
INFO: HHH10001115: Connection pool size: 20 (min=1)
Oct. 02, 2023 1:02:56 A.M. org.hibernate.validator.internal.util.Version <clinit>
INFO: HV000001: Hibernate Validator 8.0.1.Final
Oct. 02, 2023 1:02:58 A.M. org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
Oct. 02, 2023 1:02:58 A.M. org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@2bb62414] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: create table Basket (basketUuid varchar(255) not null, brandName varchar(255), primary key (basketUuid))
Hibernate: create table Kiwi (kiwiUuid varchar(255) not null, purchasePrice float not null, purchaseTimestamp timestamp, basketUuid varchar(255), primary key (kiwiUuid))
Hibernate: create table Watermelon (watermelonUuid varchar(255) not null, purchasePrice float not null, purchaseTimestamp timestamp, basketUuid varchar(255) unique, primary key (watermelonUuid))
Hibernate: alter table Watermelon drop constraint UK_ad6t7ccky3nwuethuv9mreq90
Hibernate: alter table Watermelon add constraint UK_ad6t7ccky3nwuethuv9mreq90 unique (basketUuid)
Hibernate: select b1_0.basketUuid,b1_0.brandName,w1_0.watermelonUuid,w1_0.purchasePrice,w1_0.purchaseTimestamp,k1_0.basketUuid,k1_0.kiwiUuid,k1_0.purchasePrice,k1_0.purchaseTimestamp from Basket b1_0 left join Watermelon w1_0 on b1_0.basketUuid=w1_0.basketUuid left join Kiwi k1_0 on b1_0.basketUuid=k1_0.basketUuid where b1_0.basketUuid=?
Hibernate: insert into Basket (brandName,basketUuid) values (?,?)
Hibernate: insert into Kiwi (basketUuid,purchasePrice,purchaseTimestamp,kiwiUuid) values (?,?,?,?)
Hibernate: insert into Kiwi (basketUuid,purchasePrice,purchaseTimestamp,kiwiUuid) values (?,?,?,?)
Hibernate: insert into Watermelon (basketUuid,purchasePrice,purchaseTimestamp,watermelonUuid) values (?,?,?,?)

Here are the tables (which I exported from sqlitebrowser as csv files which I am printing out here).:

user@debian:~/some_directory$ ls -a
.  ..  Basket.csv  Kiwi.csv  Watermelon.csv
user@debian:~/some_directory$ cat ./Basket.csv 
basketUuid,brandName
597eea79-2ae6-4c75-8010-831cd1b718cf,Tote
user@debian:~/some_directory$ cat ./Kiwi.csv 
kiwiUuid,purchasePrice,purchaseTimestamp,basketUuid
502fe99a-374a-4b6e-992c-703ea322ac54,1.0,1696222973854,
a794ccc1-021e-4b2a-89b8-b50053281ede,1.0,1696223033854,
user@debian:~/some_directory$ cat ./Watermelon.csv 
watermelonUuid,purchasePrice,purchaseTimestamp,basketUuid
4f8768a9-4ca0-45e5-be0f-63f9bf9c0fe9,10.0,1696222973845,
user@debian:~/some_directory$

Notice that the foreign keys in Kiwi and Watermelon (which is the primary key of Basket) are null (the nothingness that follows the last comma).

So, could someone please help me figure out what I’m not grasping properly?

Any input would be greatly appreciated!

Looks ok to me. Maybe try reproducing this with our test case template, then we can take a look. Note that SQLite is not a supported database, so if you can’t reproduce it with e.g. H2, then we can’t help you.

Edit:
Oops! The issue still seems to be the same, but I had accidentally not used the H2 database in the persistence.xml file and the test code. I was also using deprecated syntax (using javax instead of jakarta). Additionally, I improved the test code. See my next post for the corrections regarding the persistence.xml file, the test code (JPAUnitTestCase.java) and the output generated.

Original message:
Thanks for the response. :slight_smile:

I tried doing the analogous stuff with the test file you linked to and it still had the same issue in SQLite. I’m also doing this in IntelliJ IDEA Community Edition as well now, just in case.

Using H2, I made the test file code print out the Basket, Watermelon and each Kiwi with System.out.println lines (and I autogenerated toString method implementations for that to be useful), and as far as I can tell, there’s the same issue as there is with the use of SQLite.

Maybe the problem lies with the Kiwi and Watermelon converters not dealing with the Basket class? I was a little confused about that. (Sorry, I’m very new to all this.)

Here is a terminal interaction that shows the structure of everything in the project followed by the actual, new code further below - the old, unchanged code can be seen in my previous post).:

user@debian:~/IdeaProjects/MiniProjectForForumHelp$ ls -a
.  ..  .gitignore  .idea  mydatabase.sqlite  pom.xml  src  target
user@debian:~/IdeaProjects/MiniProjectForForumHelp$ cd src/
user@debian:~/IdeaProjects/MiniProjectForForumHelp/src$ ls
main  test
user@debian:~/IdeaProjects/MiniProjectForForumHelp/src$ find . -name "*"
.
./main
./main/java
./main/java/com
./main/java/com/mycompany
./main/java/com/mycompany/myapp
./main/java/com/mycompany/myapp/Driver.java
./main/java/com/mycompany/myapp/Basket.java
./main/java/com/mycompany/myapp/HibernateUtil.java
./main/java/com/mycompany/myapp/KiwiConverter.java
./main/java/com/mycompany/myapp/Kiwi.java
./main/java/com/mycompany/myapp/StringListConverter.java
./main/java/com/mycompany/myapp/WatermelonConverter.java
./main/java/com/mycompany/myapp/Watermelon.java
./main/java/com/mycompany/myapp/BasketDao.java
./main/resources
./main/resources/hibernate.cfg.xml
./main/resources/META-INF
./main/resources/META-INF/persistence.xml
./test
./test/java
./test/java/org
./test/java/org/hibernate
./test/java/org/hibernate/bugs
./test/java/org/hibernate/bugs/JPAUnitTestCase.java

hibernate.cfg.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- Database connection settings -->
        <property name="connection.driver_class">org.sqlite.JDBC</property>
        <property name="connection.url">jdbc:sqlite:mydatabase.sqlite</property>

        <!-- SQL dialect for SQLite -->
        <!-- <property name="dialect">org.hibernate.dialect.SQLiteDialect</property> -->
<!--        <property name="hibernate.dialect">org.hibernate.community.dialect.SQLiteDialect</property>-->
        <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
        <property name="hbm2ddl.auto">update</property>
        <property name="show_sql">true</property>
        <mapping class="com.mycompany.myapp.Basket"/>
        <mapping class="com.mycompany.myapp.Watermelon"/>
        <mapping class="com.mycompany.myapp.Kiwi"/>
    </session-factory>
</hibernate-configuration>

persistence.xml:

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">
    <persistence-unit name="templatePU">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>com.mycompany.myapp.Basket</class>
        <class>com.mycompany.myapp.Watermelon</class>
        <class>com.mycompany.myapp.Kiwi</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.sqlite.JDBC"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:sqlite:mydatabase.sqlite"/>
            <property name="hibernate.dialect" value="org.hibernate.community.dialect.SQLiteDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.show_sql" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

Driver.java:

Basket.java:

package com.mycompany.myapp;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Entity
public class Basket implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    @Column(name="basketUuid")
    private String basketUuid;

    private String brandName;

    @Convert(converter = WatermelonConverter.class)
    @OneToOne(mappedBy="basket", cascade=CascadeType.ALL)
    private Watermelon watermelon;

    @Convert(converter = KiwiConverter.class)
    @Convert(converter = StringListConverter.class)
    @OneToMany(mappedBy="basket", cascade=CascadeType.ALL)
    @ElementCollection
    private List<Kiwi> kiwis;

    public Basket() {
        this(UUID.randomUUID().toString(), "Generic", new Watermelon(), new ArrayList<Kiwi>());
    }

    @Override
    public String toString() {
        return "Basket{" +
                "basketUuid='" + basketUuid + '\'' +
                ", brandName='" + brandName + '\'' +
                ", watermelon=" + watermelon +
                ", kiwis=" + kiwis +
                '}';
    }

    public Basket(String basketUuid, String brandName, Watermelon watermelon, List<Kiwi> kiwis) {
        this.basketUuid = basketUuid;
        this.brandName = brandName;
        this.watermelon = watermelon;
        this.kiwis = kiwis;
    }

    public String getBasketUuid() {
        return basketUuid;
    }

    public void setBasketUuid(String basketUuid) {
        this.basketUuid = basketUuid;
    }

    public String getBrandName() {
        return brandName;
    }

    public void setBrandName(String brandName) {
        this.brandName = brandName;
    }

    public Watermelon getWatermelon() {
        return watermelon;
    }

    public void setWatermelon(Watermelon watermelon) {
        this.watermelon = watermelon;
    }

    public List<Kiwi> getKiwis() {
        return kiwis;
    }

    public void setKiwis(List<Kiwi> kiwis) {
        this.kiwis = kiwis;
    }
}

HibernateUtil.java:

KiwiConverter.java:

Kiwi.java:

package com.mycompany.myapp;

import jakarta.persistence.Entity;
import static jakarta.persistence.FetchType.LAZY;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import java.time.LocalDateTime;
import java.util.UUID;

@Entity
public class Kiwi {

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String kiwiUuid;

    private double purchasePrice;

    private LocalDateTime purchaseTimestamp;

    @ManyToOne(fetch=LAZY)
//    @ManyToOne
    @JoinColumn(name="basketUuid")
    private Basket basket;

    public Kiwi() {
//        this(UUID.randomUUID().toString(), 1.0, LocalDateTime.now(), new Basket());
    }

    public Kiwi(String kiwiUuid, double purchasePrice, LocalDateTime purchaseTimestamp, Basket basket) {
        this.kiwiUuid = kiwiUuid;
        this.purchasePrice = purchasePrice;
        this.purchaseTimestamp = purchaseTimestamp;
        this.basket = basket;
    }

    @Override
    public String toString() {
        return "Kiwi{" +
                "kiwiUuid='" + kiwiUuid + '\'' +
                ", purchasePrice=" + purchasePrice +
                ", purchaseTimestamp=" + purchaseTimestamp +
                ", basket=" + basket +
                '}';
    }

    public String getKiwiUuid() {
        return kiwiUuid;
    }

    public void setKiwiUuid(String kiwiUuid) {
        this.kiwiUuid = kiwiUuid;
    }

    public double getPurchasePrice() {
        return purchasePrice;
    }

    public void setPurchasePrice(double purchasePrice) {
        this.purchasePrice = purchasePrice;
    }

    public LocalDateTime getPurchaseTimestamp() {
        return purchaseTimestamp;
    }

    public void setPurchaseTimestamp(LocalDateTime purchaseTimestamp) {
        this.purchaseTimestamp = purchaseTimestamp;
    }

    public Basket getBasket() {
        return basket;
    }

    public void setBasket(Basket basket) {
        this.basket = basket;
    }
}

StringListConverter.java:

WatermelonConverter.java:

Watermelon.java:

package com.mycompany.myapp;

import jakarta.persistence.Basic;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import java.time.LocalDateTime;

@Entity
public class Watermelon {
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String watermelonUuid;

    private double purchasePrice;

    @Basic
    private LocalDateTime purchaseTimestamp;

    @OneToOne
    @JoinColumn(name="basketUuid")
    private Basket basket;

    @Override
    public String toString() {
        return "Watermelon{" +
                "watermelonUuid='" + watermelonUuid + '\'' +
                ", purchasePrice=" + purchasePrice +
                ", purchaseTimestamp=" + purchaseTimestamp +
                ", basket=" + basket +
                '}';
    }

    public Watermelon() {
//        this(0.0, LocalDateTime.now());
    }

    public Watermelon(double purchasePrice, LocalDateTime purchaseTimestamp) {
        this.purchasePrice = purchasePrice;
        this.purchaseTimestamp = purchaseTimestamp;
    }

    public String getWatermelonUuid() {
        return watermelonUuid;
    }

    public void setWatermelonUuid(String uuid) {
        this.watermelonUuid = uuid;
    }

    public double getPurchasePrice() {
        return purchasePrice;
    }

    public void setPurchasePrice(double purchasePrice) {
        this.purchasePrice = purchasePrice;
    }

    public LocalDateTime getPurchaseTimestamp() {
        return purchaseTimestamp;
    }

    public void setPurchaseTimestamp(LocalDateTime purchaseTimestamp) {
        this.purchaseTimestamp = purchaseTimestamp;
    }
}

BasketDao.java:

JPAUnitTestCase.java:

package org.hibernate.bugs;

import com.mycompany.myapp.Basket;
import com.mycompany.myapp.Kiwi;
import com.mycompany.myapp.Watermelon;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

//import org.junit.After;
//import org.junit.Before;
//import org.junit.Test;

/**
 * This template demonstrates how to develop a test case for Hibernate ORM, using the Java Persistence API.
 */
public class JPAUnitTestCase {

    private EntityManagerFactory entityManagerFactory;

    @BeforeEach
    public void init() {
        entityManagerFactory = Persistence.createEntityManagerFactory( "templatePU" );
    }

    @AfterEach
    public void destroy() {
        entityManagerFactory.close();
    }

    // Entities are auto-discovered, so just add them anywhere on class-path
    // Add your tests, using standard JUnit.
    @Test
    public void hhh123Test() throws Exception {
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();

        // Do stuff...
        Watermelon watermelon = new Watermelon(10.0, LocalDateTime.now());
        Kiwi kiwi1 = new Kiwi();
        kiwi1.setPurchasePrice(1.0);
        kiwi1.setPurchaseTimestamp(LocalDateTime.now());
        Kiwi kiwi2 = new Kiwi();
        kiwi2.setPurchasePrice(1.0);
        kiwi2.setPurchaseTimestamp(LocalDateTime.now().plusMinutes(1));
        List<Kiwi> kiwis = new ArrayList<>(2);
        kiwis.add(kiwi1);
        kiwis.add(kiwi2);

        Basket basket = new Basket();
        basket.setBrandName("Tote");
        basket.setWatermelon(watermelon);
        basket.setKiwis(kiwis);

        entityManager.merge(basket);

        entityManager.getTransaction().commit();

        ///////////////
        // Accessing the data
        List<Basket> baskets = entityManager.createQuery("FROM Basket").getResultList(); // Basket persistedBasket = entityManager.find(Basket.class, basket.getId());
        System.out.println("baskets: " + baskets);
        Basket persistedBasket = baskets.get(0);
        List<Kiwi> persistedKiwis = persistedBasket.getKiwis();
        Watermelon persistedWatermelon = persistedBasket.getWatermelon();

        // Work with the persisted data as needed
        System.out.println(persistedBasket);
        for (Kiwi persistedKiwi : persistedKiwis) {
            System.out.println(persistedKiwi);
            System.out.println(persistedKiwi);
        }
        ///////////////

        entityManager.close();
    }
}

Output of running the test code:

/usr/lib/jvm/java-1.17.0-openjdk-amd64/bin/java -ea -Didea.test.cyclic.buffer.size=1048576 -javaagent:/home/user/idea-IC-232.9559.62/lib/idea_rt.jar=35275:/home/user/idea-IC-232.9559.62/bin -Dfile.encoding=UTF-8 -classpath /home/user/.m2/repository/org/junit/platform/junit-platform-launcher/1.10.0/junit-platform-launcher-1.10.0.jar:/home/user/.m2/repository/org/junit/platform/junit-platform-engine/1.10.0/junit-platform-engine-1.10.0.jar:/home/user/.m2/repository/org/junit/jupiter/junit-jupiter-engine/5.10.0/junit-jupiter-engine-5.10.0.jar:/home/user/idea-IC-232.9559.62/lib/idea_rt.jar:/home/user/idea-IC-232.9559.62/plugins/junit/lib/junit5-rt.jar:/home/user/idea-IC-232.9559.62/plugins/junit/lib/junit-rt.jar:/home/user/IdeaProjects/MiniProjectForForumHelp/target/test-classes:/home/user/IdeaProjects/MiniProjectForForumHelp/target/classes:/home/user/.m2/repository/org/xerial/sqlite-jdbc/3.43.0.0/sqlite-jdbc-3.43.0.0.jar:/home/user/.m2/repository/org/hibernate/orm/hibernate-core/6.3.1.Final/hibernate-core-6.3.1.Final.jar:/home/user/.m2/repository/jakarta/persistence/jakarta.persistence-api/3.1.0/jakarta.persistence-api-3.1.0.jar:/home/user/.m2/repository/jakarta/transaction/jakarta.transaction-api/2.0.1/jakarta.transaction-api-2.0.1.jar:/home/user/.m2/repository/org/jboss/logging/jboss-logging/3.5.0.Final/jboss-logging-3.5.0.Final.jar:/home/user/.m2/repository/org/hibernate/common/hibernate-commons-annotations/6.0.6.Final/hibernate-commons-annotations-6.0.6.Final.jar:/home/user/.m2/repository/io/smallrye/jandex/3.1.2/jandex-3.1.2.jar:/home/user/.m2/repository/com/fasterxml/classmate/1.5.1/classmate-1.5.1.jar:/home/user/.m2/repository/net/bytebuddy/byte-buddy/1.14.7/byte-buddy-1.14.7.jar:/home/user/.m2/repository/jakarta/xml/bind/jakarta.xml.bind-api/4.0.0/jakarta.xml.bind-api-4.0.0.jar:/home/user/.m2/repository/jakarta/activation/jakarta.activation-api/2.1.0/jakarta.activation-api-2.1.0.jar:/home/user/.m2/repository/org/glassfish/jaxb/jaxb-runtime/4.0.2/jaxb-runtime-4.0.2.jar:/home/user/.m2/repository/org/glassfish/jaxb/jaxb-core/4.0.2/jaxb-core-4.0.2.jar:/home/user/.m2/repository/org/eclipse/angus/angus-activation/2.0.0/angus-activation-2.0.0.jar:/home/user/.m2/repository/org/glassfish/jaxb/txw2/4.0.2/txw2-4.0.2.jar:/home/user/.m2/repository/com/sun/istack/istack-commons-runtime/4.1.1/istack-commons-runtime-4.1.1.jar:/home/user/.m2/repository/jakarta/inject/jakarta.inject-api/2.0.1/jakarta.inject-api-2.0.1.jar:/home/user/.m2/repository/org/antlr/antlr4-runtime/4.10.1/antlr4-runtime-4.10.1.jar:/home/user/.m2/repository/org/hibernate/orm/hibernate-community-dialects/6.2.7.Final/hibernate-community-dialects-6.2.7.Final.jar:/home/user/.m2/repository/org/junit/jupiter/junit-jupiter-api/5.10.0/junit-jupiter-api-5.10.0.jar:/home/user/.m2/repository/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar:/home/user/.m2/repository/org/junit/platform/junit-platform-commons/1.10.0/junit-platform-commons-1.10.0.jar:/home/user/.m2/repository/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar:/home/user/.m2/repository/com/h2database/h2/2.2.224/h2-2.2.224.jar com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit5 org.hibernate.bugs.JPAUnitTestCase,hhh123Test
Oct. 03, 2023 4:00:40 A.M. org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH000204: Processing PersistenceUnitInfo [name: templatePU]
Oct. 03, 2023 4:00:41 A.M. org.hibernate.Version logVersion
INFO: HHH000412: Hibernate ORM core version 6.3.1.Final
Oct. 03, 2023 4:00:41 A.M. org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl normalizeDataAccess
WARN: HHH90000021: Encountered deprecated setting [javax.persistence.jdbc.url], use [jakarta.persistence.jdbc.url] instead
Oct. 03, 2023 4:00:41 A.M. org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl normalizeDataAccess
WARN: HHH90000021: Encountered deprecated setting [javax.persistence.jdbc.driver], use [jakarta.persistence.jdbc.driver] instead
Oct. 03, 2023 4:00:42 A.M. org.hibernate.cache.internal.RegionFactoryInitiator initiateService
INFO: HHH000026: Second-level cache disabled
Oct. 03, 2023 4:00:43 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using built-in connection pool (not intended for production use)
Oct. 03, 2023 4:00:43 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: Loaded JDBC driver class: org.sqlite.JDBC
Oct. 03, 2023 4:00:43 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001012: Connecting with JDBC URL [jdbc:sqlite:mydatabase.sqlite]
Oct. 03, 2023 4:00:43 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {}
Oct. 03, 2023 4:00:43 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
Oct. 03, 2023 4:00:43 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
INFO: HHH10001115: Connection pool size: 20 (min=1)
Oct. 03, 2023 4:00:45 A.M. org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
Oct. 03, 2023 4:00:45 A.M. org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@4351ed61] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: select b1_0.basketUuid,b1_0.brandName,w1_0.watermelonUuid,w1_0.purchasePrice,w1_0.purchaseTimestamp,k1_0.basketUuid,k1_0.kiwiUuid,k1_0.purchasePrice,k1_0.purchaseTimestamp from Basket b1_0 left join Watermelon w1_0 on b1_0.basketUuid=w1_0.basketUuid left join Kiwi k1_0 on b1_0.basketUuid=k1_0.basketUuid where b1_0.basketUuid=?
Hibernate: insert into Basket (brandName,basketUuid) values (?,?)
Hibernate: insert into Kiwi (basketUuid,purchasePrice,purchaseTimestamp,kiwiUuid) values (?,?,?,?)
Hibernate: insert into Kiwi (basketUuid,purchasePrice,purchaseTimestamp,kiwiUuid) values (?,?,?,?)
Hibernate: insert into Watermelon (basketUuid,purchasePrice,purchaseTimestamp,watermelonUuid) values (?,?,?,?)
Hibernate: select b1_0.basketUuid,b1_0.brandName from Basket b1_0
Hibernate: select w1_0.watermelonUuid,b1_0.basketUuid,b1_0.brandName,w1_0.purchasePrice,w1_0.purchaseTimestamp from Watermelon w1_0 left join Basket b1_0 on b1_0.basketUuid=w1_0.basketUuid where w1_0.basketUuid=?
Hibernate: select w1_0.watermelonUuid,b1_0.basketUuid,b1_0.brandName,w1_0.purchasePrice,w1_0.purchaseTimestamp from Watermelon w1_0 left join Basket b1_0 on b1_0.basketUuid=w1_0.basketUuid where w1_0.basketUuid=?
Hibernate: select w1_0.watermelonUuid,b1_0.basketUuid,b1_0.brandName,w1_0.purchasePrice,w1_0.purchaseTimestamp from Watermelon w1_0 left join Basket b1_0 on b1_0.basketUuid=w1_0.basketUuid where w1_0.basketUuid=?
Hibernate: select w1_0.watermelonUuid,b1_0.basketUuid,b1_0.brandName,w1_0.purchasePrice,w1_0.purchaseTimestamp from Watermelon w1_0 left join Basket b1_0 on b1_0.basketUuid=w1_0.basketUuid where w1_0.basketUuid=?
Hibernate: select w1_0.watermelonUuid,b1_0.basketUuid,b1_0.brandName,w1_0.purchasePrice,w1_0.purchaseTimestamp from Watermelon w1_0 left join Basket b1_0 on b1_0.basketUuid=w1_0.basketUuid where w1_0.basketUuid=?
Hibernate: select k1_0.basketUuid,k1_0.kiwiUuid,k1_0.purchasePrice,k1_0.purchaseTimestamp from Kiwi k1_0 where k1_0.basketUuid=?
Hibernate: select k1_0.basketUuid,k1_0.kiwiUuid,k1_0.purchasePrice,k1_0.purchaseTimestamp from Kiwi k1_0 where k1_0.basketUuid=?
Hibernate: select k1_0.basketUuid,k1_0.kiwiUuid,k1_0.purchasePrice,k1_0.purchaseTimestamp from Kiwi k1_0 where k1_0.basketUuid=?
Hibernate: select k1_0.basketUuid,k1_0.kiwiUuid,k1_0.purchasePrice,k1_0.purchaseTimestamp from Kiwi k1_0 where k1_0.basketUuid=?
Hibernate: select k1_0.basketUuid,k1_0.kiwiUuid,k1_0.purchasePrice,k1_0.purchaseTimestamp from Kiwi k1_0 where k1_0.basketUuid=?
baskets: [Basket{basketUuid='83ec5f0b-f6d7-43d7-97d9-6c3c263e3c76', brandName='Tote', watermelon=null, kiwis=[]}, Basket{basketUuid='77373ee4-d0de-4c1a-9faf-8a486ab100f7', brandName='Tote', watermelon=null, kiwis=[]}, Basket{basketUuid='27bb10c0-b882-4154-9a09-c3c38aa75001', brandName='Tote', watermelon=null, kiwis=[]}, Basket{basketUuid='61df5541-1afd-4a25-90ee-ad645333bc76', brandName='Tote', watermelon=null, kiwis=[]}, Basket{basketUuid='1b3fedef-36d7-4000-a728-82e0de3da273', brandName='Tote', watermelon=null, kiwis=[]}, Basket{basketUuid='d396ea8f-178f-4ae2-93c5-f952cf40abfc', brandName='Tote', watermelon=Watermelon{watermelonUuid='4dbaca3a-1de7-4c93-a153-186a73419cf6', purchasePrice=10.0, purchaseTimestamp=2023-10-03T04:00:45.574033536, basket=null}, kiwis=[Kiwi{kiwiUuid='5eab5db4-320b-4dfa-a6c8-40076c948d5c', purchasePrice=1.0, purchaseTimestamp=2023-10-03T04:00:45.574073430, basket=null}, Kiwi{kiwiUuid='5af9bc8d-6e38-4906-bac9-b4f21c79a03e', purchasePrice=1.0, purchaseTimestamp=2023-10-03T04:01:45.574092187, basket=null}]}]
Basket{basketUuid='83ec5f0b-f6d7-43d7-97d9-6c3c263e3c76', brandName='Tote', watermelon=null, kiwis=[]}
Oct. 03, 2023 4:00:45 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PoolState stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:sqlite:mydatabase.sqlite]

Process finished with exit code 0

persistence.xml:

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">
    <persistence-unit name="templatePU">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>com.mycompany.myapp.Basket</class>
        <class>com.mycompany.myapp.Watermelon</class>
        <class>com.mycompany.myapp.Kiwi</class>
        <properties>
            <!-- <property name="jakarta.persistence.jdbc.driver" value="org.sqlite.JDBC"/> -->
            <!-- <property name="jakarta.persistence.jdbc.url" value="jdbc:sqlite:mydatabase.sqlite"/> -->
            <property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="jakarta.persistence.jdbc.url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"/>
            <!-- <property name="hibernate.dialect" value="org.hibernate.community.dialect.SQLiteDialect"/> -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.show_sql" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

JPAUnitTestCase.java:

package org.hibernate.bugs;

import com.mycompany.myapp.Basket;
import com.mycompany.myapp.Kiwi;
import com.mycompany.myapp.Watermelon;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

//import org.junit.After;
//import org.junit.Before;
//import org.junit.Test;

/**
 * This template demonstrates how to develop a test case for Hibernate ORM, using the Java Persistence API.
 */
public class JPAUnitTestCase {

    private EntityManagerFactory entityManagerFactory;

    @BeforeEach
    public void init() {
        entityManagerFactory = Persistence.createEntityManagerFactory( "templatePU" );
    }

    @AfterEach
    public void destroy() {
        entityManagerFactory.close();
    }

    // Entities are auto-discovered, so just add them anywhere on class-path
    // Add your tests, using standard JUnit.
    @Test
    public void hhh123Test() throws Exception {
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();

        // Do stuff...
        Watermelon watermelon = new Watermelon(10.0, LocalDateTime.now());
        Kiwi kiwi1 = new Kiwi();
        kiwi1.setPurchasePrice(1.0);
        kiwi1.setPurchaseTimestamp(LocalDateTime.now());
        Kiwi kiwi2 = new Kiwi();
        kiwi2.setPurchasePrice(1.0);
        kiwi2.setPurchaseTimestamp(LocalDateTime.now().plusMinutes(1));
        List<Kiwi> kiwis = new ArrayList<>(2);
        kiwis.add(kiwi1);
        kiwis.add(kiwi2);

        Basket basket = new Basket();
        basket.setBrandName("Tote");
        basket.setWatermelon(watermelon);
        basket.setKiwis(kiwis);

        entityManager.merge(basket);

        entityManager.getTransaction().commit();

        ///////////////
        // Accessing the data
        List<Basket> persistedBaskets = entityManager.createQuery("FROM Basket").getResultList(); // Basket persistedBasket = entityManager.find(Basket.class, basket.getId());
        System.out.println("Persisted Baskets: " + persistedBaskets);
        Basket persistedBasket = persistedBaskets.get(0);
        List<Kiwi> persistedKiwis = persistedBasket.getKiwis();
        Watermelon persistedWatermelon = persistedBasket.getWatermelon();

        System.out.println(persistedBasket);

        System.out.println(watermelon);

        for (Kiwi persistedKiwi : persistedKiwis) {
            System.out.println(persistedKiwi);
        }
        ///////////////

        entityManager.close();
    }
}

Output of running the test code (JPAUnitTestCase.java):

/usr/lib/jvm/java-1.17.0-openjdk-amd64/bin/java -ea -Didea.test.cyclic.buffer.size=1048576 -javaagent:/home/user/idea-IC-232.9559.62/lib/idea_rt.jar=42803:/home/user/idea-IC-232.9559.62/bin -Dfile.encoding=UTF-8 -classpath /home/user/.m2/repository/org/junit/platform/junit-platform-launcher/1.10.0/junit-platform-launcher-1.10.0.jar:/home/user/.m2/repository/org/junit/platform/junit-platform-engine/1.10.0/junit-platform-engine-1.10.0.jar:/home/user/.m2/repository/org/junit/jupiter/junit-jupiter-engine/5.10.0/junit-jupiter-engine-5.10.0.jar:/home/user/idea-IC-232.9559.62/lib/idea_rt.jar:/home/user/idea-IC-232.9559.62/plugins/junit/lib/junit5-rt.jar:/home/user/idea-IC-232.9559.62/plugins/junit/lib/junit-rt.jar:/home/user/IdeaProjects/MiniProjectForForumHelp/target/test-classes:/home/user/IdeaProjects/MiniProjectForForumHelp/target/classes:/home/user/.m2/repository/org/xerial/sqlite-jdbc/3.43.0.0/sqlite-jdbc-3.43.0.0.jar:/home/user/.m2/repository/org/hibernate/orm/hibernate-core/6.3.1.Final/hibernate-core-6.3.1.Final.jar:/home/user/.m2/repository/jakarta/persistence/jakarta.persistence-api/3.1.0/jakarta.persistence-api-3.1.0.jar:/home/user/.m2/repository/jakarta/transaction/jakarta.transaction-api/2.0.1/jakarta.transaction-api-2.0.1.jar:/home/user/.m2/repository/org/jboss/logging/jboss-logging/3.5.0.Final/jboss-logging-3.5.0.Final.jar:/home/user/.m2/repository/org/hibernate/common/hibernate-commons-annotations/6.0.6.Final/hibernate-commons-annotations-6.0.6.Final.jar:/home/user/.m2/repository/io/smallrye/jandex/3.1.2/jandex-3.1.2.jar:/home/user/.m2/repository/com/fasterxml/classmate/1.5.1/classmate-1.5.1.jar:/home/user/.m2/repository/net/bytebuddy/byte-buddy/1.14.7/byte-buddy-1.14.7.jar:/home/user/.m2/repository/jakarta/xml/bind/jakarta.xml.bind-api/4.0.0/jakarta.xml.bind-api-4.0.0.jar:/home/user/.m2/repository/jakarta/activation/jakarta.activation-api/2.1.0/jakarta.activation-api-2.1.0.jar:/home/user/.m2/repository/org/glassfish/jaxb/jaxb-runtime/4.0.2/jaxb-runtime-4.0.2.jar:/home/user/.m2/repository/org/glassfish/jaxb/jaxb-core/4.0.2/jaxb-core-4.0.2.jar:/home/user/.m2/repository/org/eclipse/angus/angus-activation/2.0.0/angus-activation-2.0.0.jar:/home/user/.m2/repository/org/glassfish/jaxb/txw2/4.0.2/txw2-4.0.2.jar:/home/user/.m2/repository/com/sun/istack/istack-commons-runtime/4.1.1/istack-commons-runtime-4.1.1.jar:/home/user/.m2/repository/jakarta/inject/jakarta.inject-api/2.0.1/jakarta.inject-api-2.0.1.jar:/home/user/.m2/repository/org/antlr/antlr4-runtime/4.10.1/antlr4-runtime-4.10.1.jar:/home/user/.m2/repository/org/hibernate/orm/hibernate-community-dialects/6.2.7.Final/hibernate-community-dialects-6.2.7.Final.jar:/home/user/.m2/repository/org/junit/jupiter/junit-jupiter-api/5.10.0/junit-jupiter-api-5.10.0.jar:/home/user/.m2/repository/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar:/home/user/.m2/repository/org/junit/platform/junit-platform-commons/1.10.0/junit-platform-commons-1.10.0.jar:/home/user/.m2/repository/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar:/home/user/.m2/repository/com/h2database/h2/2.2.224/h2-2.2.224.jar com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit5 org.hibernate.bugs.JPAUnitTestCase
Oct. 03, 2023 5:35:53 A.M. org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH000204: Processing PersistenceUnitInfo [name: templatePU]
Oct. 03, 2023 5:35:53 A.M. org.hibernate.Version logVersion
INFO: HHH000412: Hibernate ORM core version 6.3.1.Final
Oct. 03, 2023 5:35:53 A.M. org.hibernate.cache.internal.RegionFactoryInitiator initiateService
INFO: HHH000026: Second-level cache disabled
Oct. 03, 2023 5:35:53 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using built-in connection pool (not intended for production use)
Oct. 03, 2023 5:35:53 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: Loaded JDBC driver class: org.h2.Driver
Oct. 03, 2023 5:35:53 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001012: Connecting with JDBC URL [jdbc:h2:mem:test;DB_CLOSE_DELAY=-1]
Oct. 03, 2023 5:35:53 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {}
Oct. 03, 2023 5:35:53 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
Oct. 03, 2023 5:35:53 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
INFO: HHH10001115: Connection pool size: 20 (min=1)
Oct. 03, 2023 5:35:54 A.M. org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl constructDialect
WARN: HHH90000025: H2Dialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default)
Oct. 03, 2023 5:35:54 A.M. org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
Oct. 03, 2023 5:35:54 A.M. org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@548e43b1] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: create table Basket (basketUuid varchar(255) not null, brandName varchar(255), primary key (basketUuid))
Hibernate: create table Kiwi (kiwiUuid varchar(255) not null, purchasePrice float(53) not null, purchaseTimestamp timestamp(6), basketUuid varchar(255), primary key (kiwiUuid))
Hibernate: create table Watermelon (watermelonUuid varchar(255) not null, purchasePrice float(53) not null, purchaseTimestamp timestamp(6), basketUuid varchar(255), primary key (watermelonUuid))
Hibernate: alter table if exists Watermelon drop constraint if exists UK_ad6t7ccky3nwuethuv9mreq90
Hibernate: alter table if exists Watermelon add constraint UK_ad6t7ccky3nwuethuv9mreq90 unique (basketUuid)
Hibernate: alter table if exists Kiwi add constraint FK258orov1cuirecxfvovjn3f5l foreign key (basketUuid) references Basket
Hibernate: alter table if exists Watermelon add constraint FK3eaflmfr759v2ek4ofjtjmbno foreign key (basketUuid) references Basket
Hibernate: select b1_0.basketUuid,b1_0.brandName,w1_0.watermelonUuid,w1_0.purchasePrice,w1_0.purchaseTimestamp,k1_0.basketUuid,k1_0.kiwiUuid,k1_0.purchasePrice,k1_0.purchaseTimestamp from Basket b1_0 left join Watermelon w1_0 on b1_0.basketUuid=w1_0.basketUuid left join Kiwi k1_0 on b1_0.basketUuid=k1_0.basketUuid where b1_0.basketUuid=?
Hibernate: insert into Basket (brandName,basketUuid) values (?,?)
Hibernate: insert into Kiwi (basketUuid,purchasePrice,purchaseTimestamp,kiwiUuid) values (?,?,?,?)
Hibernate: insert into Kiwi (basketUuid,purchasePrice,purchaseTimestamp,kiwiUuid) values (?,?,?,?)
Hibernate: insert into Watermelon (basketUuid,purchasePrice,purchaseTimestamp,watermelonUuid) values (?,?,?,?)
Hibernate: select b1_0.basketUuid,b1_0.brandName from Basket b1_0
Persisted Baskets: [Basket{basketUuid='2d94d934-0b5b-49da-aa5a-d960669215cf', brandName='Tote', watermelon=Watermelon{watermelonUuid='082415b7-6a0e-4fd6-b28f-41326b49aa30', purchasePrice=10.0, purchaseTimestamp=2023-10-03T05:35:55.047945507, basket=null}, kiwis=[Kiwi{kiwiUuid='e7bb6ee6-4a0f-451a-8296-b73298024cea', purchasePrice=1.0, purchaseTimestamp=2023-10-03T05:35:55.047980199, basket=null}, Kiwi{kiwiUuid='4b1b2187-a9f0-4a44-a032-2c853db94add', purchasePrice=1.0, purchaseTimestamp=2023-10-03T05:36:55.047989542, basket=null}]}]
Basket{basketUuid='2d94d934-0b5b-49da-aa5a-d960669215cf', brandName='Tote', watermelon=Watermelon{watermelonUuid='082415b7-6a0e-4fd6-b28f-41326b49aa30', purchasePrice=10.0, purchaseTimestamp=2023-10-03T05:35:55.047945507, basket=null}, kiwis=[Kiwi{kiwiUuid='e7bb6ee6-4a0f-451a-8296-b73298024cea', purchasePrice=1.0, purchaseTimestamp=2023-10-03T05:35:55.047980199, basket=null}, Kiwi{kiwiUuid='4b1b2187-a9f0-4a44-a032-2c853db94add', purchasePrice=1.0, purchaseTimestamp=2023-10-03T05:36:55.047989542, basket=null}]}
Watermelon{watermelonUuid='082415b7-6a0e-4fd6-b28f-41326b49aa30', purchasePrice=10.0, purchaseTimestamp=2023-10-03T05:35:55.047945507, basket=null}
Kiwi{kiwiUuid='e7bb6ee6-4a0f-451a-8296-b73298024cea', purchasePrice=1.0, purchaseTimestamp=2023-10-03T05:35:55.047980199, basket=null}
Kiwi{kiwiUuid='4b1b2187-a9f0-4a44-a032-2c853db94add', purchasePrice=1.0, purchaseTimestamp=2023-10-03T05:36:55.047989542, basket=null}
Oct. 03, 2023 5:35:55 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PoolState stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:h2:mem:test;DB_CLOSE_DELAY=-1]

Process finished with exit code 0

Sorry to bother you again, but do you think the problem is the pair of converters after all?

That’s all I can think of, mostly because I’m assuming you focused mostly on the annotations and also because I still feel a little confused about the involvement of the Basket in the Watermelon and Kiwi converters (WatermelonConverter and KiwiConverter).

Do I also need a Basket converter (so, a BasketConverter, for example)?

I don’t know what to tell you. Your model is just completely wrong.

You can’t mix @Convert and @OneToOne/@ManyToOne/@OneToMany/@ManyToMany. The only case where @Convert would make sense is if you used it for a map key, also see Convert (Jakarta Persistence API documentation)

The next problem is that you mix @OneToMany and @ElementCollection. It has to be either one or the other. If the element type is an entity, then it can’t be @ElementCollection.

Fix your model and if you still have problems, try to come up with a reproducer test case.

Thanks for the response. :slight_smile:

Here is the new Basket.java (which is the only file I changed).:

package com.mycompany.myapp;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Entity
public class Basket implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    @Column(name="basketUuid")
    private String basketUuid;

    private String brandName;

//    @Convert(converter = WatermelonConverter.class)
    @OneToOne(mappedBy="basket", cascade=CascadeType.ALL)
    private Watermelon watermelon;

//    @Convert(converter = KiwiConverter.class)
//    @Convert(converter = StringListConverter.class)
    @OneToMany(mappedBy="basket", cascade=CascadeType.ALL)
//    @ElementCollection
    private List<Kiwi> kiwis;

    public Basket() {
        this(UUID.randomUUID().toString(), "Generic", new Watermelon(), new ArrayList<Kiwi>());
    }

    @Override
    public String toString() {
        return "Basket{" +
                "basketUuid='" + basketUuid + '\'' +
                ", brandName='" + brandName + '\'' +
                ", watermelon=" + watermelon +
                ", kiwis=" + kiwis +
                '}';
    }

    public Basket(String basketUuid, String brandName, Watermelon watermelon, List<Kiwi> kiwis) {
        this.basketUuid = basketUuid;
        this.brandName = brandName;
        this.watermelon = watermelon;
        this.kiwis = kiwis;
    }

    public String getBasketUuid() {
        return basketUuid;
    }

    public void setBasketUuid(String basketUuid) {
        this.basketUuid = basketUuid;
    }

    public String getBrandName() {
        return brandName;
    }

    public void setBrandName(String brandName) {
        this.brandName = brandName;
    }

    public Watermelon getWatermelon() {
        return watermelon;
    }

    public void setWatermelon(Watermelon watermelon) {
        this.watermelon = watermelon;
    }

    public List<Kiwi> getKiwis() {
        return kiwis;
    }

    public void setKiwis(List<Kiwi> kiwis) {
        this.kiwis = kiwis;
    }
}

It seems I get the same output in my modification of the test code template you linked to.:

/usr/lib/jvm/java-1.17.0-openjdk-amd64/bin/java -ea -Didea.test.cyclic.buffer.size=1048576 -javaagent:/home/user/idea-IC-232.9559.62/lib/idea_rt.jar=41305:/home/user/idea-IC-232.9559.62/bin -Dfile.encoding=UTF-8 -classpath /home/user/.m2/repository/org/junit/platform/junit-platform-launcher/1.10.0/junit-platform-launcher-1.10.0.jar:/home/user/.m2/repository/org/junit/platform/junit-platform-engine/1.10.0/junit-platform-engine-1.10.0.jar:/home/user/.m2/repository/org/junit/jupiter/junit-jupiter-engine/5.10.0/junit-jupiter-engine-5.10.0.jar:/home/user/idea-IC-232.9559.62/lib/idea_rt.jar:/home/user/idea-IC-232.9559.62/plugins/junit/lib/junit5-rt.jar:/home/user/idea-IC-232.9559.62/plugins/junit/lib/junit-rt.jar:/home/user/IdeaProjects/MiniProjectForForumHelp/target/test-classes:/home/user/IdeaProjects/MiniProjectForForumHelp/target/classes:/home/user/.m2/repository/org/xerial/sqlite-jdbc/3.43.0.0/sqlite-jdbc-3.43.0.0.jar:/home/user/.m2/repository/org/hibernate/orm/hibernate-core/6.3.1.Final/hibernate-core-6.3.1.Final.jar:/home/user/.m2/repository/jakarta/persistence/jakarta.persistence-api/3.1.0/jakarta.persistence-api-3.1.0.jar:/home/user/.m2/repository/jakarta/transaction/jakarta.transaction-api/2.0.1/jakarta.transaction-api-2.0.1.jar:/home/user/.m2/repository/org/jboss/logging/jboss-logging/3.5.0.Final/jboss-logging-3.5.0.Final.jar:/home/user/.m2/repository/org/hibernate/common/hibernate-commons-annotations/6.0.6.Final/hibernate-commons-annotations-6.0.6.Final.jar:/home/user/.m2/repository/io/smallrye/jandex/3.1.2/jandex-3.1.2.jar:/home/user/.m2/repository/com/fasterxml/classmate/1.5.1/classmate-1.5.1.jar:/home/user/.m2/repository/net/bytebuddy/byte-buddy/1.14.7/byte-buddy-1.14.7.jar:/home/user/.m2/repository/jakarta/xml/bind/jakarta.xml.bind-api/4.0.0/jakarta.xml.bind-api-4.0.0.jar:/home/user/.m2/repository/jakarta/activation/jakarta.activation-api/2.1.0/jakarta.activation-api-2.1.0.jar:/home/user/.m2/repository/org/glassfish/jaxb/jaxb-runtime/4.0.2/jaxb-runtime-4.0.2.jar:/home/user/.m2/repository/org/glassfish/jaxb/jaxb-core/4.0.2/jaxb-core-4.0.2.jar:/home/user/.m2/repository/org/eclipse/angus/angus-activation/2.0.0/angus-activation-2.0.0.jar:/home/user/.m2/repository/org/glassfish/jaxb/txw2/4.0.2/txw2-4.0.2.jar:/home/user/.m2/repository/com/sun/istack/istack-commons-runtime/4.1.1/istack-commons-runtime-4.1.1.jar:/home/user/.m2/repository/jakarta/inject/jakarta.inject-api/2.0.1/jakarta.inject-api-2.0.1.jar:/home/user/.m2/repository/org/antlr/antlr4-runtime/4.10.1/antlr4-runtime-4.10.1.jar:/home/user/.m2/repository/org/hibernate/orm/hibernate-community-dialects/6.2.7.Final/hibernate-community-dialects-6.2.7.Final.jar:/home/user/.m2/repository/org/junit/jupiter/junit-jupiter-api/5.10.0/junit-jupiter-api-5.10.0.jar:/home/user/.m2/repository/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar:/home/user/.m2/repository/org/junit/platform/junit-platform-commons/1.10.0/junit-platform-commons-1.10.0.jar:/home/user/.m2/repository/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar:/home/user/.m2/repository/com/h2database/h2/2.2.224/h2-2.2.224.jar com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit5 org.hibernate.bugs.JPAUnitTestCase
Oct. 07, 2023 2:23:01 A.M. org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH000204: Processing PersistenceUnitInfo [name: templatePU]
Oct. 07, 2023 2:23:01 A.M. org.hibernate.Version logVersion
INFO: HHH000412: Hibernate ORM core version 6.3.1.Final
Oct. 07, 2023 2:23:01 A.M. org.hibernate.cache.internal.RegionFactoryInitiator initiateService
INFO: HHH000026: Second-level cache disabled
Oct. 07, 2023 2:23:02 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using built-in connection pool (not intended for production use)
Oct. 07, 2023 2:23:02 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: Loaded JDBC driver class: org.h2.Driver
Oct. 07, 2023 2:23:02 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001012: Connecting with JDBC URL [jdbc:h2:mem:test;DB_CLOSE_DELAY=-1]
Oct. 07, 2023 2:23:02 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {}
Oct. 07, 2023 2:23:02 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
Oct. 07, 2023 2:23:02 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
INFO: HHH10001115: Connection pool size: 20 (min=1)
Oct. 07, 2023 2:23:02 A.M. org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl constructDialect
WARN: HHH90000025: H2Dialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default)
Oct. 07, 2023 2:23:03 A.M. org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
Oct. 07, 2023 2:23:03 A.M. org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@5b5f9003] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: create table Basket (basketUuid varchar(255) not null, brandName varchar(255), primary key (basketUuid))
Hibernate: create table Kiwi (kiwiUuid varchar(255) not null, purchasePrice float(53) not null, purchaseTimestamp timestamp(6), basketUuid varchar(255), primary key (kiwiUuid))
Hibernate: create table Watermelon (watermelonUuid varchar(255) not null, purchasePrice float(53) not null, purchaseTimestamp timestamp(6), basketUuid varchar(255), primary key (watermelonUuid))
Hibernate: alter table if exists Watermelon drop constraint if exists UK_ad6t7ccky3nwuethuv9mreq90
Hibernate: alter table if exists Watermelon add constraint UK_ad6t7ccky3nwuethuv9mreq90 unique (basketUuid)
Hibernate: alter table if exists Kiwi add constraint FK258orov1cuirecxfvovjn3f5l foreign key (basketUuid) references Basket
Hibernate: alter table if exists Watermelon add constraint FK3eaflmfr759v2ek4ofjtjmbno foreign key (basketUuid) references Basket
Hibernate: select b1_0.basketUuid,b1_0.brandName,w1_0.watermelonUuid,w1_0.purchasePrice,w1_0.purchaseTimestamp,k1_0.basketUuid,k1_0.kiwiUuid,k1_0.purchasePrice,k1_0.purchaseTimestamp from Basket b1_0 left join Watermelon w1_0 on b1_0.basketUuid=w1_0.basketUuid left join Kiwi k1_0 on b1_0.basketUuid=k1_0.basketUuid where b1_0.basketUuid=?
Hibernate: insert into Basket (brandName,basketUuid) values (?,?)
Hibernate: insert into Kiwi (basketUuid,purchasePrice,purchaseTimestamp,kiwiUuid) values (?,?,?,?)
Hibernate: insert into Kiwi (basketUuid,purchasePrice,purchaseTimestamp,kiwiUuid) values (?,?,?,?)
Hibernate: insert into Watermelon (basketUuid,purchasePrice,purchaseTimestamp,watermelonUuid) values (?,?,?,?)
Hibernate: select b1_0.basketUuid,b1_0.brandName from Basket b1_0
Persisted Baskets: [Basket{basketUuid='6c4f11bf-af06-4cc0-bfde-6f37890cd841', brandName='Tote', watermelon=Watermelon{watermelonUuid='4cd14d26-c0a3-4b34-8495-0bcbbb2e8190', purchasePrice=10.0, purchaseTimestamp=2023-10-07T02:23:03.413746153, basket=null}, kiwis=[Kiwi{kiwiUuid='e35a375b-93ec-4b45-81b6-865049fe14cc', purchasePrice=1.0, purchaseTimestamp=2023-10-07T02:23:03.413783197, basket=null}, Kiwi{kiwiUuid='4833f611-cdf0-4ffc-b30b-ca7a27c3990e', purchasePrice=1.0, purchaseTimestamp=2023-10-07T02:24:03.413792995, basket=null}]}]
Basket{basketUuid='6c4f11bf-af06-4cc0-bfde-6f37890cd841', brandName='Tote', watermelon=Watermelon{watermelonUuid='4cd14d26-c0a3-4b34-8495-0bcbbb2e8190', purchasePrice=10.0, purchaseTimestamp=2023-10-07T02:23:03.413746153, basket=null}, kiwis=[Kiwi{kiwiUuid='e35a375b-93ec-4b45-81b6-865049fe14cc', purchasePrice=1.0, purchaseTimestamp=2023-10-07T02:23:03.413783197, basket=null}, Kiwi{kiwiUuid='4833f611-cdf0-4ffc-b30b-ca7a27c3990e', purchasePrice=1.0, purchaseTimestamp=2023-10-07T02:24:03.413792995, basket=null}]}
Watermelon{watermelonUuid='4cd14d26-c0a3-4b34-8495-0bcbbb2e8190', purchasePrice=10.0, purchaseTimestamp=2023-10-07T02:23:03.413746153, basket=null}
Kiwi{kiwiUuid='e35a375b-93ec-4b45-81b6-865049fe14cc', purchasePrice=1.0, purchaseTimestamp=2023-10-07T02:23:03.413783197, basket=null}
Kiwi{kiwiUuid='4833f611-cdf0-4ffc-b30b-ca7a27c3990e', purchasePrice=1.0, purchaseTimestamp=2023-10-07T02:24:03.413792995, basket=null}
Oct. 07, 2023 2:23:03 A.M. org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PoolState stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:h2:mem:test;DB_CLOSE_DELAY=-1]

Process finished with exit code 0

Like before, the Basket objects in the Kiwi and Watermelon objects are null. This is with the H2 database, by the way (as can be seen in the persistence.xml file for the test code, for example). I’m assuming that this corresponds to the problem I was having before with SQLite, which was that Kiwi and Watermelon had a null value for the column that’s for foreign keys to a Basket.

Each Basket should have up to many Kiwis and up to one Watermelon, hence the @OneToOne for Watermelon in Basket, the @OneToOne for Basket in Watermelon, the @OneToMany for Kiwi in Basket and the @ManyToOne for Basket in Kiwi. Another thing that I’m unsure of which could potentially be a problem is the eager vs lazy fetching stuff. I put what the Hibernate documentation recommended.

Do you see what I am doing wrong (with the current iteration of the code, which is the same as the previous iteration except that Basket.java was modified)?

Hibernate just returns you the objects of your persistence context if available, which are in your test case. Since these objects have no basket set, you see a null.

You have two options, but I’d suggest you go with the first one:

  • Set the basket on Kiwi and Watermelon. You can encapsulate this by disallowing setKiwis and instead add a addKiwi method which will take care of setting the basket field before adding to the kiwis list. You can do the same thing in the setWatermelon method.
  • flush and clear the EntityManager to get rid of the objects that you didn’t setup properly, or close and create a new EntityManager.
1 Like

Sorry for the huge delay.

I did what the first bullet point said, and it now works! Thanks! (I had assumed that Hibernate would be more automatic. :slight_smile:)

Hibernate has the option to implement bi-directional association handling automatically, but for this to work you have to run bytecode enhancement. Also see Hibernate ORM User Guide

1 Like

Thanks for bringing that to my attention!

Technically, I think that I’ll still be using the more manual way, at least for now, but I’m glad I learned about this nonetheless. :smiley: