Note: This file is written in Markdown and is best viewed with a Markdown viewer (e.g., GitHub, GitLab, VS Code, or a dedicated Markdown reader). Viewing it in a plain text editor may not render the formatting as intended.
Copyright (c) 2026 Software Tree
This project demonstrates how JDX ORM handles many-to-many relationships between Java objects using an intermediate join class and table.
The domain model is a classic user-group membership structure:
- A User can belong to many Groups.
- A Group can have many Users.
The many-to-many relationship is managed through a join class UserGroup (mapped to table USER_GRP), which holds the uId/gId pairs linking users and groups. JDX ORM uses JOIN_COLLECTION_CLASS declarations in the mapping file to define how these collections are traversed in each direction.
Key behaviors specific to many-to-many relationships in JDX ORM:
- Deep insert on a
GrouporUserpopulates the join table for the associated objects but does not recursively insert the related objects themselves — avoiding unintended duplication. Related objects must be inserted separately first (or after, if no referential integrity constraints exist at the database level). - Deep delete on a
GrouporUserremoves the join table entries (effectively disconnecting relationships) but does not delete the related objects on the other side. - Deep query fetches the related objects through the join table but avoids infinite recursion by not re-fetching the originating top-level objects.
- Associations between existing objects can also be created directly by inserting a
UserGroupjoin object without touching either theUserorGroupobjects themselves.
- Java JDK 8 or higher installed and on the system PATH.
- JDX ORM SDK installed. Set the environment variable
JX_HOMEto the SDK's top-level installation directory. - A supported JDBC-compatible database (SQLite is pre-configured; a MySQL example is also included in the
.jdxfile).
JDX_ManyToManyExample/
├── config/
│ └── manytomany_example.jdx # ORM mapping specification file
├── src/
│ └── com/softwaretree/jdxmanytomanyexample/
│ ├── ManyToManyExample.java # Main application entry point
│ └── model/
│ ├── UserGroup.java # Join class (User ↔ Group)
│ ├── User.java # User model class
│ └── Group.java # Group model class
├── bin/ # Compiled .class files (generated)
├── sources.txt # List of Java source files for compilation
├── compile.cmd # Windows: compile the Java source files
├── compile.sh # Mac/Linux: compile the Java source files
├── setEnvironment.bat # Windows: sets classpath environment variable
├── setEnvironment.sh # Mac/Linux: sets classpath environment variable
├── runJDXExample.bat # Windows: run the sample application
├── runJDXExample.sh # Mac/Linux: run the sample application
├── forward.bat # Windows: create/recreate the database schema
├── forward.sh # Mac/Linux: create/recreate the database schema
├── JDXDemo.bat # Windows: launch the JDXDemo GUI application
├── JDXDemo.sh # Mac/Linux: launch the JDXDemo GUI application
└── README.md # This file
| Class | Table | Primary Key | Fields |
|---|---|---|---|
UserGroup |
USER_GRP |
uId + gId |
uId, gId (composite primary key) |
User |
USER |
uId |
uId, uName, groups (Vector<Group>) |
Group |
GRP |
gId |
gId, gName, users (ArrayList<User>) |
The users and groups collection fields are traversed through the join table USER_GRP via JOIN_COLLECTION_CLASS definitions. Both use different Java collection types (ArrayList for Group.users, Vector for User.groups), illustrating that JDX ORM supports multiple collection types for many-to-many relationships.
This file defines the join class, the two join collection descriptors (one per direction), and the two main classes. Key elements:
JDX_DATABASEandJDBC_DRIVER— pre-configured for SQLite; a commented-out MySQL example is also included.JDX_OBJECT_MODEL_PACKAGE— the base Java package for all model classes.CLASS .UserGroup— maps the join class toUSER_GRPwith a composite primary key (uId gId).JOIN_COLLECTION_CLASS ListUsers— defines the collection ofUserobjects associated with aGroup, traversed throughUserGroup, keyed bygId, with join keyuId, ordered byuName.CLASS .Group— mapsGroupto tableGRP; declares theusersrelationship referencingListUsersBYVALUE withgId.JOIN_COLLECTION_CLASS VectorGroups— defines the collection ofGroupobjects associated with aUser, traversed throughUserGroup, keyed byuId, with join keygId. UsesVECTORcollection type.CLASS .User— mapsUserto tableUSER; declares thegroupsrelationship referencingVectorGroupsBYVALUE withuId.
Note that UserGroup is declared first in the mapping file, as it must be defined before the JOIN_COLLECTION_CLASS declarations that reference it.
Refer to the JDX Database & JDBC Driver Specification Guide for configuring other databases.
Note: Update
JDX_DATABASEandJDBC_DRIVERto match your local database setup before running.
A minimal POJO with just two fields — uId and gId — and a no-arg constructor. It represents a single row in the USER_GRP join table and can be instantiated directly to create or remove a specific user-group association without modifying either the User or Group object.
Has uId, uName, and a Vector<Group> collection (groups). The groups field is populated by JDX ORM on deep queries through the VectorGroups join collection.
Has gId, gName, and an ArrayList<User> collection (users). The users field is populated by JDX ORM on deep queries through the ListUsers join collection.
The entry point of the sample application. It demonstrates the following sequence, all wrapped in appropriate transactions:
- Deep delete all existing
Userobjects (cascades to join table entries), then shallow delete all existingGroupobjects (join entries already gone). - Create Group g1 with two users (
u1,u2). Insertu1andu2first (shallow), then insertg1(deep) to populate the join table. - Shallow and deep queries for all
GroupandUserobjects, showing the difference in what is fetched. - Create User u3 belonging to a new
Group g2. Insertg2first (shallow), then insertu3(deep) to populate the join table. - Associate u3 with g1 by directly inserting a
UserGroup(u3.uId, g1.gId)join object — demonstrating the lightweight approach to adding relationships between existing objects. - At this point:
g1hasu1,u2,u3;g2hasu3;u3belongs to both groups. - JDXVIEW query (
JDXVIEW_ListUsers_<className>) to list all users forgId=1. - Update
u3's name (shallow update) and verify the change appears in a deep query ofg2. - Deep delete
g1— removes join table entries forg1but leavesu1,u2,u3intact. - At this point:
g1is gone;u1andu2belong to no group;u3still belongs tog2. - Final deep queries for all
UserandGroupobjects to confirm the end state.
Lists all .java source files to be compiled, one per line:
./src/com/softwaretree/jdxmanytomanyexample/model/UserGroup.java
./src/com/softwaretree/jdxmanytomanyexample/model/User.java
./src/com/softwaretree/jdxmanytomanyexample/model/Group.java
./src/com/softwaretree/jdxmanytomanyexample/ManyToManyExample.java
UserGroup is listed first as it has no dependencies on the other model classes.
Compiles all Java source files listed in sources.txt and outputs .class files into the bin/ directory.
- Requires
JX_HOMEto be set to the JDX ORM SDK installation directory. - Links against
jxclasses.jar(JDX ORM library) andjson-20240303.jar(JSON support). compile.cmd— Windows batch script (supports JDK 8; a commented line supports JDK 9+).compile.sh— Mac/Linux shell script equivalent.
Windows:
compile.cmdMac/Linux:
chmod +x compile.sh # first time only
./compile.shSets the CLASSPATH environment variable to include the JDX ORM libraries and the appropriate JDBC driver JAR. Edit this file to point to the correct JDBC driver for your database before running the application.
setEnvironment.bat— Windows (uses;as classpath separator).setEnvironment.sh— Mac/Linux (uses:as classpath separator; sourced viasource ./setEnvironment.sh).
Invokes the environment setup script to configure the classpath, then runs the ManyToManyExample main class.
Windows:
runJDXExample.batMac/Linux:
chmod +x runJDXExample.sh # first time only
./runJDXExample.shCreates (or recreates) the database schema based on the ORM specification in the .jdx file, without running the application.
Windows:
forward -createMac/Linux:
chmod +x forward.sh # first time only
./forward.sh -createLaunches the JDXDemo desktop GUI application, which provides a graphical way to browse and interact with the database using the JDX ORM configuration.
Windows:
JDXDemo.batMac/Linux:
chmod +x JDXDemo.sh # first time only
./JDXDemo.sh-
Set
JX_HOMEto the root of your JDX ORM SDK installation. -
Configure the database by editing
config/manytomany_example.jdx:- Update
JDX_DATABASEwith the correct connection URL and credentials. - Update
JDBC_DRIVERwith the appropriate JDBC driver class. - Update
setEnvironment.bat(Windows) orsetEnvironment.sh(Mac/Linux) to include the JDBC driver JAR on the classpath.
- Update
-
Compile the source files:
compile.cmd # Windows ./compile.sh # Mac/Linux
-
Run the sample application:
runJDXExample.bat # Windows ./runJDXExample.sh # Mac/Linux
The application will automatically create the database schema on first run (controlled by the
forceCreateSchemaflag inManyToManyExample.java).
Mac/Linux tip: Run
chmod +x *.shonce in the project directory to make all shell scripts executable.
This project can be imported directly into the Eclipse IDE as an existing Java project using File → Import → Existing Projects into Workspace.
- JDX Database & JDBC Driver Specification Guide
- JDX ORM SDK documentation (included in your SDK installation under
JX_HOME)