Universal is a powerful and fully featured Relational Distributed Object Runtime designed to work seamlessly with both SQL and NoSQL databases, and even File/Network repository adapters. It provides a unified API to handle database interactions efficiently, making it easier to manage data persistence across different database types.
-
Cross-Database Compatibility: Supports both relational (SQL) and document-based (NoSQL) databases.
-
Cross-Platform Repository Linking: Link entities across different database adapters (e.g., MySQL ↔ MongoDB ↔ File ↔ Network).
-
Type Resolution System: Handles type conversions seamlessly between Java objects and database representations.
-
Caching and Lazy loading: Allows for automatic lazy loading and automatic caching.
-
Annotation-Based Configuration: Define repositories, constraints, and conditions using a SQL-like syntax for both MongoDB and SQL.
-
Efficient Query Handling: Uses built-in MongoDB methods and SQL functions without unnecessary query parsing.
-
Fully thread-safe: Use Universal however you want, whenever you want, from any thread, and Universal will ensure it is fully safe.
-
High performance: We take high performance measures to ensure:
- N + 1 Queries: aggressive relationship cache to attempt solving N+1 query problem for relationships and reduce it to the minimum
- Query parsing: We cache query building to ensure you never build something more than one time
- Connection pooling support: Allowing connection pools is a primary goal for Universal to thrive on high concurrency.
- Codegen and validation:
- in v7, we have replaced almost ALL reflection with code generated classes, which leads to significantly faster startup, better performance, less memory usage and compile-time validation!
- Before v7: There is only compile-time validation and reflection, though we takes extreme measures to ensure that reflection is not a big overhead by caching metadata and being ASM-based.
- Batched relationships: Universal tries to batch all relationship data, to use as little queries and achieve the highest throughput.
- Caching support: Lots of caching, from Session caches, to Result caches, to Global caches, all being evicted and controlled.
-
GraalVM Supported: Due to the lack of reflection usages like
Class.forName
import java.math.*;
import java.net.*;
import java.sql.*;
import java.time.*;
import java.util.*;
@Repository(name = "example")
public class Example {
@Id
private int id;
private String text;
private Integer integerObject;
private int integerPrimitive;
private Long longObject;
private long longPrimitive;
private Double doubleObject;
private double doublePrimitive;
private Float floatObject;
private float floatPrimitive;
private Boolean booleanObject;
private boolean booleanPrimitive;
private Short shortObject;
private short shortPrimitive;
private Byte byteObject;
private byte bytePrimitive;
private BigDecimal bigDecimal;
private BigInteger bigInteger;
private byte[] binary;
private Timestamp timestamp;
private Date date;
private Time time;
private LocalDate localDate;
private LocalTime localTime;
private LocalDateTime localDateTime;
private OffsetDateTime offsetDateTime;
private ZonedDateTime zonedDateTime;
private Duration duration;
private Period period;
private URI uri;
private URL url;
private InetAddress inetAddress;
private NetworkInterface networkInterface;
private Class<?> type;
private Locale locale;
private Currency currency;
private UUID uuid;
private EnumType enumValue;
@EnumAsOrdinal // Store the enum's ordinal in the database instead of the name
private EnumType enumValueAsOrdinal;
private List<String> list;
private Set<Integer> set;
private Queue<Integer> set;
private Deque<Integer> set;
private Map<String, String> map;
private Map<String, List<String>> mapList;
private Map<String, Set<Integer>> mapSet;
private Map<String, Queue<String>> mapList;
private Map<String, Deque<String>> mapList;
public enum EnumType { A, B, C }
}To include Universal in your project, add it as a dependency in your pom.xml (Maven) or build.gradle(.kts) (Gradle):
<dependency>
<groupId>io.github.flameyossnowy</groupId>
<artifact>universal-core</artifactId>
<version>7.1.5</version>
</dependency> <!-- + sql-common if you'd like to use SQL -->
<dependency>
<groupId>io.github.flameyossnowy</groupId>
<artifactId>universal-PLATFORM</artifactId>
<version>7.1.5</version>
</dependency>repositories {
mavenCentral()
}
dependencies {
implementation("io.github.flameyossnowy:universal-core:7.1.5")
implementation("io.github.flameyossnowy:universal-PLATFORM:7.1.5") // + sql-common if you'd like to use SQL
annotationProcessor("io.github.flameyossnowy:universal-compile-time-checker:7.1.5")
}Use annotations to define database entities:
@Repository(name = "users_repo")
public class User {
@Id
private UUID id;
private String username;
private int age;
// Getters and Setters
}Using the repository pattern:
SQLiteRepositoryAdapter<User> adapter = SQLiteRepositoryAdapter.builder(User.class)
.withCredentials(SQLiteCredentials.builder().directory("/home/.../test.db").build())
.setAutoCreate(false)
.build();
adapter.createRepository(); // if it doesn't exist.
List<User> minors = adapter.find(Query.select()
.where("age")
.lt(18)
.orderBy("age", SortOrder.ASCENDING)
.build());
for (User user : minors) {
System.out.println(user);
}For MongoDB:
MongoRepositoryAdapter<User> adapter = MongoRepositoryAdapter.builder(User.class)
.withCredentials(MongoClientSettings.builder()
.applyConnectionString(new ConnectionString("..."))
.readConcern(ReadConcern.MAJORITY)
.writeConcern(WriteConcern.W1)
.build())
.setAutoCreate(false)
.setDatabase("users")
.build();
adapter.createRepository(); // if it doesn't exist.
List<User> minors = adapter.find(Query.select()
.where("age")
.lt(18)
.orderBy("age", SortOrder.ASCENDING)
.build());
for (User user : minors) {
System.out.println(user);
}Universal now supports cross-platform repository linking, allowing entities backed by different storage systems to reference each other seamlessly.
// User entity in MySQL
@Repository(name = "users")
public class User {
@Id
private UUID id;
private String username;
// Reference to PathEntry stored in MongoDB
@ExternalRepository(adapter = "cache-adapter")
@OneToOne
private PathEntry cachePath;
// add getters and setters
}
// PathEntry entity in MongoDB
@Repository(name = "path_entries")
public class PathEntry {
@Id
private long id;
private Path entry;
private List<Path> directories;
private FileAttributes attributes;
@OneToOne
private User user;
// add getters and setters
}
// Register adapters
MySQLRepositoryAdapter<User, UUID> userAdapter = MySQLRepositoryAdapter
.builder(User.class, UUID.class)
.withCredentials(mySQLCredentials)
.build();
MongoRepositoryAdapter<PathEntry, Path> cacheAdapter = MongoRepositoryAdapter
.builder(PathEntry.class, Path.class)
.withCredentials(mongoCredentials)
.build();
// Use cross-platform relationships
User user = userAdapter.findById(userId);
PathEntry cache = user.getCachePath(); // Automatically fetched from MongoDB!- SQL Databases: MySQL, PostgreSQL, SQLite
- NoSQL Databases: MongoDB
- Microservices: File (JSON) and Networks
- Fork the repository.
- Create a new branch.
- Make your changes and commit them.
- Push your branch and create a pull request.
Universal is licensed under the MIT License. See LICENSE for details.