A Spring Boot auto-configuration for Morphium, an actively maintained MongoDB ORM for Java -- with full Jakarta Data 1.0 repository support.
Companion project: See quarkus-morphium for Quarkus integration with the same Jakarta Data feature set.
- Auto-configuration --
Morphiumbean created fromspring.morphium.*properties - Jakarta Data repositories --
@Repositoryinterfaces with JDK dynamic proxies (runtime) - Query derivation --
findBy*,countBy*,existsBy*,deleteBy*with And/Or, Between, In, Like, etc. - JDQL --
@Query("WHERE status = :s ORDER BY name")Jakarta Data Query Language - @Find / @Delete -- explicit field binding via
@Byparameters - Transactions --
@MorphiumTransactionalwith AOP-based commit/rollback - Actuator health -- Morphium connection status in
/actuator/health - Test support --
@MorphiumTestcomposite annotation with InMemDriver (no MongoDB needed) - MorphiumRepository -- escape hatch for
distinct(),query(),morphium()access
| Dependency | Minimum version |
|---|---|
| Java | 21 |
| Spring Boot | 3.4.x |
| Morphium | 6.2.2 (sboesebeck/morphium) |
Add the starter to your pom.xml:
<dependency>
<groupId>de.caluga</groupId>
<artifactId>spring-boot-morphium-starter</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>Note: Until published to Maven Central, build locally:
git clone https://github.com/Bardioc1977/spring-boot-morphium.git cd spring-boot-morphium mvn install -DskipTests
# application.properties
spring.morphium.database=my-database
spring.morphium.hosts=localhost:27017@Entity(collectionName = "products")
public class Product {
@Id private MorphiumId id;
private String name;
private double price;
private String category;
// getters, setters, constructors
}@Repository
public interface ProductRepository extends MorphiumRepository<Product, MorphiumId> {
List<Product> findByCategory(String category);
List<Product> findByPriceGreaterThan(double minPrice);
long countByCategory(String category);
@Query("WHERE category = :cat AND price > :minPrice ORDER BY price")
List<Product> findExpensive(@Param("cat") String category,
@Param("minPrice") double minPrice);
}@SpringBootApplication
@EnableMorphiumRepositories
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}@Service
public class ProductService {
@Autowired ProductRepository products;
public List<Product> findExpensive(double minPrice) {
return products.findByPriceGreaterThan(minPrice);
}
}| Feature | Details |
|---|---|
| CRUD | CrudRepository<T,K>, MorphiumRepository<T,K> -- save, insert, update, delete, findById, findAll |
| Query derivation | findBy, countBy, existsBy, deleteBy with operators: Equals, Not, GreaterThan, LessThan, Between, In, NotIn, Like, StartsWith, EndsWith, Null, NotNull, True, False -- combined with And/Or |
| @Find + @By | Explicit field binding via parameter annotations |
| @Query (JDQL) | Jakarta Data Query Language with WHERE, ORDER BY, named parameters, BETWEEN, IN, LIKE, IS NULL, NOT, GROUP BY, HAVING, aggregates |
| @OrderBy | Static sort annotation on query methods |
| Pagination | Page<T>, PageRequest, CursoredPage<T> (keyset pagination) |
| Sorting | Sort<T>, Order<T> as method parameters |
| Stream | Stream<T> return type for large result sets |
| Async | CompletionStage<T> return type for non-blocking operations |
MorphiumRepository<T,K> extends CrudRepository with Morphium-specific operations:
// Distinct values for a field
List<Object> categories = products.distinct("category");
// Direct access to the Morphium API
products.morphium().inc(product, "stock", 5);
// Create a typed Morphium Query
Query<Product> q = products.query();
q.f("price").gt(100).f("category").eq("electronics");| Property | Default | Description |
|---|---|---|
spring.morphium.database |
(required) | MongoDB database name |
spring.morphium.hosts |
localhost:27017 |
Comma-separated host:port list |
spring.morphium.username |
-- | MongoDB username |
spring.morphium.password |
-- | MongoDB password |
spring.morphium.auth-database |
admin |
Authentication database |
spring.morphium.atlas-url |
-- | MongoDB Atlas SRV URL (overrides hosts) |
spring.morphium.replica-set-name |
-- | Replica set name (required for transactions) |
spring.morphium.read-preference |
primary |
Read preference |
spring.morphium.max-connections |
250 |
Connection pool size |
spring.morphium.driver-name |
PooledDriver |
PooledDriver (production) or InMemDriver (tests) |
spring.morphium.connect-retries |
5 |
Connection retry attempts on transient failures |
spring.morphium.index-check |
CREATE_ON_STARTUP |
CREATE_ON_STARTUP, WARN_ON_STARTUP, CREATE_ON_WRITE_NEW_COL, NO_CHECK |
spring.morphium.cache.global-valid-time |
5000 |
Cache TTL in milliseconds |
spring.morphium.cache.read-cache-enabled |
true |
Enable query result cache |
spring.morphium.ssl.enabled |
false |
Enable TLS |
spring.morphium.ssl.keystore-path |
-- | Keystore path (JKS/PKCS12) |
spring.morphium.ssl.keystore-password |
-- | Keystore password |
Requires a MongoDB replica set or Atlas.
@Service
public class OrderService {
@Autowired Morphium morphium;
@MorphiumTransactional
public void placeOrder(Order order, Payment payment) {
morphium.store(order);
morphium.store(payment);
// auto-commit on success, auto-rollback on exception
}
}When spring-boot-actuator is on the classpath, a Morphium health indicator is
automatically registered at /actuator/health:
{
"status": "UP",
"components": {
"morphium": {
"status": "UP",
"details": {
"database": "my-database",
"driver": "PooledDriver",
"replicaSet": true,
"replicaSetName": "rs0"
}
}
}
}# src/test/resources/application-test.properties
spring.morphium.database=test
spring.morphium.driver-name=InMemDriver@SpringBootTest
@ActiveProfiles("test")
@EnableMorphiumRepositories
class ProductRepositoryTest {
@Autowired ProductRepository repository;
@Test
void shouldFindByCategory() {
repository.save(new Product("Widget", 9.99, "tools"));
var results = repository.findByCategory("tools");
assertThat(results).hasSize(1);
assertThat(results.get(0).getName()).isEqualTo("Widget");
}
}The spring-boot-morphium-test module provides a composite annotation:
<dependency>
<groupId>de.caluga</groupId>
<artifactId>spring-boot-morphium-test</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>@MorphiumTest
@EnableMorphiumRepositories
class ProductRepositoryTest {
@Autowired ProductRepository repository;
@Test
void shouldFindByCategory() {
// InMemDriver is auto-configured
}
}spring-boot-morphium/
spring-boot-morphium-autoconfigure/ Auto-configuration, repository proxy, AOP, health
spring-boot-morphium-starter/ Dependency-only POM (pull this in your app)
spring-boot-morphium-test/ @MorphiumTest annotation for test support
This starter uses JDK dynamic proxies at runtime (the standard Spring Data pattern), in contrast to the quarkus-morphium extension which uses Gizmo bytecode generation at build time.
Both share the same query engine via the morphium-jakarta-data module -- a framework-agnostic library containing all Jakarta Data query derivation, JDQL parsing, pagination, and CRUD logic.
morphium (core ODM)
└── morphium-jakarta-data (shared Jakarta Data runtime)
├── spring-boot-morphium (this project, JDK proxies)
└── quarkus-morphium (Gizmo bytecode, build-time)
# Requires morphium 6.2.2-SNAPSHOT and morphium-jakarta-data 1.0.0-SNAPSHOT
# in your local Maven repository
mvn clean install
# Run tests only
mvn test -pl spring-boot-morphium-autoconfigure- Morphium -- the underlying MongoDB ORM
- morphium-jakarta-data -- shared Jakarta Data runtime
- quarkus-morphium -- Quarkus CDI extension (same Jakarta Data features)
- quarkus-morphium-showcase -- interactive demo
- Jakarta Data 1.0 -- the specification
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
This project follows the Contributor Covenant Code of Conduct.