# API Reference Comprehensive reference for Morphium's core APIs, methods, and interfaces. ## Core Morphium API ### Morphium Class The main entry point for all Morphium operations. #### Constructor ```java // Primary constructor public Morphium(MorphiumConfig config) // Convenience constructors (since V2.2.23) public Morphium(String host, String database) public Morphium(String host, int port, String database) ``` #### Basic Operations **Store Operations:** ```java // Store single entity public void store(T entity) public void store(T entity, AsyncOperationCallback callback) // Store multiple entities public void storeList(List entities) public void storeList(List entities, AsyncOperationCallback callback) // Update using fields (partial updates) public void updateUsingFields(T entity, String... fields) ``` **Delete Operations:** ```java // Delete single entity public void delete(T entity) public void delete(T entity, AsyncOperationCallback callback) // Delete by query public void delete(Query query) public void delete(Query query, AsyncOperationCallback callback) ``` **Query Operations:** ```java // Create query for type public Query createQueryFor(Class type) // Get single entity by ID public T findById(Class type, Object id) ``` #### Configuration and Lifecycle ```java // Get configuration public MorphiumConfig getConfig() // Get driver public MorphiumDriver getDriver() // Close connection and cleanup public void close() // Check if closed public boolean isClosed() ``` #### Index Management ```java // Ensure all indexes for a type public void ensureIndicesFor(Class type) // Create index manually public void ensureIndex(Class type, Map index) public void ensureIndex(Class type, String... fields) ``` #### Transaction Support ```java // Transaction management public void beginTransaction() public void commitTransaction() public void abortTransaction() // Check transaction state public boolean isTransactionInProgress() public MorphiumTransactionContext getTransactionContext() ``` #### Per-Thread Behavior Overrides Morphium allows overriding certain global settings on a per-thread basis. This is useful for temporarily disabling caching or auto-values within a specific request or task. ```java // Disable/enable auto-values for the current thread public void disableAutoValuesForThread() public void enableAutoValuesForThread() public boolean isAutoValuesEnabledForThread() // Disable/enable read cache for the current thread public void disableReadCacheForThread() public void enableReadCacheForThread() public boolean isReadCacheEnabledForThread() // Disable/enable write buffer for the current thread public void disableWriteBufferForThread() public void enableWriteBufferForThread() public boolean isWriteBufferEnabledForThread() // Disable/enable async writes for the current thread public void disableAsyncWritesForThread() public void enableAsyncWritesForThread() public boolean isAsyncWritesEnabledForThread() // Reset ALL per-thread overrides back to defaults (= follow global config) public void resetThreadLocalOverrides() ``` **Important:** These overrides are backed by `ThreadLocal` and are **not** automatically cleaned up. In thread-pool or virtual-thread environments, always call `resetThreadLocalOverrides()` at the end of a request or task to prevent state from leaking between threads. > **Future improvement:** Once `java.lang.ScopedValue` ([JEP 487](https://openjdk.org/jeps/487)) is finalized (currently in preview as of JDK 24), these thread-local overrides should be replaced with scoped values. Scoped values provide automatic cleanup at scope exit and are inherently safe with virtual threads — eliminating the need for manual `resetThreadLocalOverrides()` calls. ## Query API ### Query Interface **Field Selection:** ```java // Select field for operations public Query f(String field) public Query f(Enum field) // Using field enums // Field operations public Query eq(Object value) // Equal public Query ne(Object value) // Not equal public Query lt(Object value) // Less than public Query lte(Object value) // Less than or equal public Query gt(Object value) // Greater than public Query gte(Object value) // Greater than or equal public Query in(Collection values) // In array public Query nin(Collection values) // Not in array public Query matches(String regex) // Regex match public Query exists() // Field exists public Query notExists() // Field doesn't exist ``` **Query Modifiers:** ```java // Sorting public Query sort(String field) // Ascending public Query sort(Map sort) // Custom sort // Pagination public Query skip(int skip) public Query limit(int limit) // Projection public Query project(String... fields) public Query addProjection(String field, String projection) ``` **Query Execution:** ```java // Get results public List asList() // All results as list public T get() // Single result (first match) public long countAll() // Count all matches // Async execution public void asList(AsyncOperationCallback callback) public void get(AsyncOperationCallback callback) // Iterator for large result sets public MorphiumIterator asIterable() public MorphiumIterator asIterable(int windowSize) public MorphiumIterator asIterable(int windowSize, int prefetch) // Stream API for functional processing (cursor-backed, lazy) public Stream stream() public Stream stream(int batchSize) ``` **Stream API (since 6.2.1):** `stream()` returns a `Stream` backed by the MongoDB cursor — elements are fetched lazily, not loaded into memory all at once. Always use in try-with-resources to ensure cursor cleanup: ```java try (Stream s = morphium.createQueryFor(User.class) .f("age").gte(18) .sort("lastName") .stream()) { List names = s.map(User::getLastName).toList(); } // With explicit batch size (documents per cursor round-trip) try (Stream s = query.stream(500)) { long count = s.filter(u -> u.isActive()).count(); } ``` **Logical Operators:** ```java // OR conditions public Query or(Query... queries) // NOR conditions public Query nor(Query... queries) // Create sub-query public Query q() // New query instance ``` **Advanced Features:** ```java // Text search public Query text(Query.TextSearchLanguages language, String... terms) public Query text(Query.TextSearchLanguages language, boolean caseSensitive, boolean diacriticSensitive, String... terms) // Distinct values public List distinct(String field) // Complex query with raw MongoDB query public List complexQuery(Map query) ``` **Update Operations with arrayFilters (since 6.3.0):** Filtered positional updates (`$[]` paths) are available on all update operations of a query — `set`, `inc`, `unset`, `push`, `pull`, ...: ```java // Set every list element >= 90 to 100 morphium.createQueryFor(Measurement.class) .f(Measurement.Fields.sensor).eq("s1") .setArrayFilters(Doc.of("elem", Doc.of("$gte", 90))) .set("values.$[elem]", 100, false, true); ``` `setArrayFilters` accepts a `List>` or varargs of filter documents; each document defines one `$[]` placeholder. Paths containing `$` bypass property-name translation, so write the MongoDB field names in the path. ## Aggregation API ### Aggregator Interface ```java // Create aggregator public Aggregator createAggregator(Class inputType, Class resultType) ``` **Pipeline Operations:** ```java // Match stage (filter) public Aggregator match(Query query) // Project stage (field selection/transformation) public Aggregator project(String... fields) public Aggregator project(Map projection) // Group stage public Aggregator group(String groupBy) public Aggregator group(Map groupBy) // Group operations public Aggregator sum(String field, String source) public Aggregator avg(String field, String source) public Aggregator min(String field, String source) public Aggregator max(String field, String source) public Aggregator first(String field, String source) public Aggregator last(String field, String source) public Aggregator count(String field) // End group stage public Aggregator end() // Sort stage public Aggregator sort(String... fields) public Aggregator sort(Map sort) // Skip/Limit stages public Aggregator skip(int skip) public Aggregator limit(int limit) // Gap filling / window functions (since 6.3.0) public Aggregator documents(List> documents) // $documents public Aggregator densify(String field, Number step) // $densify, "full" bounds public Aggregator densify(String field, Number step, Object bounds) public Aggregator densify(String field, Number step, Object bounds, String unit, List partitionByFields) public Aggregator fill(Map output) // $fill public Aggregator fill(Map sortBy, Map output) public Aggregator setWindowFields(Object partitionBy, // $setWindowFields Map sortBy, Map output) // Escape hatch for any other stage public Aggregator genericStage(String stageName, Object param) ``` **Execution:** ```java // Execute aggregation public List aggregate() // Get raw aggregation list public List> toAggregationList() ``` ## Messaging API ### Messaging Interface **Setup and Lifecycle:** ```java // Initialize messaging public void init(Morphium morphium) public void init(Morphium morphium, MessagingSettings settings) // Start/stop messaging public void start() public void terminate() // Check state public boolean isAlive() ``` **Message Operations:** ```java // Send message public void sendMessage(Msg message) // Send and wait for responses public Msg sendAndAwaitFirstAnswer(Msg message, long timeout) public List sendAndAwaitAnswers(Msg message, int expectedAnswers, long timeout) // Send message to specific listener public void sendDirectMessage(Msg message, String host, String listenerId) ``` **Listener Management:** ```java // Add topic listener public void addListenerForTopic(String topic, MessageListener listener) public void addListenerForTopic(String topic, MessageListener listener, boolean multithreaded) // Remove listener public boolean removeListenerForTopic(String topic, MessageListener listener) // Get registered listeners public List getListenersForTopic(String topic) ``` **Message Listener Interface:** ```java @FunctionalInterface public interface MessageListener { /** * Process incoming message * @param messaging The messaging instance * @param message The received message * @return Response message (null if no response) */ Msg onMessage(Morphium messaging, Msg message); } ``` ### Msg Class **Constructor:** ```java public Msg(String topic, String message, String value) public Msg(String topic, String message, String value, long ttl) ``` **Properties:** ```java // Basic properties public String getTopic() public void setTopic(String topic) public String getMsg() public void setMsg(String message) public String getValue() public void setValue(String value) // Timing properties public long getTtl() public void setTtl(long ttl) public long getTimestamp() public void setTimestamp(long timestamp) // Message routing public boolean isExclusive() public void setExclusive(boolean exclusive) public String getInAnswerTo() public void setInAnswerTo(String inAnswerTo) public String getSender() public void setSender(String sender) public String getRecipient() public void setRecipient(String recipient) ``` **Map Values (for complex data):** ```java // Store/retrieve complex objects as map public Map getMapValue() public void setMapValue(Map mapValue) // Convenience methods public void addAdditional(String key, Object value) public Object getAdditional(String key) ``` ## Configuration API ### MorphiumConfig **Main Settings Access:** ```java // Get nested settings objects public ConnectionSettings connectionSettings() public ClusterSettings clusterSettings() public DriverSettings driverSettings() public MessagingSettings messagingSettings() public CacheSettings cacheSettings() public ThreadPoolSettings threadPoolSettings() public WriterSettings writerSettings() public ObjectMappingSettings objectMappingSettings() public EncryptionSettings encryptionSettings() public CollectionCheckSettings collectionCheckSettings() public AuthSettings authSettings() ``` **Logging Configuration:** Logging in Morphium is handled by Log4j2. Configure logging in your `log4j2.xml` file: ```xml ``` **Factory Methods:** ```java // Create from different sources public static MorphiumConfig createFromJson(String json) public static MorphiumConfig fromProperties(Properties props) ``` ## Annotation Reference ### Entity Annotations **@Entity** ```java @Entity( value = "collection_name", // Custom collection name translateCamelCase = true, // Convert camelCase to snake_case polymorph = false, // Store class name for inheritance useFQN = false, // Use fully qualified class name nameProvider = NameProvider.class // Custom naming strategy ) ``` **@Embedded** ```java @Embedded( polymorph = false, // Store class name for polymorphism translateCamelCase = true // Convert field names ) ``` **@Id** ```java @Id // Mark field as MongoDB _id field ``` **@Property** ```java @Property( fieldName = "custom_field_name" // Custom field name in MongoDB ) ``` **@Version** ```java @Version( fieldName = "." // "." = derive MongoDB field name from Java field (camelCase convention) // or set an explicit name, e.g. fieldName = "version" ) ``` Enables **optimistic locking**. Morphium automatically: - Sets the field to `1L` on the first `store()` (INSERT path) - Increments it by 1 on every subsequent `store()` (UPDATE path) - Throws `de.caluga.morphium.VersionMismatchException` when another writer has already updated the document (stale-entity detection) The exception carries `getExpectedVersion()` (the version the caller held) for diagnostic and retry logic. See `docs/howtos/optimistic-locking.md` for a complete guide. **@Reference** ```java @Reference( lazyLoading = false, // Enable lazy loading via CGLib proxy fieldName = "ref_field", // Custom field name in MongoDB automaticStore = true, // Auto-persist unreferenced objects on store targetCollection = ".", // Override target collection (default: derived from type) cascadeDelete = false, // Delete referenced entities when parent is deleted orphanRemoval = false // Delete dereferenced entities on parent update ) ``` See `docs/howtos/references-and-relationships.md` for a comprehensive guide. **@CascadeAware** ```java @CascadeAware // Required on entity classes using cascadeDelete or orphanRemoval ``` Marker annotation (analogous to `@Lifecycle`). Without `@CascadeAware`, cascade delete and orphan removal checks are skipped entirely for performance. Add this annotation to any `@Entity` class that has `@Reference(cascadeDelete = true)` or `@Reference(orphanRemoval = true)` fields. ### Index Annotations **@Index (Field Level)** ```java @Index( direction = IndexDirection.ASC, // ASC or DESC options = {"unique:true"} // MongoDB index options ) ``` **@Index (Class Level)** ```java @Index({ "field1", // Simple ascending index "-field2", // Descending index (note the minus) "field3,field4", // Compound index "location:2d" // Geospatial index }) ``` ### Caching Annotations **@Cache** ```java @Cache( timeout = 60000, // Cache timeout in ms maxEntries = 10000, // Maximum cache entries strategy = Cache.ClearStrategy.LRU, // Eviction strategy syncCache = Cache.SyncCacheStrategy.CLEAR_TYPE_CACHE, // Cluster sync clearOnWrite = true // Clear cache on writes ) ``` **@NoCache** ```java @NoCache // Disable caching for this entity ``` ### Write Buffer Annotations **@WriteBuffer** ```java @WriteBuffer( size = 1000, // Buffer size timeout = 5000, // Flush timeout (ms) strategy = WriteBuffer.STRATEGY.WRITE_OLD // Strategy when full ) ``` **@AsyncWrites** ```java @AsyncWrites // All writes are asynchronous ``` ### Lifecycle Annotations **@CreationTime** ```java @CreationTime private long createdAt; // Set on first save ``` **@LastChange** ```java @LastChange private long lastModified; // Updated on each save ``` **@LastAccess** ```java @LastAccess private long lastAccessed; // Updated on each read ``` **Lifecycle Callbacks:** ```java @PreStore public void beforeStore() { // Called before storing to database } @PostStore public void afterStore() { // Called after successful store } @PreLoad public void beforeLoad() { // Called before loading from database } @PostLoad public void afterLoad() { // Called after loading from database } ``` ### Validation Annotations Morphium supports standard javax.validation annotations: ```java @Entity public class User { @NotNull @Size(min = 3, max = 50) private String username; @Email private String email; @Min(18) private int age; @Pattern(regexp = "^[A-Za-z]+$") private String firstName; } ``` ## Exception Handling ### Common Exceptions **MorphiumDriverException:** ```java // Thrown for driver-level issues try { morphium.store(entity); } catch (MorphiumDriverException e) { // Handle connection/driver errors logger.error("Driver error: " + e.getMessage(), e); } ``` **MorphiumAccessVetoException:** ```java // Thrown when access is denied by security rules try { List users = query.asList(); } catch (MorphiumAccessVetoException e) { // Handle security violations logger.warn("Access denied: " + e.getMessage()); } ``` ## Utility Classes ### MorphiumIterator **Large Dataset Processing:** ```java // Create iterator MorphiumIterator iterator = query.asIterable(1000, 5); // Navigation public boolean hasNext() public T next() public void remove() // Position information public long getCount() // Total number of results public int getCursor() // Current position public void ahead(int steps) // Jump ahead public void back(int steps) // Jump back // Buffer information public List getCurrentBuffer() // Current buffer contents public int getCurrentBufferSize() // Current buffer size // Threading public void setMultithreaddedAccess(boolean enable) ``` ### ObjectMapper **Manual Object Mapping:** ```java ObjectMapper mapper = morphium.getMapper(); // Object to BSON Map bson = mapper.marshall(entity); // BSON to Object Entity entity = mapper.unmarshall(Entity.class, bson); // JSON support String json = mapper.marshall(entity).toString(); Entity entity = mapper.unmarshall(Entity.class, json); ``` This API reference provides comprehensive documentation of all major Morphium APIs, including method signatures, parameters, and usage examples.